# `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 `/.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-`, 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`](../../src/core/pool_index.py) ## Classes ### `PoolIndex` *class · line 35* ```python class PoolIndex: ``` Single-file JSON metadata store for all files in a pool. #### `PoolIndex.__init__` *method · line 38* ```python __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* ```python _key(file_path: Path) -> str ``` Pool-relative POSIX key for a file path. #### `PoolIndex.load` *method · line 53* ```python 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* ```python _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* ```python save() -> None ``` Persist the index to disk. #### `PoolIndex.get_setting` *method · line 150* ```python get_setting(key: str, default=None) ``` Return a library-level setting stored in the index. #### `PoolIndex.set_setting` *method · line 154* ```python set_setting(key: str, value) -> None ``` Upsert a library-level setting and persist the index. #### `PoolIndex.get_movie` *method · line 163* ```python get_movie(key: str) -> dict | None ``` Return the movie record under `key`, or None. #### `PoolIndex.set_movie` *method · line 167* ```python set_movie(key: str, data: dict) -> None ``` Upsert a movie record and persist the index. #### `PoolIndex.delete_movie` *method · line 172* ```python delete_movie(key: str) -> None ``` Remove a movie record (if present) and persist the index. #### `PoolIndex.rekey_movie` *method · line 177* ```python 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* ```python all_movies() -> dict[str, dict] ``` Every movie record, keyed by identity. #### `PoolIndex.record_for` *method · line 188* ```python 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* ```python 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.