build-dev / nix-build (push) Failing after 13s
Server is scheduled to generate this file nightly
113 lines
4.2 KiB
C++
113 lines
4.2 KiB
C++
#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,
|
|
const std::string &displayName);
|
|
|
|
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
|