Files

217 lines
6.7 KiB
Markdown

# 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
<source-tree>/.audio-manager.ini
```
Example:
```ini
[flac]
max-khz=48000
[opus]
kbps=224
[mail]
from=Audio Manager <audio@example.org>
to=Hans <hans@example.org>
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
<source-tree>/.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`.