fix(media): the review pile is not a series, and a folder carries the year once

Two destination defects the first tvdb-grade plan exposed in its own output —
both visible by reading the plan's folder names, neither caught by any gate.

1. Jellyfin sanitizes a hidden folder's display name: `_unsorted` comes back as
   `unsorted`. The park-echo guard compared the row's series against the folder
   with the underscore, so 1,091 pile rows survived as a real series and the plan
   renamed 617 files out of the pile into a VISIBLE folder named `unsorted` —
   inventing the junk show the guard exists to prevent. The comparison now strips
   leading underscores from both sides.

2. TVDb hands back some series with the year already on the name (`Acapulco
   (2021)`). label_of appended the year anyway, producing `Acapulco (2021)
   (2021)` — a folder no matcher and no human reaches for twice. A name that
   already ends in `(YYYY)` is left alone.

Both are covered by fixtures: a pile row whose series is the sanitized spelling
must park, never file under the pile's name; a provider name carrying its year
produces one year in the path and the plan contains no `(YYYY) (YYYY)` anywhere.
This commit is contained in:
Frank committed 2026-10-31 07:27:47 -07:00
1 parent 32b58dd787
commit 6d03bbc8e7
2 files changed
+39 -5

No files matched your search

+12 -5
View File
@@ -428,10 +428,13 @@ held = {r["path"]: r for r in rows}
def row_names_the_park(path, name):
"""The library's own review pile is not a show. When the park sat INSIDE the
library the server indexed the whole folder as one series named after it, and
a row like that would rename a real show to `_unsorted` — so a row whose
series is the hidden top-level folder the file itself sits in is dropped."""
a row like that would rename a real show to the pile — so a row whose series is
the hidden top-level folder the file itself sits in is dropped. The server also
sanitizes the display name, dropping the leading underscore, so `unsorted` and
`_unsorted` are the same pile: compare them without their leading punctuation,
or the pile survives as a visible series folder."""
top = rel(path).split("/")[0]
return top.startswith("_") and eng.norm(name) == eng.norm(top)
return top.startswith("_") and eng.norm(name.lstrip("_")) == eng.norm(top.lstrip("_"))
def in_review_pile(path):
@@ -687,10 +690,14 @@ def series_key(name):
def label_of(s):
"""`<Series> (<year>)`, the form both matchers read."""
"""`<Series> (<year>)`, the form both matchers read. A provider's name can
arrive WITH the year already on it — TVDb hands back `Acapulco (2021)` for the
reboot — and appending a second one names a folder nothing will match again."""
nm, yr = identity(s)
nm = clean(nm)
return f"{nm} ({yr})" if yr else nm
if not yr or re.search(r"\(\d{4}\)\s*$", nm):
return nm
return f"{nm} ({yr})"
def episode_title(r, s, season, ep):