documentation and small bug fixes

This commit is contained in:
2026-06-28 18:55:40 +02:00
parent b1b593896a
commit e538e8b180
7 changed files with 362 additions and 223 deletions
+187 -105
View File
@@ -1,134 +1,216 @@
# audio-library-manager
Tools for maintaining audio library trees.
`audio-library-manager` maintains a music library in two forms:
The package currently contains two managers:
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.
- `flac-48khz-manager.rkt`: keeps a FLAC tree at a maximum sample rate of 48 kHz.
- `flac2opus-manager.rkt`: mirrors a FLAC source tree to an Opus target tree.
The current entry point is `audio-manager.rkt`, exported as the function
`audio-manager` from `main.rkt`.
Both managers use the same administration files in the source tree:
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.
- `.music-info.db`: keystore state database
- `.flac-48khz-manager.ini`: configuration
- `.flac-48khz-manager.log`: log file
## Requirements
The `flac2opus` state uses its own key prefix in `.music-info.db`, so it can share
the same database with the 48 kHz manager without mixing state entries. State
keys use only normalized paths relative to the configured source/base directory:
absolute mount points are not stored, and path separators are always `/`.
Racket packages:
## FLAC 48 kHz manager
- `racket-audio`
- `simple-ini`
- `simple-log`
- `net-lib`
The command keeps a FLAC directory tree at a maximum sample rate of 48 kHz.
Files above the configured threshold are converted in place by a direct call to
`racket-audio/audio-encoder`. The conversion code is deliberately synchronous:
no places, channels or worker protocol are used.
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.
Run:
## Usage
```sh
racket flac-48khz-manager.rkt /path/to/flac-tree
```
When a FLAC file has no embedded picture and the same directory contains one of
`cover.jpg`, `folder.jpg`, `cover.png` or `folder.png`, the manager embeds that
image as front-cover picture before fingerprinting/conversion. This keeps FLAC
artwork consistent before a later Opus mirror is made.
The `flac-48khz-manager` scanner only processes `.flac` files. Other files such
as `.mp3`, booklets and cover images are ignored by this manager.
## FLAC to Opus mirror manager
The command mirrors a source directory to a target directory. FLAC files are
converted to Ogg Opus files with extension `.opus`; all other regular files are
copied unchanged, preserving their relative path and modification time. Examples
include `booklet.pdf`, `cover.jpg`, `folder.png`, cue sheets, text files and
other sidecar files.
Run:
```sh
racket flac2opus-manager.rkt /path/to/flac-tree /path/to/opus-tree
racket flac2opus-manager.rkt --kbps 192 /path/to/flac-tree /path/to/opus-tree
```
The default Opus bitrate is 224 kbps. The library API exposes the same setting
as keyword argument:
From a Racket REPL or a small wrapper script:
```racket
(manage-flac2opus-tree source-directory target-directory #:kbps 224)
#lang racket/base
(require audio-library-manager)
(audio-manager "/mnt/music" "/mnt/music-opus")
```
Metadata is copied through `racket-audio/taglib` and `racket-audio/audio-encoder`:
ordinary TagLib properties are transferred, embedded pictures are transferred,
and an additional `FLAC2OPUS` comment is written to mark the conversion. The
batch converter itself remains a simple synchronous function call.
The first argument is the source music tree. The second argument is the target
Opus mirror tree.
The manager removes target files that belonged to source files which disappeared
since the previous run. It deliberately does not mirror its own root-level
administration files: `.music-info.db`, `.flac-48khz-manager.ini` and
`.flac-48khz-manager.log`.
The optional log level defaults to `debug`:
Paths are handled as Racket paths rather than by splitting on `/`, so Windows
absolute paths and UNC paths such as `\\panderleou\music` are preserved by the
platform path implementation.
```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
Important configuration keys are created automatically in `.flac-48khz-manager.ini`.
The same file is used by both managers. The implementation now reads this file as a simple-ini value directly; there is no separate configuration struct layered on top of the ini model.
The manager expects a configuration file at:
```ini
[manager]
max-sample-rate=48000
hash-algorithm="sha256"
change-detection="flac-taglib"
dry-run=#f
display-log=#t
log-file=".flac-48khz-manager.log"
compression-level=5
[opus-manager]
log-file=".flac2opus-manager.log"
[mail]
enabled=#f
send-on-success=#f
send-on-error=#t
host=""
port=25
tls=#f
username=""
password=""
from=""
to=""
cc=""
bcc=""
subject-prefix="[flac-48khz-manager]"
```text
<source-tree>/.audio-manager.ini
```
SMTP reports are HTML and summarize counters and errors.
Example:
## Change detection
```ini
[flac]
max-khz=48000
The default change detection is `flac-taglib`:
[opus]
kbps=224
1. unchanged files are skipped with a cheap `size` + `mtime` comparison;
2. new or visibly changed files get a semantic fingerprint;
3. for FLAC files, the semantic fingerprint consists of FLAC STREAMINFO data,
including the FLAC audio MD5 signature, plus TagLib properties and embedded
picture metadata/content hash;
4. for non-FLAC files in the Opus mirror, the default is `mtime` + `size`;
5. full-file hashing is available by setting `change-detection="hash"`.
[mail]
from=Audio Manager <audio@example.org>
to=Hans <hans@example.org>
server=smtp.example.org
port=25
user=
passwd=
```
This avoids reading every complete audio file during a normal run, which matters
on Windows and network shares.
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.
## FLAC files with ID3v2 prefixes
## Processing model
Version 0.1.4 accepts native FLAC files that start directly with `fLaC`, and FLAC
files with an ID3v2 tag before the `fLaC` marker. The latter occurs in some
libraries and is accepted by players such as foobar2000/libFLAC. The fast
STREAMINFO reader skips the ID3v2 prefix before reading the FLAC metadata.
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`.