annie.app_state

The composition root: the one place that wires the backend together for the UI.

It sits above every package: it builds the source registry, the scan, the review store and the background services (rendering, conversion, previews) from annie.dataset, annie.media and annie.parsers, and the UI (annie.pages, app.py) reaches them through state. Nothing below it imports it.

Holds the configured SourceRegistry, the cached scan manifest (Browse/Annotator are pure consumers of it), the review store, the render service, and session-only UI settings (row heights). Adding or removing a source re-runs the scan in place, so there is no Scan button.

Sources are session-only: the registry is seeded from the ANNIE_* environment variables on startup and otherwise lives for the process lifetime. Curation (verdicts, notes, annotator selection) and protagonist corrections persist independently in SQLite / the _manual CSV.

Attributes

state

The single shared state instance.

Classes

UiSettings

Session-only UI preferences set on the Settings tab.

AppState

Mutable application state shared between tabs.

Functions

seed_registry(→ annie.dataset.sources.SourceRegistry)

Build the initial registry from the ANNIE_* environment variables.

Module Contents

class annie.app_state.UiSettings[source]

Session-only UI preferences set on the Settings tab.

browse_row_height

Media height (px) of a Browse row’s thumbnail/strip/render.

annotator_row_height

Max media height (px) of an Annotator row; its boxes flex to share the row width and only hit this cap on very wide screens.

auto_scroll

Whether reaching the bottom of Browse / Annotator reveals the next page automatically, instead of waiting for a “Show more” click.

page_size

How many rows one page reveals, whether auto-scrolled or clicked.

embed_ttl_seconds

How long an embedded clip stays on a row before it reverts to its placeholder, freeing the memory the browser holds for it.

unload_after_seconds

How long a row may sit off screen before its preview frames are dropped; they are decoded again when it scrolls back.

grid_thumb_height

Media height (px) of a Browse grid box (Quick selection view); its width is derived 16:9.

grid_page_size

How many grid boxes one page reveals — larger than page_size because a grid box is a single cheap frame.

grid_unload_after_seconds

Off-screen TTL for grid boxes; shorter than unload_after_seconds since the grid packs many videos on screen.

annie.app_state.seed_registry() → annie.dataset.sources.SourceRegistry[source]

Build the initial registry from the ANNIE_* environment variables.

class annie.app_state.AppState[source]

Mutable application state shared between tabs.

registry

The configured data sources (the dataset definition).

scan

The most recent scan result, recomputed on every source change.

store

The SQLite review-status store.

renderer

The render-job service.

converter

The audio/video re-encode batch runner.

audio_cache

Probed audio-stream presence per video id (lazy; see Browse).

frames_cache

Decoded frame count per video id (lazy; see Browse).

ui

Session-only UI preferences.

active_config

The dataset config file currently loaded, or None for the env-seeded / blank dataset. Lets the Dataset tab show it as selected.

scanned_tracks

Each video’s protagonist as scanned (the heuristic CSV), before the review DB’s corrections are layered over it; lets a DB switch start over.

previews

The shared preview loader (bounded, newest-first, cached decoding).

scanning

Whether a scan is running right now (start-up scan included), so every page can show it as busy.

restore_last_config() → pathlib.Path | None[source]

Reopen the config remembered from the previous run, with its review database.

This is what lets a user close Annie and, on the next start, land straight back in their dataset with all their progress — no need to re-pick the config. A config that has gone missing or fails to load is skipped (and logged), leaving the current dataset in place.

Returns:

The config path that was restored, or None if nothing was.

rescan() → None[source]

Rebuild the manifest from the current registry (after a source change).

Also clears the audio and frame-count caches so that any replaced or renamed video files are re-probed on the next Browse render.

set_store(db_path: pathlib.Path) → None[source]

Replace the active review store with one backed by db_path.

The file is created (with the schema applied) if it does not exist yet. Call this whenever the user changes the persistence target — either by loading a config that embeds a "db" path, or by choosing a DB file in the Persistence block on the Dataset tab.

The new DB’s protagonist corrections replace the previous DB’s on the scanned videos straight away, instead of only after the next rescan or restart.

Parameters:

db_path – Absolute path to the SQLite file to open.

review_lookup() → collections.abc.Callable[[str], annie.dataset.filtering.ReviewState][source]

Read every review state in one query and return a per-key lookup.

For a pass over many videos (e.g. the Browse filter); the lookup answers exactly like review_state() but from a snapshot taken now.

Returns:

A function mapping a video key to its ReviewState.

review_state(key: str) → annie.dataset.filtering.ReviewState[source]

Return the filtering-facing review state for a video (default liked).

Parameters:

key – The video key.

Returns:

A ReviewState; videos with no stored row are liked (good) with no note and not queued for the Annotator.

annie.app_state.state

The single shared state instance.

The initial scan is deferred to app startup (see annie.app) so imports stay fast.