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
+62
View File
@@ -0,0 +1,62 @@
"""Pool file naming convention.
Every movie in the pool is named ``Title (YYYY).ext`` — a title followed by a
four-digit year in parentheses. The year lets two films of the same name live
side by side and makes the filename self-describing (the year can be recovered
without any metadata). These helpers build, validate and parse that stem (the
filename without its extension).
"""
import re
# A trailing four-digit year in parentheses. The title is non-greedy so a title
# that itself contains parentheses keeps them: "Já, robot (2004)" but also
# "Kurz (special) (2019)" → title "Kurz (special)", year 2019.
_POOL_STEM_RE = re.compile(r"^(?P<title>.+?) \((?P<year>\d{4})\)$")
_FOUR_DIGITS = re.compile(r"\d{4}")
def is_valid_year(year: object) -> bool:
"""True when ``year`` is (or stringifies to) exactly four digits."""
return bool(re.fullmatch(r"\d{4}", str(year).strip()))
def canonical_pool_stem(title: str, year: object) -> str:
"""Build the canonical pool stem ``Title (YYYY)``.
Raises:
ValueError: the title is empty or the year is not four digits.
"""
title = (title or "").strip()
year_s = str(year).strip()
if not title:
raise ValueError("Název filmu nesmí být prázdný.")
if not re.fullmatch(r"\d{4}", year_s):
raise ValueError(f"Rok musí být čtyřmístné číslo, ne „{year}“.")
return f"{title} ({year_s})"
def parse_pool_stem(stem: str) -> tuple[str, int] | None:
"""Split a canonical stem into ``(title, year)``; ``None`` if it isn't one."""
match = _POOL_STEM_RE.match((stem or "").strip())
if not match:
return None
return match.group("title").strip(), int(match.group("year"))
def is_canonical_pool_stem(stem: str) -> bool:
"""True when ``stem`` matches the ``Title (YYYY)`` convention."""
return _POOL_STEM_RE.match((stem or "").strip()) is not None
def year_from_filename(name: str) -> str | None:
"""Best-effort four-digit year guessed from a raw (release) filename.
Prefers a parenthesised year (``… (1999) …``) and otherwise falls back to the
last standalone 19xx/20xx run. Used only to pre-fill the import dialog — the
user confirms it. Returns the year as a string, or ``None``.
"""
paren = re.search(r"\((19\d{2}|20\d{2})\)", name)
if paren:
return paren.group(1)
loose = re.findall(r"(?<!\d)(19\d{2}|20\d{2})(?!\d)", name)
return loose[-1] if loose else None