## Purpose And Scope - Project name: FFX - User problem: TV episode files from mixed sources arrive with inconsistent codecs, stream metadata, subtitle layouts, season and episode numbering, and output filenames, which makes them awkward to archive and use in media-player applications. - Target users: Individual operators curating a local TV media library on a workstation, especially users willing to define normalization rules per show. - Success outcome: A user can inspect source files, define reusable show and pattern rules, and produce output files whose streams, metadata, and filenames follow a predictable schema for web playback and library import. - Out of scope: - Multi-user or hosted service workflows. - General movie-library management. - Distributed transcoding or remote job orchestration. - Broad media-server administration beyond file preparation. ## Required Product - Deliverable type: Installable Python command-line application with a Textual terminal UI for inspection and rule editing. - Core capabilities: - Maintain an SQLite-backed database of shows, filename-matching patterns, per-pattern stream layouts and metadata tags, and optional season-shift rules. - Inspect existing media files through `ffprobe` and compare discovered stream metadata with stored normalization rules. - Convert media files through `ffmpeg` into a normalized output layout, including video recoding, audio transcoding to Opus, metadata cleanup and rewrite, and controlled disposition flags. - Build output filenames from detected or configured show, season, and episode information, optionally enriched from TMDB and a configurable Jinja-style filename template. - Support auxiliary file operations such as subtitle import, unmuxing, crop detection, rename-only conversion runs, and direct in-place episode renaming. - Supported environments: - Local execution on a Python-capable workstation. - Best-supported on Linux-like systems because the implementation assumes `~/.local`, `/dev/null`, `nice`, and `cpulimit`. - Requires `ffmpeg`, `ffprobe`, and `cpulimit` on `PATH`. - Operational owner: The local user running the tool and maintaining its config, database, and external tooling. ## Suggested User Stories - As a library maintainer, I want to define show-specific matching rules once so that future source files can be normalized automatically. - As an operator, I want to inspect a file before conversion so that I can compare its actual streams and tags against the stored target schema. - As a user preparing web-playback files, I want to recode video and audio with a small set of predictable options so that results are compatible and consistently named. - As a user dealing with nonstandard releases, I want CLI overrides for language, title, stream order, default and forced tracks, and season and episode data so that one-off fixes do not require database edits first. - As a user importing anime or other shifted numbering schemes, I want season and episode offsets per show so that generated filenames align with TMDB and media-library expectations. ## Functional Requirements - The system shall provide a CLI entrypoint named `ffx` with commands for `convert`, `inspect`, `shows`, `rename`, `unmux`, `cropdetect`, `setup`, `configure_workstation`, `upgrade`, `version`, and `help`. - The system shall support a two-step local installation and preparation flow: - `tools/setup.sh` is the bootstrap entrypoint for the first step and shall own bundle virtualenv creation, package installation, shell alias exposure, and optional Python test-package installation. - `tools/configure_workstation.sh` is the bootstrap entrypoint for the second step and shall own workstation dependency checks and installation plus local config and directory seeding. - After the bundle is installed, `ffx setup` and `ffx configure_workstation` shall remain aligned wrapper entrypoints for those same two steps. - The CLI command `ffx setup` shall act as a wrapper for the first-step bundle-preparation flow in `tools/setup.sh`. - The CLI command `ffx configure_workstation` shall act as a wrapper for the second-step preparation flow in `tools/configure_workstation.sh`. - The system shall persist reusable normalization rules in SQLite for: - shows and show formatting digits, - regex-based filename patterns, - per-pattern media tags, - per-pattern stream definitions, - shifted-season mappings, - internal database version properties. - Detailed show, pattern, and duplicate-match management rules live in `requirements/pattern_management.md`. - The system shall inspect source media using `ffprobe` and derive a structured description of container metadata and streams. - The system shall optionally open a Textual UI to browse shows, inspect files, and create, edit, or delete shows, patterns, stream definitions, tags, and shifted-season rules. - The system shall match filenames against stored regex patterns to decide whether an input file should inherit a target stream and metadata schema. - The system shall convert supported input files (`mkv`, `mp4`, `avi`, `flv`, `webm`) with `ffmpeg`, supporting at least: - VP9, AV1, and H.264 video encoding, - Opus audio encoding with bitrate selection based on channel layout, - metadata and disposition rewriting, - optional crop detection and crop application, - optional deinterlacing and denoising, - optional subtitle import from external files, - rename-only move mode. - The system shall support optional TMDB lookups to resolve show names, years, and episode titles when a show ID, season, and episode are available. - The system shall generate output filenames from show metadata, season and episode indices, and episode names using the configured filename template. - The system shall allow CLI overrides for stream languages, stream titles, default and forced tracks, stream order, TMDB show and episode data, output directory, label prefix, and processing resource limits. - Processing resource limit rules: - `--nice` shall accept niceness values from `-20` through `19`; omitting the option shall disable niceness adjustment. - `--cpu` shall accept either a positive absolute `cpulimit` value such as `200`, or a percentage suffixed with `%` such as `25%` to represent a share of present CPUs; omitting the option or using `0` shall disable CPU limiting. - When both limits are configured, the process wrapper shall execute the target command through `cpulimit` around a `nice -n ...` invocation so both limits apply to the launched media command. - The system shall support extracting streams into separate files via `unmux` and reporting suggested crop parameters via `cropdetect`. - The system shall support in-place episode renaming via `rename`, requiring a `--prefix`, accepting optional `--season` and `--suffix` overrides, preserving the source extension, and supporting dry-run output without moving files. - Crop detection shall use a configurable sampling window, defaulting to a 60-second seek and a 180-second analysis duration, and repeated crop-detection requests for the same source plus sampling window shall reuse cached results within one process. - The system shall handle invalid input and system failures gracefully by logging warnings or raising `click` errors for missing files, invalid media, missing TMDB credentials, incompatible database versions, and ambiguous track dispositions when prompting is disabled. ## Quality Requirements - The system should stay understandable as a small local tool: controllers, descriptors, models, and screens should remain separate enough for contributors to trace a workflow end to end. - The system should produce predictable output for the same database rules, CLI overrides, and source files. - The system should preserve a lightweight operational footprint: local SQLite state, local log file, no mandatory background services. - The system should be testable through modern automatically discovered tests and through remaining legacy harness coverage during migration. - The system should expose enough logging to diagnose failed probes, failed conversions, and rule mismatches without requiring a debugger. ## Constraints And Assumptions - Technology constraints: - Python package built with setuptools. - Primary libraries: `click`, `textual`, `sqlalchemy`, `jinja2`, `requests`. - Conversion and inspection rely on external executables rather than pure-Python media libraries. - Hosting or infrastructure constraints: - Intended for local execution, not server deployment. - Stores default state in `~/.local/etc/ffx.json`, `~/.local/var/ffx/ffx.db`, and `~/.local/var/log/ffx.log`. - Timeline constraints: - The current implemented scope reflects a compact alpha release stream up to version `0.2.4`. - Team capacity assumptions: - Maintained as a small codebase where simple patterns and direct controller logic are preferred over framework-heavy abstractions. - Third-party dependencies: - `ffmpeg`, `ffprobe`, and `cpulimit`. - TMDB API access through `TMDB_API_KEY` for metadata enrichment. - Installation assumptions: - The Python-side bundle install step and optional Python test extras are managed by `tools/setup.sh`, with `ffx setup` as the aligned wrapper after bootstrap. - The workstation-preparation step is managed separately by `tools/configure_workstation.sh` or `ffx configure_workstation`. ## Acceptance Scope - First release boundary: - Local installation through `pip`. - Working SQLite-backed rule storage. - Functional CLI conversion and inspection workflows. - Textual CRUD flows for shows, patterns, tags, tracks, and shifted seasons. - TMDB-assisted filename generation, subtitle import, season shifting, database versioning, and configurable output filename templating. - Excluded follow-up ideas: - Completing placeholder screens such as settings and help. - Hardening platform portability beyond Linux-like systems. - Broader media types, richer release packaging, and production-grade background processing. - Demonstration scenario: - Inspect a TV episode file, define or update the matching show and pattern in the TUI, then run `ffx convert` so the result uses the stored stream schema, optional TMDB episode naming, and a normalized output filename.