diff --git a/AGENTS.md b/AGENTS.md index 0b8e566..d44a165 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,46 +1,88 @@ # Repository Guidelines -## Project Structure & Module Organization -- Core package lives in `src/vlm/`. -- CLI entrypoint is `src/vlm/cli.py` (`vlm` console script). Shared CLI helpers live in `cli_helpers.py`. Command logic is in `commands/` (scan, parse, enrich, analyze, plan, execute, review_plan, report, quarantine_cmd, state_cmd, config_cmd). -- Functional modules by concern: scanning (`scanner.py`), parsing (`parser.py`), enrichment (`enrichment.py`, `cache.py`, `providers/`), analysis/planning/execution (`analysis.py`, `planner.py`, `executor.py`), I/O helpers (`io.py`), utilities (`utils.py`), state/reporting/logging (`state.py`, `reports.py`, `logging_config.py`), config (`config.py`), models (`models.py`). -- Tests live in `tests/` and mirror feature areas (e.g. `tests/test_scanner.py`, `tests/test_cli_state.py`, `tests/test_enrichment.py`). -- Project metadata and tool config are in `pyproject.toml`. +## Project Overview +Video Library Manager (VLM) - Python CLI for managing personal video collections. Safety-first, human-in-the-loop approach. All operations reversible. -## Build, Test, and Development Commands -- `uv pip install -e .` installs the package in editable mode. -- `uv pip install -e ".[dev]"` installs dev dependencies (`pytest`, `hypothesis`, `pytest-cov`, `ruff`). -- `uv run pytest -q` runs the full test suite. -- `uv run pytest tests/test_logging.py` runs a targeted test file during iteration. -- `uv run ruff check src tests` runs the linter (also in CI). -- `vlm --help` verifies CLI startup and available commands. +## Quick Start +```bash +uv pip install -e ".[dev]" # Install with dev deps +uv run pytest -q # Run tests +uv run vlm --help # Verify CLI +``` -## Coding Style & Naming Conventions -- Use Python 3.10+ idioms, 4-space indentation, and PEP 8 naming. -- Modules/functions/variables: `snake_case`; classes: `PascalCase`; constants: `UPPER_SNAKE_CASE`. -- Keep modules focused on a single responsibility; prefer small pure helpers in domain modules. -- Add type hints for public functions and non-trivial internal APIs. -- Use absolute imports in `src/vlm/`: `from vlm.module import ...` (avoid new relative imports). -- Ruff (`E`, `F`, `I`) is configured in `pyproject.toml`; CI runs `ruff check src tests`. +## Core Workflow +1. `vlm scan` → discover files → `artifacts/inventory.csv` +2. `vlm parse` → extract identities → `artifacts/identities.json` +3. `vlm enrich` → (optional) add TMDB metadata +4. `vlm analyze` → detect gaps/duplicates → `artifacts/analysis.json` +5. `vlm plan` → generate execution plan → `artifacts/plan.json` +6. `vlm review-plan` → preview high-risk operations +7. `vlm execute` → dry-run by default, `--confirm` to execute +8. `vlm rollback` → undo executed operations -## Testing Guidelines -- Framework: `pytest`; property-based tests use `hypothesis`. -- Naming (enforced in config): files `test_*.py`, functions `test_*`, classes `Test*`. -- Add/extend tests with each behavior change, including CLI error paths and edge cases. -- Prefer narrow unit tests for module logic plus targeted CLI integration tests via `CliRunner`. +## Project Structure +- `src/vlm/cli.py` - CLI entrypoint +- `src/vlm/commands/` - Command implementations (scan, parse, enrich, analyze, plan, execute, review_plan, report, quarantine_cmd, state_cmd, config_cmd) +- `src/vlm/scanner.py` - File discovery + ffprobe metadata +- `src/vlm/parser.py` - Filename parsing (movies: title+year, series: SxxExx) +- `src/vlm/enrichment.py` - TMDB enrichment pipeline +- `src/vlm/planner.py` - Execution plan generation +- `src/vlm/executor.py` - File operations with rollback +- `src/vlm/models.py` - Data structures (VideoFile, MovieIdentity, SeriesIdentity, etc.) +- `tests/` - Test suite mirroring source modules -## Commit & Pull Request Guidelines -- Current history is minimal; use clear, imperative commit subjects (example: `fix logging fallback for unwritable log dir`). -- Keep commits focused; avoid mixing refactors and behavior changes unless tightly coupled. -- PRs should include: summary, rationale, test evidence (`pytest` output), and any CLI-visible output changes. -- Link related issues/tasks when applicable and call out config or migration impacts. +## Key Concepts -## Security & Configuration Tips -- Do not commit local paths, personal media metadata, or generated state/log artifacts. -- Validate config changes against `vlm --help` and at least one end-to-end CLI flow before merging. +### Safety Protocol +- NEVER delete files permanently - use quarantine +- All operations create rollback logs with `--confirm` +- Default mode is dry-run +### File Categorization +Based on top-level directory matching `categories` config (case-insensitive). Default: `movie`, `series`, `anime`. -## Documentation baseline -- Updated to reflect release 0.2.0 baseline as of 2026-06-01. -- Canonical release notes are tracked in `CHANGELOG.md`. -- Default workflow artifacts: `artifacts/` (do not commit generated CSV/JSON). +### Schema Versions +- **v1** (default): Lightweight, no embedded metadata +- **v2** (with `--inventory`): Includes video metadata for quality-aware duplicate resolution + +### Parsing Patterns (Hardcoded) +- Movies: `{title} ({year})` or `{title}.{year}` +- Series: `S{season:02d}E{episode:02d}` or `{season}x{episode}` + +## Development Commands +```bash +uv run pytest # All tests +uv run pytest tests/test_scanner.py # Specific file +uv run ruff check src tests # Lint +uv run vlm scan # Discover files +uv run vlm parse --inventory artifacts/inventory.csv # Parse with metadata +uv run vlm plan --analysis artifacts/analysis.json # Plan with duplicates +uv run vlm review-plan --tui # Interactive review (requires [tui]) +``` + +## Code Style +- Python 3.10+, 4-space indent, PEP 8 +- `snake_case` functions/vars, `PascalCase` classes, `UPPER_SNAKE_CASE` constants +- Type hints for public APIs +- Absolute imports: `from vlm.module import ...` +- Ruff (`E`, `F`, `I`) enforced in CI + +## Testing +- pytest + hypothesis for property-based tests +- Naming: `test_*.py`, `test_*()`, `Test*` +- Add tests with behavior changes +- Prefer unit tests + targeted CLI integration via `CliRunner` + +## Commit Guidelines +- Imperative subjects: `fix logging fallback for unwritable log dir` +- Keep commits focused (no mixed refactors + behavior changes) +- Include: `Co-Authored-By: Claude Sonnet 4.5 ` +- PRs: summary, rationale, test evidence, CLI output changes + +## Important Notes +- Anime: discovered but not parsed in v1 +- State tracking: optional, persisted to `~/.vlm/state.json` +- Quarantine: only movie/series (not anime/other) +- Timestamps: UTC ISO 8601 format +- Logging: `~/.vlm/vlm.log`, falls back to console if unwritable +- Config: `~/.vlm/config.yaml` diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 60829ea..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,279 +0,0 @@ -# CLAUDE.md - -## Documentation Status -- Synchronized with release 0.2.0 baseline on 2026-06-01 (see `CHANGELOG.md`). -- Default workflow outputs: `artifacts/` — do not commit generated CSV/JSON at repo root. - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Project Overview - -Video Library Manager (VLM) is a Python CLI tool for managing personal video collections with a safety-first, human-in-the-loop approach. All file operations are reversible, require explicit confirmation, and generate reviewable execution plans before making changes. - -## Development Commands - -**Important:** This project uses `uv` for Python package management. All commands should be run with `uv run` to ensure they execute in the correct project environment with proper dependencies. - -### Installation -```bash -# Install package in editable mode -uv pip install -e . - -# Install with dev dependencies (pytest, hypothesis) -uv pip install -e ".[dev]" - -# Optional Textual UI for `vlm review-plan --tui` -uv pip install -e ".[tui]" -``` - -The default CLI path does not require Textual; it is imported only when `uv run vlm review-plan --tui` is used. - -### Testing -```bash -# Run all tests (use uv run to execute in the project environment) -uv run pytest - -# Run specific test file -uv run pytest tests/test_scanner.py - -# Run with verbose output -uv run pytest -v - -# Run with quiet output (summary only) -uv run pytest -q - -# Count total test cases -uv run pytest --collect-only -q -``` - -### Running the CLI -```bash -# Verify CLI works (use uv run for proper environment) -uv run vlm --help - -# Initialize config -uv run vlm config init - -# Common workflow -uv run vlm scan # Discover files -uv run vlm parse # Extract identities (v1 schema) -uv run vlm parse --inventory artifacts/inventory.csv # Embed metadata for quality-aware duplicate handling -uv run vlm enrich # (Optional) Enrich titles/reputation via TMDB -uv run vlm enrich --refresh-all # Force full refresh (ignore cache) -uv run vlm analyze # Detect gaps/duplicates -uv run vlm plan # Generate execution plan -uv run vlm plan --analysis artifacts/analysis.json # Generate plan with duplicate resolution -uv run vlm review-plan # Export CSV + terminal review preview -uv run vlm review-plan --tui # Optional full-screen review UI -uv run vlm apply-review # Sync edited CSV decisions back into the plan -uv run vlm execute # Dry-run (default) -uv run vlm execute --confirm # Actually execute -uv run vlm rollback # Undo executed operations - -# Reporting -uv run vlm report summary # Overview statistics -uv run vlm report inventory # File inventory -uv run vlm report completeness # Series with missing episodes -uv run vlm report duplicates # Duplicate files with quality comparison - -# Quarantine management -uv run vlm quarantine list # List quarantined files -uv run vlm quarantine add --reason "duplicate" -uv run vlm quarantine restore - -# State management -uv run vlm state show -uv run vlm state set --status reviewed -``` - -## Architecture - -### Core Workflow -VLM follows a read-first, multi-stage pipeline: -1. **Scan** → discovers video files, extracts metadata via ffprobe (optional), saves to `artifacts/inventory.csv` -2. **Parse** → extracts titles/years/seasons/episodes from filenames, saves to `artifacts/identities.json` - - Use `--inventory artifacts/inventory.csv` to embed video metadata (v2 schema) for accurate duplicate resolution by quality - - Without `--inventory`, produces v1 schema (lightweight, no embedded metadata) -3. **Enrich** (optional) → adds bilingual titles and reputation (TMDB); updates `artifacts/identities.json` in place; uses SQLite cache for incremental runs -4. **Analyze** → detects episode gaps and duplicates, saves to `artifacts/analysis.json` -5. **Plan** → generates reviewable execution plan (`artifacts/plan.json`) with file operations -6. **Review / Apply Review** → previews high-risk operations in terminal or optional TUI, then syncs edited CSV decisions back into the plan when needed -7. **Execute** → performs file operations (dry-run by default, `--confirm` to execute) -8. **Rollback** → reverses executed operations (best-effort) - -### Module Organization -- `cli.py` - Thin Click registrar with global options; command definitions live in `commands/` -- `cli_helpers.py` - Shared CLI helpers (context init, command runner, report emission) -- `context.py` - CLIContext (config, paths) and pass_context for commands -- `commands/` - Command modules (scan, parse, enrich, analyze, plan, execute/rollback, review_plan, report, quarantine_cmd, state_cmd, config_cmd) -- `plan_render.py` - Shared rendering of plan summaries in CLI output -- `plan_review.py` - High-risk operation flagging and manual-review export -- `plan_structure_preview.py` - Target library tree preview for review-plan -- `review_display.py` - Human-readable plan review rendering shared by CLI preview and TUI -- `review_tui.py` - Optional Textual review UI (lazy import) -- `transaction.py` - Transaction/rollback logging for executed operations -- `scanner.py` - File discovery using system `find` command, metadata extraction via ffprobe -- `parser.py` - Filename parsing using regex patterns (movies: title + year, series: SxxExx) -- `enrichment.py` - Enrichment pipeline; `cache.py` - SQLite cache; `providers/` - TMDB etc. -- `io.py` - Unified JSON/CSV I/O helpers, including validated typed plan loading/saving -- `utils.py` - UTC time, format_size, shared helpers -- `analysis.py` - Completeness checking (episode gaps) and duplicate detection -- `duplicate_resolve.py` - Duplicate group resolution with explicit failures for unresolved strategies/data -- `planner.py` - Execution plan generation with conflict detection and manual-review duplicate fallback -- `executor.py` - File operations (move/rename/quarantine) with rollback logging and library-root safety checks -- `quarantine.py` - Quarantine management with manifest tracking -- `state.py` - File state tracking across workflow stages -- `reports.py` - Report generation (inventory, completeness, duplicates, summary) -- `config.py` - YAML configuration loading and validation -- `models.py` - Dataclass definitions for all data structures -- `logging_config.py` - Logging setup with fallback to console if file logging fails - -### Key Data Structures -All defined in `models.py`: -- `VideoFile` - represents discovered video file with metadata -- `MovieIdentity` / `SeriesIdentity` - parsed identity with confidence score -- `ExecutionPlan` - collection of file operations with summary -- `FileOperation` - single operation (move/rename/quarantine/no-op) with conflict detection -- `RollbackLog` - log of executed operations for reversal -- `QuarantineEntry` - quarantined file with original location -- `FileState` - workflow state (reviewed/ignored/planned/executed/quarantined) - -### File Categorization -Based on top-level directory within library root, matched against configured category mappings (case-insensitive). - -Files in unmapped directories are categorized as "other" and skipped by planner/quarantine operations. - -### Parsing Patterns (Hardcoded) -**Movies** (high confidence): -- `{title} ({year})` -- `{title}.{year}` - -**Series** (high confidence): -- `S{season:02d}E{episode:02d}` -- `{season}x{episode}` - -Patterns are hardcoded in parser.py, not user-configurable. - -### Configuration -Default location: `~/.vlm/config.yaml` - -Key settings: -- `library_root` - root directory to scan (required) -- `video_extensions` - list of extensions to recognize -- `templates.movie_dir` / `templates.series_dir` - directory structure templates -- `templates.movie_filename` / `templates.series_filename` - filename templates -- `quarantine_dir` - name of quarantine directory (default: `.quarantine`) -- `log_level` - logging verbosity -- `categories` - mapping of category names to directory name lists -- `enrichment` (or `enrich`) - TMDB/api_keys, cache_db, translation, reputation; see README for full schema -- `plan.duplicate_keep` - when using `vlm plan --analysis`: `by_quality`, `by_reputation` (default), `by_reputation_quality_time`, `first_seen`, or `manual` - -### Category Mappings - -Categories are determined by matching the top-level directory name against configured mappings: - -**Default mappings:** -```yaml -categories: - movie: [movie] - series: [series] - anime: [anime] -``` - -**Custom mappings** support multiple directory names per category: -```yaml -categories: - movie: [movie, movies, films] - series: [series, tv, shows, television] - anime: [anime] -``` - -This allows files in `/library/movies/` or `/library/films/` to be recognized as the "movie" category. Directory matching is case-insensitive. - -**Migration Note:** If you have existing directories with non-standard names (like "movies" or "tv"), update your config.yaml and re-run `vlm scan` to fix categorization. No files will be moved. - -### Schema Versioning - -**identities.json Schema Versions:** - -- **v1** (default without `--inventory`): Lightweight schema without embedded metadata - - Records contain: path, filename, category, title, year/season/episodes, confidence, needs_review - - VideoFile objects reconstructed with defaults: size_bytes=0, resolution=None, codec=None - - Suitable for basic organization workflows - -- **v2** (with `--inventory`): Enhanced schema with embedded video metadata - - All v1 fields plus `video_metadata` object containing: - - size_bytes, modified_timestamp, resolution, codec, duration_seconds, bitrate_kbps - - Enables accurate duplicate resolution by quality (compare resolution, codec, file size) - - Required for `by_quality` duplicate resolution strategy - - Backward compatible: v1 files load without errors - -**Implementation Details:** -- `_video_file_from_record()` in io.py extracts embedded metadata if present -- Parse command with `--inventory` flag loads inventory.csv and embeds metadata in output -- Schema version stored in `vlm_schema_version` field at root level of identities.json - -### File Discovery -Uses system `find` command for speed, falls back to Python recursion if unavailable. Hidden paths (starting with `.`) are skipped automatically. - -### Timestamp Handling -All timestamps stored in UTC using ISO 8601 format (`YYYY-MM-DDTHH:MM:SS`). The scanner normalizes naive timestamps to UTC using system timezone. - -### Logging -Logs to `~/.vlm/vlm.log` by default. If log directory is unwritable, falls back to console-only logging and continues execution (does not fail). - -### Error Handling -- Configuration errors: display helpful message, create default config, continue -- Missing ffprobe: skip metadata extraction, log debug message, continue -- File access errors: log error, skip file, continue scanning -- Invalid YAML: display error, use default config - -## Testing Guidelines - -- Framework: pytest with hypothesis for property-based tests -- Test file naming: `test_*.py` -- Test function naming: `test_*` -- Test class naming: `Test*` -- Use `CliRunner` for CLI integration tests -- Prefer narrow unit tests for module logic plus targeted CLI integration tests -- Add tests with each behavior change, including error paths and edge cases - -## Important Implementation Notes - -### Safety Protocol -- NEVER permanently delete files - use quarantine instead -- All file operations create rollback logs when executed with --confirm -- Execution plans detect destination conflicts and mark operations -- Default mode is dry-run; --confirm required for actual execution -- Quarantine is reversible via restore command - -### Anime Handling -Anime files are discovered and categorized but NOT parsed in v1 (deferred for future implementation). - -### State Management -State tracking is optional and allows marking files as reviewed/ignored/planned/executed/quarantined. State is persisted to `~/.vlm/state.json`. - -### Quarantine Constraints -Only movie and series files can be quarantined in v1 (anime and other categories rejected). - -### Template Variables -Available for path/filename templates: -- Movies: `{title}`, `{year}`, `{ext}` -- Series: `{title}`, `{season}`, `{episode}`, `{ext}` - -Format specifiers like `{season:02d}` are supported. - -## Code Style - -- Python 3.10+ idioms -- 4-space indentation -- PEP 8 naming: `snake_case` for functions/variables, `PascalCase` for classes, `UPPER_SNAKE_CASE` for constants -- Type hints for public functions and non-trivial internal APIs -- Modules focused on single responsibility -- No formatter/linter enforced - maintain consistency with existing files - -## Commit Guidelines - -- Clear, imperative commit subjects (e.g., "fix logging fallback for unwritable log dir") -- Keep commits focused - avoid mixing refactors and behavior changes -- Include co-author tag: `Co-Authored-By: Claude Sonnet 4.5 `