# Audiobook metadata: sources & precedence Every audiobook ingestion path (single-file, folder-of-tracks, zip-of- audio) fills the same fields from the same ranked sources. Each source **only fills fields the earlier ones left empty** — curated data always outranks guesses — and every source is optional: a book still ingests (title from the filename) when all of them are absent. Admin edits made after ingest are protected by the metadata-override mechanism on rescans, regardless of source quality. ## Book-level metadata (title, author, narrators, series, …) | Rank | Source | Feeds | |---|---|---| | 1 | **Sidecars** — `metadata.opf` (Calibre), `metadata.json` (Audiobookshelf/Libation, array-or-string tolerant) | title (+subtitle join), author, series + index, narrators, abridged, ASIN, tags/genres, dates, publisher, description | | 2 | **Folder structure** — `Author/Title`, `Author/Series, Book #N - Title`, `Author/Series/Title` | title, author, series + index | | 3 | **Embedded tags** (via ffprobe) | `album` → title; `album_artist` → author (`artist` fallback); `composer` → **narrators** (Audible's own convention); `grouping` → series; `date` → publish date; `genre` → genre; Audible freeform atoms `----:com.apple.iTunes:SERIES`/`:SERIES-PART`/`:SUBTITLE`/`:ASIN`/`:ABRIDGED` | | 4 | **Filename/folder name** | title last of all (created only — never lets a rescan blank a title) | Abridged is the one guarded field: an explicit sidecar `false` wins even when a tag says `true` (the sidecar's presence is tracked, not just its value). Narrators from the composer tag stay ONE string — composer values have no reliable multi-narrator delimiter, and splitting "Vance, Simon" would manufacture fake people. ## Chapters (the `{index, title, start, end}` array) | Rank | Source | |---|---| | 1 | Sidecar `metadata.json` `chapters[]` (curated, global seconds) | | 2 | Embedded m4b chapter atoms (`chpl` / QuickTime text track, read by ffprobe) | | 3 | **CUE sheet** — `.cue` next to the audio file (FILE-directive matched, `INDEX 01 MM:SS:FF` at 75 fps); the classic one-big-flac + cue rip shape | | 4 | Track boundaries — for folder/zip books, each file is a chapter | ## Track ordering (multi-file books) | Rank | Source | |---|---| | 1 | **Playlist** — exactly one `.m3u`/`.m3u8` among the book root's direct children; its entry order wins and `#EXTINF` names the tracks | | 2 | **Tags** — `(disc, track)` sort when *every* track carries a track number (fixes flat `01.mp3` dumps from multi-disc rips) | | 3 | **Natural sort** of relative paths (`02` before `10`), recursive — the default | Track display titles, highest first: `movement_name` → `title` tag → playlist `#EXTINF` → cleaned filename (leading ordinals/separators stripped). ## Book grouping (which files form one book) - The book root is the nearest ancestor holding audio files DIRECTLY, merged upward through disc-part directories (`CD1`, `Disc 2`, `Part 3`, `05`) when the parent has no audio of its own. - Sibling directories are NEVER merged (two books under one author stay two books); a root with a single track falls back to the single-file model. - A lone `.zip` of audio files is its own book (layout "zip"); a folder of tracks is one book with `file_path` = the directory (layout "folder"); a single audio file is the Batch A model (no layout key). - Rescans take a fast path (track count + total size + known durations unchanged → no re-probe) and absorb pre-grouping one-track strays. ## Covers | Rank | Source | |---|---| | 1 | Sidecar `cover.jpg` / `folder.jpg` / … next to the book | | 2 | **Embedded art** (`APIC` mp3, `covr` m4b, flac picture) — one optional ffmpeg call, written as a `.cover.jpg` sibling following the EPUB convention | ## Accepted containers (audiobook libraries) `.m4b` `.m4a` `.mp3` `.flac` `.zip` (book container) `.opus` `.ogg` `.oga` `.aac` `.wav` — all browser-playable; served with their real media types (`audio/ogg` per RFC 7845 for Opus-in-Ogg, etc.). ## Documented non-goals - **ID3v2 CHAP/CTOC chapter frames** — the written MP3 standard for embedded chapters, near-zero audiobook adoption; would need a hand-rolled ID3v2.4 parser. Revisit only if real files show up. - **NFO sidecars** — no genuine audiobook NFO standard exists (Jellyfin's Bookshelf uses Calibre OPF, which we read). - **ReplayGain / EBU R128 loudness tags** — a playback feature, not ingestion; separate plan if ever wanted. - **`.wma`** — browsers cannot play it; excluded deliberately.