# `src/core/naming.py` Pool file naming convention. Every movie in the pool is named `Title (YYYY) [tmdbid-N].ext` — a title, a four-digit year in parentheses, and (when known) the TMDb id in brackets, which is exactly the form Jellyfin matches on. The `[tmdbid-N]` part is optional: a plain `Title (YYYY)` is still valid (Jellyfin then matches by name). The year lets two same-named films coexist and makes the filename self-describing. A 3D movie additionally carries a `.3D.` tag right before the extension (Jellyfin's own convention — https://jellyfin.org/docs/general/server/media/movies/): `Title (YYYY) [tmdbid-N].3D.HSBS.ext`. `FORMAT` is one of `THREE_D_FORMATS`; Jellyfin reads it case-insensitively but Curator always writes it upper-case for a single canonical form. These helpers build, validate and parse the stem (the filename without its extension). Source: [`src/core/naming.py`](../../src/core/naming.py) ## Functions ### `is_valid_year` *function · line 35* ```python is_valid_year(year: object) -> bool ``` True when `year` is (or stringifies to) exactly four digits. ### `canonical_pool_stem` *function · line 40* ```python canonical_pool_stem(title: str, year: object, tmdb_id: object=None, format_3d: object=None) -> str ``` Build the canonical pool stem `Title (YYYY)` (+ ` [tmdbid-N]` / `.3D.` if given). Raises: ValueError: the title is empty, the year is not four digits, a given `tmdb_id` is not a positive integer, or `format_3d` isn't one of `THREE_D_FORMATS`. ### `parse_pool_stem` *function · line 73* ```python parse_pool_stem(stem: str) -> tuple[str, int] | None ``` Split a canonical stem into `(title, year)`; `None` if it isn't one. A trailing `[tmdbid-N]` is tolerated and dropped (use `parse_tmdb_id` to read it), so the returned title is always the clean title. ### `parse_tmdb_id` *function · line 85* ```python parse_tmdb_id(stem: str) -> int | None ``` Read the `[tmdbid-N]` from a canonical stem, or `None` if absent. ### `parse_3d_format` *function · line 93* ```python parse_3d_format(stem: str) -> str | None ``` Read the `.3D.` tag from a canonical stem (upper-cased), or `None` if absent. ### `is_canonical_pool_stem` *function · line 102* ```python is_canonical_pool_stem(stem: str) -> bool ``` True when `stem` matches the `Title (YYYY)` convention. ### `year_from_filename` *function · line 107* ```python 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`. ### `three_d_format_from_filename` *function · line 129* ```python three_d_format_from_filename(name: str) -> str | None ``` Best-effort 3D format guessed from a raw (release) filename, e.g. `Avatar.2009.3D.HSBS.BluRay.mkv` → `"HSBS"`. Unlike `parse_3d_format` this doesn't require the rest of the name to be a canonical pool stem — used to pre-fill a version label while importing. Returns `None` if absent.