# audio-library-manager `audio-library-manager` maintains a music library in two forms: 1. a source FLAC tree, optionally normalised so FLAC files do not exceed a configured sample rate; and 2. a mirrored Opus tree, where FLAC files are converted to `.opus` and non-FLAC sidecar files are copied unchanged. The current entry point is `audio-manager.rkt`, exported as the function `audio-manager` from `main.rkt`. The implementation is intentionally simple. It is a command-line batch process: scan files, compare with the saved state, run a small ordered set of processing steps, write the state, send a report. It does not use places, channels, threads or a worker protocol. ## Requirements Racket packages: - `racket-audio` - `simple-ini` - `simple-log` - `net-lib` Native libraries are provided or loaded by `racket-audio`. For the current audio path this normally means FLAC, Opus/Opusenc, TagLib and SoXR. FFmpeg is not part of the intended FLAC-to-Opus path; it is only relevant for `racket-audio` features that need FFmpeg-based decoding. ## Usage From a Racket REPL or a small wrapper script: ```racket #lang racket/base (require audio-library-manager) (audio-manager "/mnt/music" "/mnt/music-opus") ``` The first argument is the source music tree. The second argument is the target Opus mirror tree. The optional log level defaults to `debug`: ```racket (audio-manager "/mnt/music" "/mnt/music-opus" #:log-level 'info) ``` ## Files created in the source tree The manager stores its administration files in the source directory: - `.audio-manager.ini` — configuration, read with `simple-ini`. - `.audio-manager.db` — serialized state hash, keyed by normalized relative paths. - `.audio-manager.log` — log file. State keys are normalized relative paths from the source tree. Absolute mount points are not stored, and path separators are normalized to `/`. This makes the state less dependent on the local mount point used on a particular machine. ## Configuration The manager expects a configuration file at: ```text /.audio-manager.ini ``` Example: ```ini [flac] max-khz=48000 [opus] kbps=224 [mail] from=Audio Manager to=Hans server=smtp.example.org port=25 user= passwd= ``` The mail section is currently required. If the mail configuration is missing or incomplete, the manager fails at startup with a configuration error. This is intentional: a batch run should not silently skip reporting. ## Processing model The manager uses a file walker with an ordered processing pipeline. Each step receives: ```racket base-path path info ``` and returns the same three values, with `info` possibly enriched. The `info` hash contains the relative path, type, extension, state and any metadata discovered by earlier steps. The important file states are: - `new` — the relative path was not present in the saved state. - `changed` — the path existed before, but type, size or modification time changed. - `unchanged` — the path exists and its basic filesystem state is unchanged. - `deleted` — the path existed in the saved state but no longer exists in the source tree. For unchanged entries, the previous enriched `info` hash is reused. For changed entries, the previous `info` hash is reused but marked as `changed` and updated with the current type, size and modification time. Stages must therefore treat `changed` as the signal to re-inspect content-dependent data. The pipeline is grouped conceptually as: 1. enrichment: normalize/identify known extensions, sniff audio files, detect FLAC-with-ID3, and read FLAC sample rate/bit depth when needed; 2. conversion/actions: downsample FLAC files above the configured rate, embed a sidecar cover image when a FLAC has no embedded picture, convert FLAC to Opus, and copy non-FLAC sidecar files; 3. cleanup/logging: remove target files for deleted source entries and log progress. ## FLAC handling FLAC files are detected by extension and confirmed by `racket-audio` sniffing. A file with extension `.flac` but an ID3 prefix is reported as a FLAC-with-ID3 case. Such files are not treated as ordinary sidecar files. For valid FLAC files: - sample rate and bit depth are read through the FLAC decoder; - files with a sample rate greater than `[flac] max-khz` are converted in place through `racket-audio/audio-encoder`; - conversion is synchronous and direct; - if the file has no embedded picture, `cover.jpg`, `cover.jpeg`, `folder.jpg`, `folder.jpeg`, `cover.png` or `folder.png` in the same directory is embedded as a front-cover picture. Temporary FLAC files produced by interrupted conversions should be ignored by the scanner. The implementation uses manager-specific temporary names for this purpose. ## Opus mirror handling For every processable FLAC source file, the manager writes a corresponding Opus file under the target tree: ```text source: album/track.flac target: album/track.opus ``` The default bitrate is 224 kbps and can be changed with `[opus] kbps`. Non-FLAC files are copied unchanged to the target tree when they are new, changed, or missing from the target. Hidden files are ignored. Typical copied sidecar files include cover images, PDFs, cue sheets and logs. When a source entry is deleted, the corresponding target entry is removed. For a deleted FLAC source, the target extension is changed from `.flac` to `.opus`. Renames are deliberately represented as `deleted` plus `new`; no rename detection is attempted. ## Logging and report The manager logs to: ```text /.audio-manager.log ``` The report contains sections for: - FLAC files with ID3 tags; - FLAC conversions and cover updates; - Opus conversions; - file counters for processed, new, changed, unchanged and deleted files; - failed conversions and failed copies. At the end of a successful scan the serialized state is written to `.audio-manager.db` and the report is sent by mail. ## API ```racket (audio-manager music-path opus-path #:log-level [log-level 'debug]) ``` Runs the complete batch process. `music-path` is the source tree and `opus-path` is the target Opus mirror tree. The function returns `'done` after a completed run. ## Design notes The package intentionally keeps responsibilities separated: - `audio-manager.rkt` orchestrates the batch run and owns the pipeline; - `private/file-walker.rkt` scans the filesystem and maintains the state model; - `private/flac-handling.rkt` contains FLAC inspection and FLAC downsampling; - `private/opus-handling.rkt` contains FLAC-to-Opus conversion; - `private/mail.rkt` sends reports; - `private/log.rkt` defines the logger; - `private/util.rkt` contains small path/date/cover helpers. The manager does not implement an audio pipeline itself. Audio decoding, encoding, metadata and resampling are delegated to `racket-audio`.