Adopt "Title (YYYY)" pool naming and clean Filmotéka link names

This commit is contained in:
2026-07-27 20:51:31 +02:00
parent 4c4180f28c
commit 1c78ca9013
13 changed files with 784 additions and 145 deletions
+28 -7
View File
@@ -98,8 +98,17 @@ movie table, and one-click Filmotéka generation.
Filmotéka output, with the files materialized as **hardlinks** into the pool.
So `pool/Seriály/...` is cloned 1:1 into `output/Seriály/...` (same structure,
hardlinked files). This is how Seriály work.
- **File naming:** imported movies are renamed to **`Title.ext`** (no year in the
filename; year lives in metadata/tags).
- **File naming:** pooled movies follow the convention **`Title (YYYY).ext`** — a
clean title plus a four-digit year in parentheses (`naming.py`:
`canonical_pool_stem` / `parse_pool_stem`). The year lets two same-named films
coexist and makes the filename self-describing (`File.name_context` recovers
the year from the filename when no ČSFD/tag year is present). The GUI **import
requires a four-digit year** (per-row *Rok* field, pre-filled from the source
filename and fillable from ČSFD — a ČSFD-suggested year is tinted blue to be
verified, a name colliding with the pool is tinted red). *Filmy → "Přejmenovat
dle ČSFD (rok)…"* (`FileManager.rename_all_to_canonical`) brings older
`Title.ext` files up to the convention from their ČSFD metadata; files without
a known year are skipped. `File.title` always stays the clean title (no year).
- **Import copy vs move:** by default the original file is **copied** into the
pool (non-destructive); the import dialog also offers a **move** option that
relocates the source into the pool instead.
@@ -122,11 +131,20 @@ movie table, and one-click Filmotéka generation.
The `transform` (e.g. `decade_band`) shapes only the **folder name** — tags keep
the **exact value** (rating → tag `Hodnocení/90`, folder `Dle hodnocení/90100 %`);
it is applied at Filmotéka generation via `filmoteka_category_transforms`.
- **Per-category filename template** (`filename_template` in a schema entry): the
hardlink name **inside that category's folders only** is rendered from the
movie's metadata (`File.name_context`: title/year/rating/ext/stem/filename plus
any free-form attributes), e.g. a Kolekce with `"{collection_sort} - {title}{ext}"`.
Other folders and the pool file keep the plain name; applied via
- **Filmotéka link naming (clean title, year on collision):** the default
hardlink name in the tag tree is the movie's **clean title**`Title.ext`,
*not* the pooled `Title (YYYY).ext`. When two different films would collide on
that name **within one folder**, the colliding ones keep the disambiguating
**year** (`Title (YYYY).ext`); a residual same-title-and-year clash gets a
stable numeric suffix. `HardlinkManager._plan_links` resolves the whole tag
tree to a collision-free `(file, path)` plan that **both** link creation and
obsolete-detection consume, so they can never disagree on a name (the previous
churn source). Copy-as-is mirrors (Seriály) are unaffected — they mirror 1:1.
- **Per-category filename template** (`filename_template` in a schema entry):
overrides the default naming **inside that category's folders only**, rendered
from the movie's metadata (`File.name_context`: title/year/rating/ext/stem/
filename plus any free-form attributes), e.g. a Kolekce with
`"{collection_sort} - {title}{ext}"`. Applied via
`filmoteka_category_filename_templates`.
- **Free-form per-movie attributes** (`File.attributes`, set in the GUI): arbitrary
`key → value` metadata stored in the index and merged into `name_context`, so
@@ -152,6 +170,9 @@ movie table, and one-click Filmotéka generation.
## Done
- Pool naming convention `Title (YYYY).ext` (`naming.py`): year required at
import (per-row Rok field, blue = ČSFD-suggested, red = pool collision), plus
"Přejmenovat dle ČSFD (rok)" to bring older files up to the convention
- Video integrity check (`integrity.py`, Testy → "Kontrola integrity videa"):
FFmpeg-based scan for corrupted/unreadable video data, deep (full decode) or
quick (ffprobe), over selected movies or the whole pool