# `src/core/file.py` The `File` class: one playable movie file as the UI sees it. A `File` is a *view* onto one media entry of a movie record in the pool index — metadata (title, tags, ČSFD link, attributes, date) lives on the shared record, so every version of a film reads the same values. See `docs/architecture.md`. Source: [`src/core/file.py`](../../src/core/file.py) ## Classes ### `File` *class · line 5* ```python class File: ``` One movie file in the pool, as the UI sees it. Holds the path, the list of tags and the metadata accessors; metadata itself is stored on the movie record in the pool index and the `File` reads it through it. #### `File.__init__` *method · line 6* ```python __init__(file_path: Path, tagmanager=None, index=None) -> None ``` Create a file object for `file_path`. Metadata is loaded from the pool index when `index` is given; without an index the object is in-memory only. #### `File._identity_from_path` *method · line 41* ```python _identity_from_path() -> tuple[str, str, str | None, int | None, str] ``` `(key, title, year, tmdb_id, label)` implied by this file's location. A file inside its own `Title (rok) [tmdbid]` folder is one version of that movie — identity comes from the **folder**, and the rest of its own stem is the version label. A flat file carries both in its own name. #### `File.get_metadata` *method · line 67* ```python get_metadata() -> None ``` Load this file's metadata from the movie record that owns it. Since the pool index became identity-keyed (see `src.core.movie`), a File is a *view* on one media entry of a movie record — every version of the same film therefore reads the same title/tags/ČSFD/… A file the index doesn't know yet joins the movie of the same identity when there is one (that's how a newly added version inherits the shared metadata instead of blanking it), otherwise it starts a new record. #### `File._init_new_metadata` *method · line 95* ```python _init_new_metadata() -> None ``` Reset all metadata fields to their defaults for a file the index doesn't know yet. #### `File._build_record` *method · line 107* ```python _build_record() -> dict ``` Serialise this file's metadata into the dictionary stored in the pool index (tags as full paths, auto-derived tags, date, title, ČSFD link, …). #### `File._apply_record` *method · line 126* ```python _apply_record(data: dict) -> None ``` Load metadata from an index record dictionary into this object's fields (the inverse of `_build_record`). Missing keys fall back to defaults. #### `File.save_metadata` *method · line 152* ```python save_metadata() ``` Persist metadata into this file's movie record (no-op without index). Writes the shared fields onto the movie record and makes sure the record lists this file among its media. A file the index has never seen starts a new record under its own identity key. #### `File._library_name` *method · line 182* ```python _library_name() -> str ``` Top-level pool folder this file sits in (its library), or `""`. #### `File.added_timestamp` *method · line 190* ```python added_timestamp() -> float ``` Epoch seconds for 'date added' — the stored `added` or the file mtime. Used to order the "recently added" folder (newer = larger). The fallback is **mtime**, not ctime: creating the Filmotéka hardlinks bumps the source inode's ctime, which would make ctime-based ordering meaningless, whereas mtime (preserved from the source on import) stays stable. #### `File.name_context` *method · line 209* ```python name_context() -> dict ``` Fields for a miniDLNA filename template (see config tag schema). Provides title / year / rating / ext / stem / filename from the movie's metadata (year & rating come from the NFO cache, year falling back to a `Rok` tag, then the canonical filename). Missing values render empty. #### `File.set_attribute` *method · line 242* ```python set_attribute(key: str, value: str | None) -> None ``` Set a free-form attribute (e.g. 'collection_sort'); None/'' removes it. #### `File.delete_metadata` *method · line 253* ```python delete_metadata() -> None ``` Drop this file from its movie record; the last one takes the record. Removing one version of a multi-version movie leaves the movie (and its metadata) in place — only when its last media entry goes does the whole record go with it. #### `File.relocate` *method · line 273* ```python relocate(new_path: Path) -> None ``` Point this File at a new path, moving its media entry along. The physical file must already have been moved/renamed by the caller; this only repoints the movie record's media entry (and the File), so a rename never detaches a file from its movie. #### `File.set_date` *method · line 294* ```python set_date(date_str: str | None) ``` Set the date the movie was added (`YYYY-MM-DD`) or clear it with `None` / an empty string, then save the metadata. #### `File.apply_nfo` *method · line 303* ```python apply_nfo(nfo, schema: list[dict] | None=None) -> dict ``` Regenerate the auto (NFO-derived) tags from the movie's NFO. Reads genres/year/countries/rating from `nfo` (`nfo.NfoData`) per the tag schema's source fields and (re)creates those tags; user-added tags are kept. Also caches year/rating (for folder grouping) and fills the title when missing. `nfo` of `None` (no NFO yet) is a no-op. Returns: dict with 'success' and 'tags_added'. #### `File.add_tag` *method · line 347* ```python add_tag(tag) ``` Attach a tag to this file. Accepts a `Tag` or a `category/name` string; a string without a category goes to the `default` category. Saves on change. #### `File.remove_tag` *method · line 364* ```python remove_tag(tag) ``` Detach a tag, given as a `Tag` or a `category/name` string. Saves on change.