Commit Graph
3 Commits
Author SHA1 Message Date
vicrodh b6c69509df build(deps): unify lofty at 0.25.1
cx
2026-08-26 21:31:47 -06:00
vicrodh b69a058bc3 feat(rip): a provenance log and the cover, beside the tracks
qbz-rip.log is deliberately NOT an EAC log. An EAC or XLD log is trusted for
what it PROVES — test-and-copy, a drive read-offset correction, an AccurateRip
cross-check against thousands of other rips of the same disc — and QBZ does
none of the three. A file that imitated the format without the method would be
worse than no file: it invites a claim this ripper cannot back, and the people
who read rip logs are exactly the people who check.

So the header says what it is and is not in the first block, not in small
print. What remains is true and useful: which disc (DiscID and TOC fingerprint,
both recomputable by anyone holding it), which drive, and per track the audio
md5 that already lives in the file's own STREAMINFO — verifiable with flac -t
without QBZ. Verified end to end: metaflac --show-md5sum prints exactly what
the log claims, and flac -t passes on every track.

"0 read errors" is a real promise and is stated as one: an unreadable sector
ABORTS the rip rather than being written as silence, which is stronger than a
burst-mode EAC rip. Where the OS did the reading there is no drive to name, and
the log says that instead of printing a volume as though it were hardware.

A partial rip declares itself partial: three tracks with no such line read as
the whole album.

cover.jpg keeps the source's EXTENSION — renaming a PNG to .jpg is how a
picture stops opening. Neither sidecar can fail the rip: the audio is the
deliverable, and a missing extra is a blemish on a folder of correct files.

Five tests, including that the log states all three things it does not do, that
the logged digest IS the file's own, and the calendar arithmetic that is the
only thing here that could be quietly wrong for years.

cc
2026-08-21 18:57:42 -06:00
vicrodh 5d3d51a882 feat(rip): rip a CD to tagged FLAC, bit-exact and seekable
New crate `qbz-rip`: CD audio in, tagged FLAC out. Frontend-agnostic — it
knows discs, samples and files, and reports progress through a callback so a
UI can drive it without this crate depending on one.

`flacenc`, pure Rust: no libFLAC to build, nothing extra to bundle into
Flatpak, Snap or AppImage, and macOS gets it for free. `lofty` (already in the
tree) writes the Vorbis comments.

`RipSource` is the portability seam, and it is the only part that differs
between platforms: Linux reads sectors through ioctls, while macOS MOUNTS an
audio CD and presents each track as an AIFF under /Volumes — so there a "read"
is a file read. Everything after the seam is shared.

Two defects were found by ripping a real disc and looking at the result, and
neither would have failed a test:

  1. The tags were never written. Tagging happened on the `.flac.part` file,
     and lofty identifies a file by its EXTENSION — so it wrote nothing, and
     said nothing. Tagging now happens after the rename, with a test that
     reads the bytes back and asserts the strings are in them.

  2. The files could not be SEEKED. `flac -d --skip=2:00` returned
     FLAC__STREAM_DECODER_SEEK_ERROR and `flac -t` warned 3102 times over 3103
     frames. The cause is precise: a stream's last frame is short (12 709 620
     samples at a 4096 block leaves 3828), flacenc reports that honestly as
     min_blocksize 3828 / max 4096 — but in FLAC `min != max` MEANS
     variable-blocksize, and a decoder reading one expects SAMPLE numbers in
     the frame headers while the frames correctly carry FRAME numbers.
     libFLAC's own encoder writes min == max for exactly this reason. Two
     bytes of STREAMINFO, and now: zero warnings, seek works.

Verified against the drive, not inferred: 176 400 bytes decoded out of the
FLAC are byte-identical to the same sectors read straight off the disc. The
whole album ripped from the UI — seven tracks, 436 MB, every one decoding
clean, tagged with TITLE/ARTIST/ALBUM/TRACKNUMBER/TRACKTOTAL/DATE/ALBUMARTIST,
and no partial file left behind.

Filenames are sanitised for the strictest filesystem the library might be
copied to, including Windows' reserved DEVICE names and its habit of silently
dropping a trailing dot — which would turn two tracks into one collision.

cc
2026-08-21 02:27:24 -06:00