From ad9563412de56ab671de1dcbfff3badafedb5477 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 2 Nov 2026 03:59:14 -0800 Subject: [PATCH] docs(audiobookshelf): what a residual is made of MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four laws from finishing the un-shadow, correcting one: - A book whose files ALL fail to probe never becomes an item, so a disk-vs-DB folder gap beside `Invalid data` lines is corrupt media, not a lost book. A format-only ffprobe clears files the scanner rejects — do not trust it. - `Disc 01`/`CD 1` subfolders are parts of one item (110 of them here, under a 192-track book); the extension census counts them, ABS does not. - `.cbr`/`.cbz` group like media but `parseComicMetadata` throws `ERAR_BAD_ARCHIVE`, so those items land media-less: the file, not the scanner. - Scan completion is a NEW scan uuid; `podman logs --since` is a sliding window and ages its own evidence out. - `?force=1` is now recorded as neither discovery nor repair: a forced full re-scan left item count, path set and media-less count identical. Verification names the five book folders that need re-acquiring. --- .../Dankserver/Audiobookshelf.md | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/serverAppConfigs-docs/Dankserver/Audiobookshelf.md b/serverAppConfigs-docs/Dankserver/Audiobookshelf.md index 837370b..d7e15a2 100644 --- a/serverAppConfigs-docs/Dankserver/Audiobookshelf.md +++ b/serverAppConfigs-docs/Dankserver/Audiobookshelf.md @@ -153,21 +153,37 @@ the file, not the bind: the same line count grows while the total climbs. ABS's own single-book layout; formats of one book share a folder), through the journal-guarded mover, then delete the stale item so the old path is not kept, then scan. -- **`?force=1` is not a discovery arm.** Both arms of `POST /libraries/:id/scan` - walk the disk; force additionally re-scans every item that already exists - (measured 1:33 against 0:04 on ~4,600 items). Finding new folders needs neither, - so the deployer's cheap trigger stays on the plain arm. +- **`?force=1` is neither a discovery arm nor a repair arm.** Both arms of + `POST /libraries/:id/scan` walk the disk, so finding new folders needs neither + and the deployer's cheap trigger stays on the plain arm. Force additionally + re-scans every item that already exists (measured 1:33 against 0:04 on ~4,600 + items) and repaired nothing on a library whose residuals were file-level: item + count, path set and media-less count identical before and after. - **`DELETE /api/items/:id` is a DB row; `?hard=1` is `fs.remove()`.** In `LibraryItemController.delete`, `hardDelete = req.query.hard == 1` and then `fs.remove(libraryItemPath)`. Pointed at a covering item, that path is the whole swallowed subtree — `hard=1` there deletes every book beneath it off the array. Assert the item's `path` first, and never pass `hard`. - **`Invalid data found when processing input` names the file, not the bind.** The - scanner logs it per file and skips the file — the book never appears — so a - missing title beside those lines is library debris, not a server fault. Census of - the refusals on the first full scan: 38 of 43 files were 0 bytes, 3 were WAV - bytes wearing a `.mp3` name, 2 were unreadable. `stat -c %s` before any - investigation of the server. + scanner logs it per file and skips that file; a book whose files ALL fail never + becomes an item at all, so the disk-vs-DB folder census shows it as a book with + no item. That is corrupt media, not a lost book. Never clear a suspect file with + a lenient probe: `ffprobe -show_entries format=duration` happily returns three + hours for the WAV bytes wearing a `.mp3` name that the scanner refuses. Read the + log's file paths instead, and `stat -c %s` first — 0-byte files are the common + case, and a truncated download reports `moov atom not found`. +- **A `Disc 01` / `CD 1` subfolder is part of a book, not a book.** The extension + census counts those folders; ABS deliberately does not — its grouping attaches + their files to the ancestor item (measured: 110 such folders under one item + carrying all 192 tracks). Read the basename before believing a disk-vs-DB gap. +- **`.cbr`/`.cbz` group like media and never play.** They sit in the grouping + predicate, so they hide books, but the comic parser throws `ERAR_BAD_ARCHIVE` + (`parseComicMetadata` → `CbrComicBookExtractor`) and the item lands with no + media. A media-less row beside those lines is the file, not the scanner. +- **A scan is finished when a NEW scan uuid completes.** Match + `Library scan "" completed in ...`. `podman logs --since 30m` is a sliding + window: the set of visible completion lines changes on its own as old lines age + out, so a poller keyed on that hash reads a mid-scan number and calls it done. ## Verification @@ -178,3 +194,10 @@ stub of the API above: create-once, idempotent re-run, no secret in a URL, refus by URL when the server does not answer, and the deployer calling it only after the health gate) and `tests/media_overlay.bats` (only [[Plex]] and [[Jellyfin]] may reference the metadata view). + +Five book folders hold media no scanner can read, so they stay out of the library: +three 2024 Nebula nominees in the `_unsorted` box (two `.m4b` with no `moov` atom, +one 36-file `.mp3` set that is not MPEG audio at all), `Anthony Heald/Bounty +Hunter Wars - Book 1` and `Star Wars Full Cast Audio Drama/Dark Empire III` — the +latter two also exist in readable form under their author folders. Fix by +re-acquiring the files; the scanner names every one of them in its log.