Plan a TV relayout from the numbering Jellyfin already has
/mnt/entropy/TVShows is scene packs, not a library: release folders with
seasons buried several levels down, subtitles under Subs/<release-name>/, and
bonus material in nine spellings of "Extras". Jellyfin has already matched and
numbered most of it — 47,676 of its 58,551 files carry a matched, numbered
row. This branch makes that work the authority for re-filing the library, and
refuses to guess where it is absent.
What lands
scripts/media-census.py jellyfin — export the matched rows (file series year season episode extra tmdb) from the live database, opened read-only.
scripts/media-census.py enumerate|probe — what is on disk, and the runtimes
the film arm needs.
scripts/media-shows.py — the planner: plan TSV in the executor's own format
plus an exceptions file that is the review, not a log.
scripts/media-apply.py is unchanged and does the moves: journal first, rollback and sweep afterwards. Nothing in this branch touches the library.
serverAppConfigs-docs/Dankserver/Media Relayout.md gains the section that
owns the contract and the evidence chain.
Evidence, strongest first
the episode marker the file's own name states (S01E02-E03, 1x04);
the Season NN folder it sits in and the number its name leads with inside
it — Season 19/01 Charles Barkley, Nirvana.avi is S19E01;
the provider row, for identity (series name and year) and for numbering a
file whose own name says nothing;
a bonus folder anywhere above the file, or Jellyfin's ExtraType;
runtime over SHORT_MAX → film-shaped, and it leaves for --movies only
when a movie provider names it.
Two refusals, both earned on the real library
Folders resolve a series; they never invent one. An early run turned …/03. Extra/01. NCOP/NCOP 01.mkv into a root-level series called 01 NCOP.
Folder text may now only match a registered name as a token run — (CBB) Tengen Toppa Gurren Lagann - The Complete Series (BD 1080p) names Tengen Toppa Gurren Lagann — and a bonus subfolder with no registered name
in any ancestor parks.
A scraped row does not outrank the filesystem. Jellyfin numbers multi-season
packs badly: every file under SNL 16-20/Season 16..19 carries season 16
episode 20 in the database, and one Gundam row says season 2004. The folder and
the file's own leading number win; a row that still insists on season 1989
parks its file instead of creating Season 1989.
Also fixed on the way: a sidecar now searches every ancestor folder for the video
it names (the Subs/<release-name>/ layout was losing 792 subtitles), and the
shared bonus-folder test no longer reads a bare index as a title — name_words
drops "extras" as release junk, so 01. Extras reduced to 01 and "matched"
the 01 of NCOP 01, cancelling the bonus evidence in the engine's own guard.
Verification
tests/media_shows.bats: 19 behaviors, each one output-level — where a file
lands, what parks, that a destination is never claimed twice, that re-planning
a library the plan already satisfies moves nothing.
./tests/run.sh: 684 tests green.
Dry run against the real library (read-only, nice -n 19): 48,757 moves,
9,680 parked, 5,799 folders, 39.02 TiB "touched" — renames on one filesystem,
so no data moves and no space is needed. The run-time census is still
finishing, so the film arm has not had its durations yet: the 1,664 parked
long files will become films (or stay parked) on the next plan.
What this does NOT do
Nothing is applied. scripts/media-apply.py --apply against the library is the
next step and belongs after Frank has read the exceptions report — /tmp/tv_exceptions.txt, currently: 2,646 files that are not media or have
nothing beside them to belong to, 1,940 bonus files inside packs no provider
ever matched, 1,664 files no authority numbers, and ~450 files whose only row is
numbered nonsense (season 1989, season 0).
Rollback is the journal: media-apply.py rollback --journal /mnt/entropy/media-relayout-tv.jsonl --apply, per rename.
# Plan a TV relayout from the numbering Jellyfin already has
`/mnt/entropy/TVShows` is scene packs, not a library: release folders with
seasons buried several levels down, subtitles under `Subs/<release-name>/`, and
bonus material in nine spellings of "Extras". Jellyfin has already matched and
numbered most of it — **47,676 of its 58,551 files carry a matched, numbered
row**. This branch makes that work the authority for re-filing the library, and
refuses to guess where it is absent.
## What lands
- `scripts/media-census.py jellyfin` — export the matched rows (`file series
year season episode extra tmdb`) from the live database, opened read-only.
- `scripts/media-census.py enumerate|probe` — what is on disk, and the runtimes
the film arm needs.
- `scripts/media-shows.py` — the planner: plan TSV in the executor's own format
plus an exceptions file that is the review, not a log.
- `scripts/media-apply.py` is unchanged and does the moves: journal first,
`rollback` and `sweep` afterwards. Nothing in this branch touches the library.
- `serverAppConfigs-docs/Dankserver/Media Relayout.md` gains the section that
owns the contract and the evidence chain.
## Evidence, strongest first
1. the episode marker the file's own name states (`S01E02-E03`, `1x04`);
2. the `Season NN` folder it sits in **and the number its name leads with inside
it** — `Season 19/01 Charles Barkley, Nirvana.avi` is S19E01;
3. the provider row, for identity (series name and year) and for numbering a
file whose own name says nothing;
4. a bonus folder anywhere above the file, or Jellyfin's `ExtraType`;
5. runtime over `SHORT_MAX` → film-shaped, and it leaves for `--movies` only
when a movie provider names it.
## Two refusals, both earned on the real library
- **Folders resolve a series; they never invent one.** An early run turned
`…/03. Extra/01. NCOP/NCOP 01.mkv` into a root-level series called `01 NCOP`.
Folder text may now only match a registered name as a token run —
`(CBB) Tengen Toppa Gurren Lagann - The Complete Series (BD 1080p)` names
*Tengen Toppa Gurren Lagann* — and a bonus subfolder with no registered name
in any ancestor parks.
- **A scraped row does not outrank the filesystem.** Jellyfin numbers multi-season
packs badly: every file under `SNL 16-20/Season 16..19` carries season 16
episode 20 in the database, and one Gundam row says season 2004. The folder and
the file's own leading number win; a row that still insists on season 1989
parks its file instead of creating `Season 1989`.
Also fixed on the way: a sidecar now searches every ancestor folder for the video
it names (the `Subs/<release-name>/` layout was losing 792 subtitles), and the
shared bonus-folder test no longer reads a bare index as a title — `name_words`
drops "extras" as release junk, so `01. Extras` reduced to `01` and "matched"
the `01` of `NCOP 01`, cancelling the bonus evidence in the engine's own guard.
## Verification
- `tests/media_shows.bats`: 19 behaviors, each one output-level — where a file
lands, what parks, that a destination is never claimed twice, that re-planning
a library the plan already satisfies moves nothing.
- `./tests/run.sh`: 684 tests green.
- Dry run against the real library (read-only, `nice -n 19`): **48,757 moves,
9,680 parked, 5,799 folders, 39.02 TiB "touched"** — renames on one filesystem,
so no data moves and no space is needed. The run-time census is still
finishing, so the film arm has not had its durations yet: the 1,664 parked
long files will become films (or stay parked) on the next plan.
## What this does NOT do
Nothing is applied. `scripts/media-apply.py --apply` against the library is the
next step and belongs after Frank has read the exceptions report —
`/tmp/tv_exceptions.txt`, currently: 2,646 files that are not media or have
nothing beside them to belong to, 1,940 bonus files inside packs no provider
ever matched, 1,664 files no authority numbers, and ~450 files whose only row is
numbered nonsense (season 1989, season 0).
Rollback is the journal: `media-apply.py rollback --journal
/mnt/entropy/media-relayout-tv.jsonl --apply`, per rename.
---
cwd: /home/blank/.omp/wt/wt-20261030-163847-6d1fc1f · session: 01a18f2e-18b1-7573-bcd5-ac99636f8bcb
The Movies relayout planned from Plex; the TV library has no Plex rows and
58k files whose names lie about which episode they hold. Jellyfin has already
matched and numbered 47,676 of them, so the planner treats that numbering as
the authority and the file name as the fallback: an episode number the name
states, or a provider row, or nothing - and "nothing" parks the file under
_unsorted with a reason instead of inventing a number.
- media-census.py jellyfin: one TSV row per matched episode, its container
path mapped back to the host, series name/year/TMDb id from the Series row
(the episode row carries none of them). Both TSV writers now end lines with
\n so a shell consumer sees the last field clean.
- media-shows.py: the plan. Series folders take the provider's own spelling;
one file claiming two episodes keeps both numbers; two files claiming one
episode - the bigger keeps the standard name, the other parks; bonus
material files under the series' extras folder, never as an episode; a long
file inside the TV library leaves for Movies only when TMDb answers with a
matching title, otherwise it parks. Re-running the plan on a library it
already filed moves nothing.
- tests/media_shows.bats: 15 behaviors, including the executor preflight and
the re-plan stability law.
The first run against the real library died in the anchor lookup: a subtitle
whose own name carries the media extension matches BOTH prefix forms of its
video, and the "keep the longest" comparison read the destination slot of the
tuple instead of the length slot. The fixture only ever matched one prefix, so
the seam was green over a crash.
The tail the sidecar keeps is now stripped of that container word: Jellyfin and
Plex both read "Show S01E01.forced.srt", not "Show S01E01.mkv.forced.srt", and
an nfo still carries the media extension because that one is constructed, not
parsed.
A dry run of the TV planner against the real 58k-file library produced a root
series called "01 NCOP" out of a bonus subfolder, copied Jellyfin's stale
numbering (every file under SNL 16-20/Season 16..19 carries season 16 episode
20; one Gundam row says season 2004), and lost subtitles a scene pack had
buried in Subs/<release-name>/.
- Folders now RESOLVE a series and never invent one: a folder's words match a
registered name as a token run ("(CBB) Tengen Toppa Gurren Lagann - The
Complete Series (BD 1080p)" names Tengen Toppa Gurren Lagann), and folder
words alone name nothing, so an unknown pack's bonus folder parks instead of
opening a new show at the library root.
- Numbering priority: the marker the file's own name states, then the Season NN
folder plus the number the name leads with inside it, then the provider row.
A row that still insists on season 1989 parks its file rather than creating
Season 1989.
- The provider row keeps identity: the registered name and its year survive a
file whose own marker numbers it, and the pack index a release leads with
("4a. Seed DESTINY") is folded out of the folder name.
- A sidecar searches every ancestor folder for the video it names, not just the
parent, so Subs/<release-name>/<release>.jpn.srt follows its episode.
- The shared bonus-folder test no longer reads an index as a title: name_words
drops "extras" as release junk, so "01. Extras" reduced to "01" and matched
the "01" of "NCOP 01", cancelling the bonus evidence. Only words can name a
film.
One page owns relayout: the census commands, the order the planner believes
things in, the two refusals a dry run on the real library proved necessary, the
apply and rollback path, and the standing wart that a provider name can itself
be scene junk ("Black Clover 001", 92 episodes) — renaming that is Jellyfin's
job, not the mover's.
The first run against the real library died in the anchor lookup: a subtitle
whose own name carries the media extension matches BOTH prefix forms of its
video, and the "keep the longest" comparison read the destination slot of the
tuple instead of the length slot. The fixture only ever matched one prefix, so
the seam was green over a crash.
The tail the sidecar keeps is now stripped of that container word: Jellyfin and
Plex both read "Show S01E01.forced.srt", not "Show S01E01.mkv.forced.srt", and
an nfo still carries the media extension because that one is constructed, not
parsed.
A dry run of the TV planner against the real 58k-file library produced a root
series called "01 NCOP" out of a bonus subfolder, copied Jellyfin's stale
numbering (every file under SNL 16-20/Season 16..19 carries season 16 episode
20; one Gundam row says season 2004), and lost subtitles a scene pack had
buried in Subs/<release-name>/.
- Folders now RESOLVE a series and never invent one: a folder's words match a
registered name as a token run ("(CBB) Tengen Toppa Gurren Lagann - The
Complete Series (BD 1080p)" names Tengen Toppa Gurren Lagann), and folder
words alone name nothing, so an unknown pack's bonus folder parks instead of
opening a new show at the library root.
- Numbering priority: the marker the file's own name states, then the Season NN
folder plus the number the name leads with inside it, then the provider row.
A row that still insists on season 1989 parks its file rather than creating
Season 1989.
- The provider row keeps identity: the registered name and its year survive a
file whose own marker numbers it, and the pack index a release leads with
("4a. Seed DESTINY") is folded out of the folder name.
- A sidecar searches every ancestor folder for the video it names, not just the
parent, so Subs/<release-name>/<release>.jpn.srt follows its episode.
- The shared bonus-folder test no longer reads an index as a title: name_words
drops "extras" as release junk, so "01. Extras" reduced to "01" and matched
the "01" of "NCOP 01", cancelling the bonus evidence. Only words can name a
film.
One page owns relayout: the census commands, the order the planner believes
things in, the two refusals a dry run on the real library proved necessary, the
apply and rollback path, and the standing wart that a provider name can itself
be scene junk ("Black Clover 001", 92 episodes) — renaming that is Jellyfin's
job, not the mover's.
dank
merged commit 82f6ec55c2 into main2026-10-30 23:38:36 -07:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Plan a TV relayout from the numbering Jellyfin already has
/mnt/entropy/TVShowsis scene packs, not a library: release folders withseasons buried several levels down, subtitles under
Subs/<release-name>/, andbonus material in nine spellings of "Extras". Jellyfin has already matched and
numbered most of it — 47,676 of its 58,551 files carry a matched, numbered
row. This branch makes that work the authority for re-filing the library, and
refuses to guess where it is absent.
What lands
scripts/media-census.py jellyfin— export the matched rows (file series year season episode extra tmdb) from the live database, opened read-only.scripts/media-census.py enumerate|probe— what is on disk, and the runtimesthe film arm needs.
scripts/media-shows.py— the planner: plan TSV in the executor's own formatplus an exceptions file that is the review, not a log.
scripts/media-apply.pyis unchanged and does the moves: journal first,rollbackandsweepafterwards. Nothing in this branch touches the library.serverAppConfigs-docs/Dankserver/Media Relayout.mdgains the section thatowns the contract and the evidence chain.
Evidence, strongest first
S01E02-E03,1x04);Season NNfolder it sits in and the number its name leads with insideit —
Season 19/01 Charles Barkley, Nirvana.aviis S19E01;file whose own name says nothing;
ExtraType;SHORT_MAX→ film-shaped, and it leaves for--moviesonlywhen a movie provider names it.
Two refusals, both earned on the real library
…/03. Extra/01. NCOP/NCOP 01.mkvinto a root-level series called01 NCOP.Folder text may now only match a registered name as a token run —
(CBB) Tengen Toppa Gurren Lagann - The Complete Series (BD 1080p)namesTengen Toppa Gurren Lagann — and a bonus subfolder with no registered name
in any ancestor parks.
packs badly: every file under
SNL 16-20/Season 16..19carries season 16episode 20 in the database, and one Gundam row says season 2004. The folder and
the file's own leading number win; a row that still insists on season 1989
parks its file instead of creating
Season 1989.Also fixed on the way: a sidecar now searches every ancestor folder for the video
it names (the
Subs/<release-name>/layout was losing 792 subtitles), and theshared bonus-folder test no longer reads a bare index as a title —
name_wordsdrops "extras" as release junk, so
01. Extrasreduced to01and "matched"the
01ofNCOP 01, cancelling the bonus evidence in the engine's own guard.Verification
tests/media_shows.bats: 19 behaviors, each one output-level — where a filelands, what parks, that a destination is never claimed twice, that re-planning
a library the plan already satisfies moves nothing.
./tests/run.sh: 684 tests green.nice -n 19): 48,757 moves,9,680 parked, 5,799 folders, 39.02 TiB "touched" — renames on one filesystem,
so no data moves and no space is needed. The run-time census is still
finishing, so the film arm has not had its durations yet: the 1,664 parked
long files will become films (or stay parked) on the next plan.
What this does NOT do
Nothing is applied.
scripts/media-apply.py --applyagainst the library is thenext step and belongs after Frank has read the exceptions report —
/tmp/tv_exceptions.txt, currently: 2,646 files that are not media or havenothing beside them to belong to, 1,940 bonus files inside packs no provider
ever matched, 1,664 files no authority numbers, and ~450 files whose only row is
numbered nonsense (season 1989, season 0).
Rollback is the journal:
media-apply.py rollback --journal /mnt/entropy/media-relayout-tv.jsonl --apply, per rename.cwd: /home/blank/.omp/wt/wt-20261030-163847-6d1fc1f · session: 01a18f2e-18b1-7573-bcd5-ac99636f8bcb
The Movies relayout planned from Plex; the TV library has no Plex rows and 58k files whose names lie about which episode they hold. Jellyfin has already matched and numbered 47,676 of them, so the planner treats that numbering as the authority and the file name as the fallback: an episode number the name states, or a provider row, or nothing - and "nothing" parks the file under _unsorted with a reason instead of inventing a number. - media-census.py jellyfin: one TSV row per matched episode, its container path mapped back to the host, series name/year/TMDb id from the Series row (the episode row carries none of them). Both TSV writers now end lines with \n so a shell consumer sees the last field clean. - media-shows.py: the plan. Series folders take the provider's own spelling; one file claiming two episodes keeps both numbers; two files claiming one episode - the bigger keeps the standard name, the other parks; bonus material files under the series' extras folder, never as an episode; a long file inside the TV library leaves for Movies only when TMDb answers with a matching title, otherwise it parks. Re-running the plan on a library it already filed moves nothing. - tests/media_shows.bats: 15 behaviors, including the executor preflight and the re-plan stability law.A dry run of the TV planner against the real 58k-file library produced a root series called "01 NCOP" out of a bonus subfolder, copied Jellyfin's stale numbering (every file under SNL 16-20/Season 16..19 carries season 16 episode 20; one Gundam row says season 2004), and lost subtitles a scene pack had buried in Subs/<release-name>/. - Folders now RESOLVE a series and never invent one: a folder's words match a registered name as a token run ("(CBB) Tengen Toppa Gurren Lagann - The Complete Series (BD 1080p)" names Tengen Toppa Gurren Lagann), and folder words alone name nothing, so an unknown pack's bonus folder parks instead of opening a new show at the library root. - Numbering priority: the marker the file's own name states, then the Season NN folder plus the number the name leads with inside it, then the provider row. A row that still insists on season 1989 parks its file rather than creating Season 1989. - The provider row keeps identity: the registered name and its year survive a file whose own marker numbers it, and the pack index a release leads with ("4a. Seed DESTINY") is folded out of the folder name. - A sidecar searches every ancestor folder for the video it names, not just the parent, so Subs/<release-name>/<release>.jpn.srt follows its episode. - The shared bonus-folder test no longer reads an index as a title: name_words drops "extras" as release junk, so "01. Extras" reduced to "01" and matched the "01" of "NCOP 01", cancelling the bonus evidence. Only words can name a film.One page owns relayout: the census commands, the order the planner believes things in, the two refusals a dry run on the real library proved necessary, the apply and rollback path, and the standing wart that a provider name can itself be scene junk ("Black Clover 001", 92 episodes) — renaming that is Jellyfin's job, not the mover's.A dry run of the TV planner against the real 58k-file library produced a root series called "01 NCOP" out of a bonus subfolder, copied Jellyfin's stale numbering (every file under SNL 16-20/Season 16..19 carries season 16 episode 20; one Gundam row says season 2004), and lost subtitles a scene pack had buried in Subs/<release-name>/. - Folders now RESOLVE a series and never invent one: a folder's words match a registered name as a token run ("(CBB) Tengen Toppa Gurren Lagann - The Complete Series (BD 1080p)" names Tengen Toppa Gurren Lagann), and folder words alone name nothing, so an unknown pack's bonus folder parks instead of opening a new show at the library root. - Numbering priority: the marker the file's own name states, then the Season NN folder plus the number the name leads with inside it, then the provider row. A row that still insists on season 1989 parks its file rather than creating Season 1989. - The provider row keeps identity: the registered name and its year survive a file whose own marker numbers it, and the pack index a release leads with ("4a. Seed DESTINY") is folded out of the folder name. - A sidecar searches every ancestor folder for the video it names, not just the parent, so Subs/<release-name>/<release>.jpn.srt follows its episode. - The shared bonus-folder test no longer reads an index as a title: name_words drops "extras" as release junk, so "01. Extras" reduced to "01" and matched the "01" of "NCOP 01", cancelling the bonus evidence. Only words can name a film.One page owns relayout: the census commands, the order the planner believes things in, the two refusals a dry run on the real library proved necessary, the apply and rollback path, and the standing wart that a provider name can itself be scene junk ("Black Clover 001", 92 episodes) — renaming that is Jellyfin's job, not the mover's.