- Updated AGENTS.md to reflect changes in CLI commands and module organization, including the addition of an enrichment step and new functional modules. - Introduced analysis.json, identities.json, inventory.csv, and plan.json to support enriched metadata and execution planning. - Added CODE_IMPROVEMENTS.md to document identified code issues and proposed solutions for future enhancements. - Updated README.md to include new enrichment features and configuration options. - Removed unused dependency on ffmpeg-python from pyproject.toml. These changes improve the overall functionality and maintainability of the Video Library Manager project.
208 lines
8.2 KiB
Markdown
208 lines
8.2 KiB
Markdown
# CLAUDE.md
|
|
|
|
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
|
|
|
|
### Installation
|
|
```bash
|
|
# Install package in editable mode
|
|
uv pip install -e .
|
|
|
|
# Install with dev dependencies (pytest, hypothesis)
|
|
uv pip install -e ".[dev]"
|
|
```
|
|
|
|
### Testing
|
|
```bash
|
|
# Run all tests
|
|
pytest
|
|
|
|
# Run specific test file
|
|
pytest tests/test_scanner.py
|
|
|
|
# Run with verbose output
|
|
pytest -v
|
|
```
|
|
|
|
### Running the CLI
|
|
```bash
|
|
# Verify CLI works
|
|
vlm --help
|
|
|
|
# Initialize config
|
|
vlm config init
|
|
|
|
# Common workflow
|
|
vlm scan # Discover files
|
|
vlm parse # Extract identities
|
|
vlm enrich # (Optional) Enrich titles/reputation via TMDB
|
|
vlm analyze # Detect gaps/duplicates
|
|
vlm plan # Generate execution plan
|
|
vlm execute # Dry-run (default)
|
|
vlm execute --confirm # Actually execute
|
|
```
|
|
|
|
## Architecture
|
|
|
|
### Core Workflow
|
|
VLM follows a read-first, multi-stage pipeline:
|
|
1. **Scan** → discovers video files, extracts metadata via ffprobe (optional), saves to inventory.csv
|
|
2. **Parse** → extracts titles/years/seasons/episodes from filenames, saves to identities.json
|
|
3. **Enrich** (optional) → adds bilingual titles and reputation (TMDB); updates identities.json in place; uses SQLite cache for incremental runs
|
|
4. **Analyze** → detects episode gaps and duplicates, saves to analysis.json
|
|
5. **Plan** → generates reviewable execution plan (plan.json) with file operations
|
|
6. **Execute** → performs file operations (dry-run by default, --confirm to execute)
|
|
7. **Rollback** → reverses executed operations (best-effort)
|
|
|
|
### Module Organization
|
|
- `cli.py` - Click-based CLI interface, global options, command registration
|
|
- `context.py` - CLIContext (config, paths) and pass_context for commands
|
|
- `commands/` - Command implementations (scan, analyze, plan)
|
|
- `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` - Load/save identities JSON/CSV, plan/analysis input helpers
|
|
- `utils.py` - UTC time, format_size, shared helpers
|
|
- `analysis.py` - Completeness checking (episode gaps) and duplicate detection
|
|
- `planner.py` - Execution plan generation with conflict detection
|
|
- `executor.py` - File operations (move/rename/quarantine) with rollback logging
|
|
- `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
|
|
|
|
### 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.
|
|
|
|
### 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 <noreply@anthropic.com>`
|