# `src/core/tmdb.py` TMDb (The Movie Database) client — Curator's identity source. Replaces ČSFD. Its only job is to turn a **TMDb id** (or a title/year search) into a canonical **title + year** for naming the pool file. The rich metadata and artwork are fetched by **Jellyfin itself** — Curator does not need them here. Needs a free API key in `TMDB_API_KEY` (loaded from `.env`). Everything degrades gracefully when the key or the network is missing: `api_available` reports readiness and the lookups raise `TmdbError` with a clear message. Source: [`src/core/tmdb.py`](../../src/core/tmdb.py) ## Classes ### `TmdbResult` *class · line 29* ```python class TmdbResult: ``` A resolved TMDb entry — just enough to name the pool file. ### `TmdbDetails` *class · line 39* ```python class TmdbDetails: ``` Full TMDb data used to (re)generate a movie's tags (genres etc.). Exposes `field_values` so it plugs into the tag schema the same way the NFO reader does (fields: genres / countries / year / rating). #### `TmdbDetails.field_values` *method · line 53* ```python field_values(name: str) -> list[str] ``` The values of one tag source field (`genres`, `countries`, `year`, `rating`, …) as a list of strings, ready to become tags. Unknown field names return an empty list. ### `TmdbError` *class · line 65* ```python class TmdbError(RuntimeError): ``` A TMDb request could not be completed (no key, network, bad status). ## Functions ### `api_key` *function · line 69* ```python api_key() -> Optional[str] ``` The configured TMDb API key, or None. ### `api_available` *function · line 75* ```python api_available() -> bool ``` True when a TMDb API key is configured. ### `_get` *function · line 80* ```python _get(path: str, params: dict) -> dict ``` GET a TMDb API path with the configured key and language. Raises `TmdbError` on a missing key, a network failure or an error response. ### `_year_of` *function · line 98* ```python _year_of(date_str: Optional[str]) -> Optional[str] ``` The four-digit year at the start of a TMDb date (`YYYY-MM-DD`), or `None`. ### `lookup_movie` *function · line 104* ```python lookup_movie(tmdb_id: int) -> Optional[TmdbResult] ``` Resolve a movie by its TMDb id → title + year, or None if it has no title. ### `movie_details` *function · line 113* ```python movie_details(tmdb_id: int) -> TmdbDetails ``` Full movie data from TMDb (genres/countries/rating/year), localized to cs. ### `lookup_tv` *function · line 127* ```python lookup_tv(tmdb_id: int) -> Optional[TmdbResult] ``` Resolve a series by its TMDb id → name + first-air year, or None. ### `lookup` *function · line 136* ```python lookup(tmdb_id: int, kind: str='movie') -> Optional[TmdbResult] ``` Resolve a TMDb id as a movie (default) or a series (`kind="tv"`). ### `search_movie` *function · line 141* ```python search_movie(query: str, year: Optional[str]=None, limit: int=5) -> list[TmdbResult] ``` Search movies by title (optionally narrowed by year); best matches first. ### `search_tv` *function · line 161* ```python search_tv(query: str, year: Optional[str]=None, limit: int=5) -> list[TmdbResult] ``` Search series by name (optionally narrowed by first-air year).