# Architecture

## Architecture Goals

- Keep the tool small, local, and easy to reason about.
- Separate media inspection, stored normalization rules, and conversion execution clearly enough that users can inspect and adjust behavior.
- Favor explicit local state and deterministic rule application over opaque automation.
- Make external runtime dependencies and platform assumptions visible.

## System Context

- Primary actors:
  - Local operator running the CLI.
  - Local operator using the Textual TUI to inspect files and maintain rules.
- External systems:
  - `ffprobe` for media introspection.
  - `ffmpeg` for conversion and extraction.
  - TMDB API for optional show and episode metadata.
  - Local filesystem for source media, generated outputs, subtitles, logs, config, and database files.
- Data entering the system:
  - Media container and stream metadata from source files.
  - Regex patterns and per-show normalization rules entered in the TUI.
  - Optional config values from `~/.local/etc/ffx.json`.
  - Optional TMDB identifiers and CLI overrides.
  - Optional external subtitle files.
- Data leaving the system:
  - Normalized output media files.
  - Extracted stream files from unmux operations.
  - SQLite rows representing shows, patterns, tracks, tags, shifted seasons, and properties.
  - Local log output and console messages.

## High-Level Building Blocks

- Frontend, CLI, API, or worker:
  - A Click-based CLI in [`src/ffx/cli.py`](/home/osgw/.local/src/codex/ffx/src/ffx/cli.py), exposed as the `ffx` command and via `python -m ffx`, including lightweight maintenance wrappers for bundle setup, workstation preparation, and upgrade tasks.
  - A Textual terminal UI rooted in [`src/ffx/ffx_app.py`](/home/osgw/.local/src/codex/ffx/src/ffx/ffx_app.py) with screens for shows, patterns, file inspection, tracks, tags, and shifted seasons.
- Core business logic:
  - Descriptor objects model media files, shows, and tracks.
  - Controllers encapsulate CRUD operations and workflow orchestration for shows, patterns, tags, tracks, season shifts, configuration, and conversion.
  - `MediaDescriptorChangeSet` computes differences between a file and its stored target schema to drive metadata and disposition updates.
  - File inspection caches combined `ffprobe` data and crop-detection results per source and sampling window within one process to avoid repeated subprocess work.
- Storage:
  - SQLite via SQLAlchemy ORM, with schema rooted in shows, patterns, tracks, media tags, track tags, shifted seasons, and generic properties.
  - Ordered schema migrations are loaded dynamically from per-version-step modules under [`src/ffx/model/migration/`](/home/osgw/.local/src/codex/ffx/src/ffx/model/migration/).
  - A configuration JSON file supplies optional path, metadata-filtering, and filename-template settings.
- Integration adapters:
  - Process execution wrapper for `ffmpeg`, `ffprobe`, `nice`, and `cpulimit`, with explicit disabled states for niceness and CPU limiting, support for both absolute `cpulimit` values and machine-wide percent input, and a combined `cpulimit -- nice -n ... <command>` execution shape when both limits are configured.
  - HTTP adapter for TMDB via `requests`.

## Data And Interface Notes

- Key entities or records:
  - `Show`: canonical TV show metadata plus digit-formatting rules, optional show-level notes, and an optional show-level encoding-quality fallback.
  - `Pattern`: regex rule tying filenames to one show and one target media schema.
  - `Track` and `TrackTag`: persisted target stream records, codec, dispositions, audio layout, and stream-level tags. Detailed source-to-target mapping rules live in `requirements/subtrack_mapping.md`.
  - `MediaTag`: persisted container-level metadata for a pattern.
  - `ShiftedSeason`: mapping from source numbering ranges to adjusted season and episode numbers, owned either by a show as fallback or by a pattern as override.
  - `Property`: internal key-value storage currently used for database versioning.
- External interfaces:
  - CLI commands for conversion, inspection, extraction, and crop detection.
  - TUI workflows for rule authoring and rule maintenance.
  - Environment variable `TMDB_API_KEY` for TMDB access.
  - Config keys `databasePath`, `logDirectory`, and `outputFilenameTemplate`, plus optional metadata-filter rules.
- Validation rules:
  - Only supported media-file extensions are accepted for conversion.
  - Stored database version must either match the runtime-required version already or have a supported sequential migration path to it.
  - A normalized descriptor may have at most one default and one forced stream per relevant track type.
  - Shifted-season ranges are intended not to overlap within the same owner scope and season, and runtime resolution prefers pattern-owned matches over show-owned matches.
  - TMDB lookups require a show ID and season and episode numbers.
- Error-handling approach:
  - User-facing operational failures are raised as `click.ClickException` or warnings.
  - Ambiguous default and forced stream states trigger prompts unless `--no-prompt` is set, in which case the command fails fast.
  - External-process failures and invalid media are surfaced through logs and command errors rather than retries, except for TMDB rate-limit retries.

## Deployment And Operations

- Runtime environment:
  - Local Python environment with the package installed and `ffmpeg`, `ffprobe`, `nice`, and `cpulimit` available on `PATH`.
- Deployment shape:
  - Single-process command execution on demand; no daemon, queue, or network service of its own.
- Secrets and configuration handling:
  - TMDB secret is read from `TMDB_API_KEY`.
  - User config is read from `~/.local/etc/ffx.json`.
  - Database path may also be overridden per command via `--database-file`.
- Logging and monitoring approach:
  - File and console logging configured per invocation.
  - Default log file path is `~/.local/var/log/ffx.log`.
  - No dedicated monitoring integration is present.

## Open Technical Questions

- Question: Should Linux-specific assumptions such as `/dev/null`, `nice`, `cpulimit`, and `~/.local` remain part of the supported-platform contract?
- Risk: Portability and operational behavior are underspecified for non-Linux environments.
- Next decision needed: Either document Linux-like systems as the official support boundary or refactor the process and path handling for broader portability.

- Question: Should placeholder TUI surfaces such as settings and help become part of the required product surface or stay explicitly out of scope?
- Risk: The UI appears broader than the actually finished feature set.
- Next decision needed: Either remove or complete placeholder screens and update requirements accordingly.
