Add files via upload
This commit is contained in:
parent
07f2ed525b
commit
6e7f0c1505
37 changed files with 4084 additions and 20 deletions
68
extras/cpp/audio_meta.hpp
Normal file
68
extras/cpp/audio_meta.hpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// extras/cpp — decorative, separate from installer/installer.cpp (the real,
|
||||
// functional C++ source). a tiny header-only audio-tag toy, mirroring
|
||||
// app/backend/metadata.py in spirit.
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace nexdex {
|
||||
|
||||
struct AudioTag {
|
||||
std::string title;
|
||||
std::string artist;
|
||||
std::optional<std::string> album;
|
||||
std::optional<int> year;
|
||||
std::optional<int> trackNumber;
|
||||
|
||||
bool isComplete() const {
|
||||
return !title.empty() && !artist.empty();
|
||||
}
|
||||
|
||||
std::string describe() const {
|
||||
std::ostringstream out;
|
||||
out << artist << " -- " << title;
|
||||
if (album) out << " [" << *album << "]";
|
||||
if (year) out << " (" << *year << ")";
|
||||
if (trackNumber) out << " track #" << *trackNumber;
|
||||
return out.str();
|
||||
}
|
||||
};
|
||||
|
||||
class AudioTagBuilder {
|
||||
public:
|
||||
AudioTagBuilder(std::string title, std::string artist) {
|
||||
tag_.title = std::move(title);
|
||||
tag_.artist = std::move(artist);
|
||||
}
|
||||
|
||||
AudioTagBuilder& album(std::string album) {
|
||||
tag_.album = std::move(album);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AudioTagBuilder& year(int year) {
|
||||
tag_.year = year;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AudioTagBuilder& trackNumber(int n) {
|
||||
tag_.trackNumber = n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AudioTag build() const {
|
||||
return tag_;
|
||||
}
|
||||
|
||||
private:
|
||||
AudioTag tag_;
|
||||
};
|
||||
|
||||
inline std::vector<std::string> knownExtensions() {
|
||||
return {"mp3", "flac", "wav", "m4a", "alac", "ogg", "opus"};
|
||||
}
|
||||
|
||||
} // namespace nexdex
|
||||
34
extras/cpp/demo.cpp
Normal file
34
extras/cpp/demo.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// extras/cpp/demo.cpp — decorative, not part of the build. compile with:
|
||||
// cl.exe /std:c++17 /EHsc demo.cpp /Fe:demo.exe
|
||||
// or: g++ -std=c++17 demo.cpp -o demo
|
||||
|
||||
#include <iostream>
|
||||
#include "audio_meta.hpp"
|
||||
#include "progress_bar.hpp"
|
||||
#include "playlist.hpp"
|
||||
|
||||
int main() {
|
||||
using nexdex::AudioTagBuilder;
|
||||
using nexdex::ProgressBar;
|
||||
using nexdex::Playlist;
|
||||
using nexdex::Track;
|
||||
|
||||
auto tag = AudioTagBuilder("MATADORA (Extended)", "SUKA.")
|
||||
.year(2026)
|
||||
.build();
|
||||
|
||||
std::cout << tag.describe() << "\n\n";
|
||||
|
||||
ProgressBar bar("MATADORA (Extended)", 30);
|
||||
for (int pct = 0; pct <= 100; pct += 20) {
|
||||
std::cout << bar.render(pct) << "\n";
|
||||
}
|
||||
|
||||
Playlist playlist;
|
||||
playlist.add(Track{tag, "downloads/MATADORA (Extended).flac", 222});
|
||||
std::cout << "\nplaylist: " << playlist.size() << " track(s), total "
|
||||
<< Playlist::formatDuration(playlist.totalDurationSecs()) << "\n";
|
||||
|
||||
std::cout << "\nmade by savsis with <3\n";
|
||||
return 0;
|
||||
}
|
||||
79
extras/cpp/playlist.hpp
Normal file
79
extras/cpp/playlist.hpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// extras/cpp — decorative. mirrors extras/rust/src/playlist.rs, just in
|
||||
// C++: a tiny in-memory playlist model with no real I/O.
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <numeric>
|
||||
#include "audio_meta.hpp"
|
||||
|
||||
namespace nexdex {
|
||||
|
||||
struct Track {
|
||||
AudioTag tag;
|
||||
std::string path;
|
||||
int durationSecs = 0;
|
||||
};
|
||||
|
||||
class Playlist {
|
||||
public:
|
||||
void add(Track track) {
|
||||
tracks_.push_back(std::move(track));
|
||||
}
|
||||
|
||||
size_t size() const { return tracks_.size(); }
|
||||
bool empty() const { return tracks_.empty(); }
|
||||
|
||||
int totalDurationSecs() const {
|
||||
return std::accumulate(
|
||||
tracks_.begin(), tracks_.end(), 0,
|
||||
[](int sum, const Track& t) { return sum + t.durationSecs; });
|
||||
}
|
||||
|
||||
std::vector<const Track*> byArtist(const std::string& artist) const {
|
||||
std::vector<const Track*> result;
|
||||
for (const auto& t : tracks_) {
|
||||
if (equalsIgnoreCase(t.tag.artist, artist)) {
|
||||
result.push_back(&t);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<const Track*> longest() const {
|
||||
if (tracks_.empty()) return std::nullopt;
|
||||
auto it = std::max_element(
|
||||
tracks_.begin(), tracks_.end(),
|
||||
[](const Track& a, const Track& b) { return a.durationSecs < b.durationSecs; });
|
||||
return &(*it);
|
||||
}
|
||||
|
||||
static std::string formatDuration(int totalSecs) {
|
||||
int hours = totalSecs / 3600;
|
||||
int minutes = (totalSecs % 3600) / 60;
|
||||
int seconds = totalSecs % 60;
|
||||
|
||||
char buf[32];
|
||||
if (hours > 0) {
|
||||
snprintf(buf, sizeof(buf), "%d:%02d:%02d", hours, minutes, seconds);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "%d:%02d", minutes, seconds);
|
||||
}
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
private:
|
||||
static bool equalsIgnoreCase(const std::string& a, const std::string& b) {
|
||||
if (a.size() != b.size()) return false;
|
||||
return std::equal(a.begin(), a.end(), b.begin(), [](char x, char y) {
|
||||
return std::tolower(static_cast<unsigned char>(x)) ==
|
||||
std::tolower(static_cast<unsigned char>(y));
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<Track> tracks_;
|
||||
};
|
||||
|
||||
} // namespace nexdex
|
||||
31
extras/cpp/progress_bar.hpp
Normal file
31
extras/cpp/progress_bar.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// extras/cpp — decorative. a tiny console progress bar, echoing the shape
|
||||
// of the /api/job/<id> polling response from backend/jobs.py.
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace nexdex {
|
||||
|
||||
class ProgressBar {
|
||||
public:
|
||||
ProgressBar(std::string label, int width) : label_(std::move(label)), width_(width) {}
|
||||
|
||||
std::string render(int percent) const {
|
||||
percent = std::clamp(percent, 0, 100);
|
||||
int filled = width_ * percent / 100;
|
||||
int empty = width_ - filled;
|
||||
|
||||
std::string bar;
|
||||
bar.append(filled, '#');
|
||||
bar.append(empty, '-');
|
||||
|
||||
return label_ + " [" + bar + "] " + std::to_string(percent) + "%";
|
||||
}
|
||||
|
||||
private:
|
||||
std::string label_;
|
||||
int width_;
|
||||
};
|
||||
|
||||
} // namespace nexdex
|
||||
Loading…
Add table
Add a link
Reference in a new issue