97 lines
5.9 KiB
Markdown
97 lines
5.9 KiB
Markdown
# 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`.
|
|
- 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.
|
|
- Storage:
|
|
- SQLite via SQLAlchemy ORM, with schema rooted in shows, patterns, tracks, media tags, track tags, shifted seasons, and generic properties.
|
|
- 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 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 for generated filenames.
|
|
- `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.
|
|
- `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 match the runtime-required version.
|
|
- 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 for the same show and season.
|
|
- 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.
|