Files

228 lines
5.7 KiB
Markdown

# `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.