feat(13-04): tag extraction across mp3/flac/m4a/ogg with media-root confinement
Completes Task 3 on top of the recovered wip checkpoint (be8f24b4):
- fix the programmatically-generated MP3 fixture's frame length: lofty's
Header::read computes samples*bitrate*125/sample_rate with truncating
integer division BEFORE adding the padding byte, so the FF FB 52 C4
frame is 209 bytes, not 210 — the off-by-one made cmp_header miss the
second frame sync and reject the whole file as containing an invalid
frame (mp3_id3v24_yields_full_record now passes; fixture-only fix,
production code untouched)
- all 7 music::tags tests green; no binary audio fixtures committed
(fixtures are built byte-by-byte into tempdirs at test run time)
- extract_tags canonicalizes and confines to caller-supplied media_roots
before opening any file (T-13-20); non-audio is a distinct NotAudio
error vs the Ok/has_tags=false untagged fallback (T-13-21)
- entity types in music/mod.rs implement 13-MUSIC-MODEL.md exactly:
hybrid-identity TrackId, derived albums/artists, MUSIC_SCHEMA_VERSION=1
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
be8f24b4e3
commit
4b577493b1
@@ -165,10 +165,16 @@ mod tests {
|
||||
/// 64kbps, 44100Hz, mono, padded — the exact byte pattern lofty's own
|
||||
/// test suite uses as a known-good frame header
|
||||
/// (`mpeg/header.rs::tests::rev_search_for_frame_header`). Its computed
|
||||
/// frame length (samples * bitrate * 125 / sample_rate + padding) is
|
||||
/// 210 bytes.
|
||||
/// frame length matches lofty's `Header::read` exactly:
|
||||
/// `samples * bitrate * 125 / sample_rate` truncates *before* the
|
||||
/// padding byte is added — `1152 * 64 * 125 / 44100 = 208`, `+ 1`
|
||||
/// padding = **209** bytes. The frames written below must be exactly
|
||||
/// this long, because lofty confirms a frame sync by comparing the
|
||||
/// candidate header against the bytes found exactly `len` later
|
||||
/// (`find_next_frame`/`cmp_header`); an off-by-one frame length makes
|
||||
/// the whole file "contain an invalid frame".
|
||||
const MP3_FRAME_HEADER: [u8; 4] = [0xFF, 0xFB, 0x52, 0xC4];
|
||||
const MP3_FRAME_LEN: usize = 210;
|
||||
const MP3_FRAME_LEN: usize = 209;
|
||||
|
||||
fn mp3_frame() -> Vec<u8> {
|
||||
let mut frame = MP3_FRAME_HEADER.to_vec();
|
||||
|
||||
Reference in New Issue
Block a user