initial commit
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace radiantwave::db {
|
||||
class DatabaseManager;
|
||||
}
|
||||
|
||||
namespace radiantwave::audio {
|
||||
|
||||
// One entry from the audio checksums manifest.
|
||||
//
|
||||
// Supported line formats (in priority order):
|
||||
// <filename> '<display name>' <hz> <md5> // current
|
||||
// <md5> <filename> // legacy fallback
|
||||
//
|
||||
// hz is the actual frequency value of the track (e.g. 396), written by hand
|
||||
// or by a script that has no access to the frequency-id table; 0 means
|
||||
// "none / unset". The manifest author may also write the frequency id (or any
|
||||
// unrecognized number): only values that resolve to a known frequency are
|
||||
// honored, anything else falls back to the Hz parsed from the filename, so
|
||||
// the file's own name is always the safety net.
|
||||
struct AudioManifestEntry {
|
||||
std::string filename;
|
||||
std::string display_name;
|
||||
int solfeggio_frequency_hz = 0;
|
||||
std::string md5;
|
||||
};
|
||||
|
||||
// Downloads audio assets from files.radiantwavetech.com in the background
|
||||
// and keeps the database's audio_files table in sync with what is actually
|
||||
// on disk.
|
||||
//
|
||||
// Fetches checksums.md5, compares each entry against the local file's MD5,
|
||||
// and re-downloads anything that is missing or whose checksum differs.
|
||||
// Files present on disk but absent from the manifest are deleted, and the
|
||||
// audio_files table is reconciled on every pass (and after each individual
|
||||
// download) so the settings audio list reflects live progress: a file that
|
||||
// just finished downloading appears in the list immediately, and files not
|
||||
// yet downloaded are not listed. The worker runs a persistent loop: if
|
||||
// there is no internet at startup the status shows "Waiting for internet..."
|
||||
// and a download starts automatically once connectivity returns. When all
|
||||
// files verify it keeps re-checking the manifest periodically so changed
|
||||
// checksums are picked up while running.
|
||||
class AudioDownloader {
|
||||
public:
|
||||
AudioDownloader() = default;
|
||||
~AudioDownloader();
|
||||
|
||||
AudioDownloader(const AudioDownloader&) = delete;
|
||||
AudioDownloader& operator=(const AudioDownloader&) = delete;
|
||||
|
||||
// Spawns the background thread. Safe to call repeatedly; only one worker
|
||||
// runs at a time. The manifest is reconciled against `db` on every pass.
|
||||
void start(db::DatabaseManager& db);
|
||||
|
||||
// Signals the worker to stop and joins the thread.
|
||||
void shutdown();
|
||||
|
||||
// Returns the current human-readable status for display (e.g. footer).
|
||||
std::string statusString() const;
|
||||
|
||||
static constexpr const char* AUDIO_BASE_URL = "https://files.radiantwavetech.com/audio/";
|
||||
static constexpr const char* MANIFEST_FILENAME = "checksums.md5";
|
||||
|
||||
private:
|
||||
void run();
|
||||
bool fetchManifest(std::vector<AudioManifestEntry>& out);
|
||||
bool downloadAndVerify(const std::string& filename, const std::string& expectedMd5);
|
||||
|
||||
void setStatus(const std::string& msg);
|
||||
void wait(std::chrono::seconds seconds);
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
std::condition_variable cv_;
|
||||
std::thread worker_;
|
||||
std::atomic<bool> stop_{false};
|
||||
std::string status_;
|
||||
db::DatabaseManager* db_ = nullptr;
|
||||
};
|
||||
|
||||
// Parses checksums.md5 manifest text into entries. Blank lines and lines
|
||||
// starting with '#' are ignored. Lines that don't match a known format are
|
||||
// skipped. Returns false if no valid entries were found.
|
||||
bool parseManifest(const std::string& text, std::vector<AudioManifestEntry>& out);
|
||||
|
||||
// Maps a frequency value in Hz to its internal solfeggio frequency id using
|
||||
// the same table the color palettes are seeded from (174/285->1, 396->2,
|
||||
// 417->3, 432->4, 528->5, 639->6, 741->7, 852->8, 963->9). Returns 0 for
|
||||
// frequencies with no id (binaurals, AlphaWaves, OriginalAudio, ...).
|
||||
int frequencyIdForHz(int hz);
|
||||
|
||||
// Parses the leading frequency value out of an audio filename like
|
||||
// "396Hz.wav" -> 396. Requires the digits to be followed by "Hz"
|
||||
// (case-insensitive); returns 0 when the name has no frequency (e.g.
|
||||
// "AlphaWaves.wav", "OriginalAudio.wav").
|
||||
int hzFromFilename(const std::string& filename);
|
||||
|
||||
// Computes the lowercase MD5 hex of a file, or an empty string on failure.
|
||||
std::string computeFileMd5(const std::string& path);
|
||||
|
||||
} // namespace radiantwave::audio
|
||||
Reference in New Issue
Block a user