fix(scan): match audiobook files by embedded tags when path heuristics fail#688
fix(scan): match audiobook files by embedded tags when path heuristics fail#688rknall wants to merge 1 commit into
Conversation
…tics fail The per-audiobook file scan attributed candidate files using only path/name heuristics: a file was kept only if its filename or folder contained the audiobook title, or its path contained the author. Layouts where the folder/filename does not carry that information (e.g. AudioBookShelf-style series-creator folders with numbered episode filenames) had every candidate rejected, so correctly-placed files were never linked (0 files imported). Add an embedded-tag confirmation fallback: for candidates the path heuristics reject, read the file's ID3/MP4 tags (reusing PathMetadataParser via the bundled ffprobe) and attribute the file when the embedded ASIN matches the audiobook (definitive), or when both title and author agree after normalization. Tags are read concurrently with a bounded degree of parallelism; the match decision is applied on a single thread. The match logic is factored into ScanBackgroundService.MatchEmbeddedTags and covered by unit tests.
|
The ASIN-definitive / title+author split here looks like the right shape to me, and I like that the fallback only runs on candidates the path heuristics already rejected, so the common case pays nothing. Two notes, one of them just housekeeping. This currently conflicts with One thing I'd want to fix in the rebase rather than carry forward. Since the branch doesn't build against The title test is a bidirectional H. Rider Haggard is the clean example.
They're all by Haggard, so It isn't only short titles, either. Audible's real title for Haggard's Marie is Worth saying: adding word boundaries doesn't fix this. I tried that first. For context on why I care about the softer branch: across a test library of over 1,500 books, zero of the files carried an ASIN in any spelling Are you planning to rebase this? Happy to help — I can send the title-matching fix and the xunit cases as a PR against your branch, or if it's easier, put up a fresh branch carrying your work forward with you credited. Whichever you prefer; I don't want to step on it. The test file drops in standalone either way, if it's useful. (Unrelated to this PR, but for context on where I'm coming from: #763 is a naming-path fix I put up separately — series positions from Audnexus aren't always numbers, and a non-numeric one was being dropped and replaced by the track number. Different subsystem entirely; mentioning it only so the above doesn't read as a drive-by.) |
Summary
Audiobooks whose on-disk layout does not encode the title/author in the folder or filename — e.g. AudioBookShelf-style libraries with series-creator folders and numbered episode filenames — were left with zero linked files after a scan, even when the files sat in the correct
BasePath. The per-audiobook scan attributed files purely by path/name heuristics (filename/folder must contain the title, or the path must contain the author), which reject these files.This adds an embedded-tag confirmation fallback: for candidates the path heuristics reject, the scan reads the file's embedded ID3/MP4 tags (via the bundled ffprobe, reusing
PathMetadataParser) and links a file when its embedded ASIN matches the audiobook (definitive), or when both title and author agree after normalization.Changes
Added
ScanBackgroundService.MatchEmbeddedTags— a pure, unit-tested decision for attributing a file to an audiobook from its embedded tags (ASIN = definitive; title+author = softer fallback).PathMetadataParser.ReadEmbeddedTagsAsync+ the bundled ffprobe.Changed
min(4, CPUs)); the match decision is applied on a single thread.Testing
ScanBackgroundServiceTagMatchTests(9 cases: ASIN match incl. case/whitespace insensitivity, title+author when the ASIN differs, punctuation/subtitle tolerance, author-only and title-only negatives, null/empty tags) — all pass..../Elfie Donnelly/Bibi und Tina/61 - Retten die Biber/Bibi und Tina - 61 - Retten die Biber.mp3) went from 0 → 1 linked file, confirmed via the embedded ASIN.Notes
PathMetadataParserto also read plaintitle/artisttags (it currently readsalbum/album_artist); and regional ASIN mismatches (file tag carries the.deASIN while the record holds the.comASIN), which belong with the regional-search work.