4.0 KiB
src/core/pool_index.py
Unified metadata index for the Curator pool.
Instead of one sidecar file per movie, the whole pool keeps a single JSON index
at <pool>/.Curator.!index. Curator owns the pool (it inserts/removes files
itself), so files never move behind its back and a central index is safe.
The index also carries library-level settings (tag_schema,
copyasis_folders) under a settings section, so everything describing a
particular pool travels with the pool. The global config keeps only app data
(window state, MRU) and the pointers to where the pool/output live.
On-disk shape (v2)::
{"version": 2,
"settings": {...},
"movies": {"tmdb-603": {"title": …, "media": [{"role", "label", "file"}, …]}}}
Records are keyed by the movie's identity (tmdb-<id>, or a title/year
slug when there's no id) and own their files — see src.core.movie. The
original v1 shape keyed a record by one file's pool-relative path, which
made metadata a passenger on that file; PoolIndex.load migrates such an
index in place (backing the old file up first). Migration only rewrites
metadata — no file on disk is moved, because a one-video movie is already in
its v2 position.
Source: src/core/pool_index.py
Classes
PoolIndex
class · line 35
class PoolIndex:
Single-file JSON metadata store for all files in a pool.
PoolIndex.__init__
method · line 38
__init__(pool_dir: Path) -> None
Open the index of the pool at pool_dir (loads it, migrating an older version if needed).
PoolIndex._key
method · line 45
_key(file_path: Path) -> str
Pool-relative POSIX key for a file path.
PoolIndex.load
method · line 53
load() -> None
Load the index from disk (missing/corrupt index = empty).
A v1 (path-keyed) index is migrated to v2 in place — the old file is
copied to .Curator.!index.v1.bak first.
PoolIndex._migrate_v1_to_v2
method · line 76
_migrate_v1_to_v2() -> None
Re-key path-keyed records into identity-keyed movie records.
Each v1 record described one file; several of them can describe one movie (the interim multi-version layout put them in a shared folder), so they are merged by identity. Metadata only — nothing is moved on disk, since a v1 movie's files already sit where v2 wants them.
PoolIndex.save
method · line 139
save() -> None
Persist the index to disk.
PoolIndex.get_setting
method · line 150
get_setting(key: str, default=None)
Return a library-level setting stored in the index.
PoolIndex.set_setting
method · line 154
set_setting(key: str, value) -> None
Upsert a library-level setting and persist the index.
PoolIndex.get_movie
method · line 163
get_movie(key: str) -> dict | None
Return the movie record under key, or None.
PoolIndex.set_movie
method · line 167
set_movie(key: str, data: dict) -> None
Upsert a movie record and persist the index.
PoolIndex.delete_movie
method · line 172
delete_movie(key: str) -> None
Remove a movie record (if present) and persist the index.
PoolIndex.rekey_movie
method · line 177
rekey_movie(old_key: str, new_key: str) -> None
Move a record to a new identity key (e.g. its TMDb id was set/fixed).
PoolIndex.all_movies
method · line 184
all_movies() -> dict[str, dict]
Every movie record, keyed by identity.
PoolIndex.record_for
method · line 188
record_for(file_path: Path) -> dict | None
The movie record that owns file_path, or None if untracked.
PoolIndex.find_movie_by_media
method · line 193
find_movie_by_media(file_path: Path) -> tuple[str, dict] | None
(key, record) of the movie owning file_path, or None.
The reverse lookup a file needs now that records are keyed by identity rather than by path.