Three things the 2026-10-31 five-library relayout taught, written where the next operator reads them: - A verify run must open the servers' databases plain `mode=ro`. Both keep their libraries in WAL mode; `immutable=1` skips the write-ahead log, so a scanner's own committed rows read as missing and the read can fail as "database disk image is malformed". The census page claimed immutable — now it says what the code does. - "No row at the destination" splits into four classes, and only REAL (no row at dst AND the file still at src) is the relayout's own damage. Phantom rows naming a pre-move path are normal behaviour for both servers. And the owning server decides whether a pass can convict: Jellyfin holds no audiobook library, so that journal verifies against Plex or it proves nothing. - A chain of passes rolls back newest journal first, or the tool refuses; the refusals measured that day are the tool working, not failing. The music and audiobook arms moved to their own pages (progressive disclosure; the parent drops 175 lines and stays the owner of the shared gates, the executor, the journal law and the rollback). Stale per-run counts destroyed: episode counts, byte sizes, move tallies for a pass that already happened.
75 lines
3.8 KiB
Markdown
75 lines
3.8 KiB
Markdown
---
|
|
type: reference
|
|
title: Media Audiobook Relayout
|
|
description: "Re-filing /mnt/entropy/Audiobooks by Plex's chapter rows: narrator shelves, no renumbering, the refusals."
|
|
tags: [dankserver, media-server, plex, media-relayout]
|
|
timestamp: 2026-10-31T00:00:00Z
|
|
---
|
|
|
|
# Media Audiobook Relayout
|
|
|
|
`/mnt/entropy/Audiobooks` is the one library here that [[Jellyfin]] does not read
|
|
at all — its music scanner has no audiobook concept — while [[Plex]] indexes all
|
|
of it as Artist → Album → Track: the album is the BOOK, that book's single artist
|
|
is the NARRATOR, both matched out of the files' own tags. Today one book is split
|
|
across `… [Part 1]`, `… [Part 2]` folders three or four deep inside a collection
|
|
pack, so a scan serves three quarters of a novel; `scripts/media-audiobooks.py`
|
|
re-files the tree so the property both servers' book scanners assume is true —
|
|
|
|
Audiobooks/<Narrator>/<Book> (<year>)/<the file keeps its own name>
|
|
|
|
The shared gates, the executor, the journal law and the rollback live in
|
|
[[Media Relayout]]; this page is the audiobook arm only.
|
|
|
|
```bash
|
|
# 1. The authority: Plex's chapter rows for this root (the DB opens read-only).
|
|
python3 scripts/media-census.py audiobooks --root /mnt/entropy/Audiobooks \
|
|
--out /tmp/ab_rows.tsv
|
|
# 2. What is on disk (stat only).
|
|
python3 scripts/media-census.py enumerate --root /mnt/entropy/Audiobooks \
|
|
--out /tmp/ab_enum.tsv
|
|
# 3. The plan.
|
|
python3 scripts/media-audiobooks.py --root /mnt/entropy/Audiobooks \
|
|
--enum /tmp/ab_enum.tsv --rows /tmp/ab_rows.tsv --out /tmp/ab_plan.tsv \
|
|
--exceptions /tmp/ab_exceptions.txt
|
|
# 4. Read the exceptions file FIRST. Then the same executor, journal and rollback
|
|
# as [[Media Relayout]] shows, on its own journal, and refresh the Plex section
|
|
# as in step 5 of the movie Procedure — from inside the container, never over
|
|
# the host port.
|
|
scripts/media-apply.py apply --plan /tmp/ab_plan.tsv --root /mnt/entropy \
|
|
--journal /mnt/entropy/media-relayout-audiobooks.jsonl --apply
|
|
```
|
|
|
|
The group is the identity Plex asserts in its own database — **(narrator, book,
|
|
year)** — so one book arriving in four part folders becomes one folder, and a
|
|
1965 and a 2020 recording that share a title stay two books.
|
|
|
|
Two laws are forced by what the rows actually hold:
|
|
|
|
+- **A chapter is never renumbered.** Most books contain chapters whose index Plex
|
|
does not know, so a number written into a name would be invented — and it would
|
|
buy nothing, because both servers order playback by the embedded track tag, not
|
|
by the file name. A wrong number in a name is the number a human later trusts.
|
|
Fix order in the tags: a Plex scan re-reads tags and never renames a file.
|
|
+- **The shelf is the narrator, not the author.** Every book has exactly one artist
|
|
row and it is the narrator; the author survives only inside some album titles
|
|
(`Kryptos by Graham McNeill`) and in no column Plex stores, so deriving it would
|
|
mean parsing titles where a ripper wrote one and inventing it everywhere else.
|
|
The author stays visible in the folder name Plex itself shows.
|
|
|
|
What it refuses, the music arm's list with one addition: a video container, audio
|
|
no chapter row names, and a loose file in a folder holding two books all park under
|
|
`_unsorted` with the path they have today — and so does a chapter whose row names
|
|
**no book or no narrator**: a placeholder (`[Unknown Album]`, `[Unknown Artist]`)
|
|
that unrelated books share, or a chapter number mistagged as the artist (`0.4`).
|
|
`Various Artists` is not a placeholder — that is a multi-cast read.
|
|
|
|
The reviewed plan lives at `/mnt/entropy/media-relayout-audiobooks-plan.tsv`; it
|
|
applies on its own journal, behind the music writer, and then refreshes the Plex
|
|
section. Verify it with `--db-kind plex` — Jellyfin holds no rows here, so a
|
|
Jellyfin pass proves nothing either way.
|
|
|
|
## See Also
|
|
|
|
[[Media Relayout]], [[Media Music Relayout]], [[Plex]]
|