refactor: Remove old decorators and integrate caching into the new cache subsystem

- Deleted the `renamer.decorators` package, including `caching.py` and `__init__.py`, to streamline the codebase.
- Updated tests to reflect changes in import paths for caching decorators.
- Added a comprehensive changelog to document major refactoring efforts and future plans.
- Introduced an engineering guide detailing architecture, core components, and development setup.
This commit is contained in:
sHa
2026-01-02 08:12:28 +00:00
parent 7c7e9ab1e1
commit 60f32a7e8c
11 changed files with 1965 additions and 2182 deletions

View File

@@ -1,208 +0,0 @@
# AI Agent Instructions for Media File Renamer Project
## Project Description
This is a Python Terminal User Interface (TUI) application for managing media files. It uses the Textual library to provide a curses-like interface in the terminal. The app allows users to scan directories for video files, display them in a hierarchical tree view, view detailed metadata information including video, audio, and subtitle tracks, and rename files based on intelligent metadata extraction.
**Current Version**: 0.7.0-dev (Phase 1 complete)
Key features:
- Recursive directory scanning with tree navigation
- Dual-mode display: Technical (codec/track details) and Catalog (TMDB metadata with posters)
- Tree-based file navigation with expand/collapse functionality
- Multi-source metadata extraction (MediaInfo, filename parsing, embedded tags, TMDB API)
- Intelligent file renaming with proposed names and confirmation
- Settings management with persistent configuration
- **NEW**: Unified cache subsystem with flexible strategies and decorators
- **NEW**: Command palette (Ctrl+P) with cache management commands
- **NEW**: Thread-safe cache with RLock protection
- **NEW**: Comprehensive logging (warning/debug levels)
- **NEW**: Proper exception handling (no bare except clauses)
- Terminal poster display using rich-pixels
- Color-coded information display
- Keyboard and mouse navigation
- Multiple UI screens (main app, directory selection, help, rename confirmation, settings)
- Extensible extractor and formatter architecture
- Loading indicators and comprehensive error handling
## Technology Stack
- Python 3.11+
- Textual ≥6.11.0 (TUI framework)
- PyMediaInfo ≥6.0.0 (detailed track information)
- Mutagen ≥1.47.0 (embedded metadata)
- Python-Magic ≥0.4.27 (MIME type detection)
- Langcodes ≥3.5.1 (language code handling)
- Requests ≥2.31.0 (HTTP client for TMDB API)
- Rich-Pixels ≥1.0.0 (terminal image display)
- Pytest ≥7.0.0 (testing framework)
- UV (package manager and build tool)
## Code Structure
- `renamer/main.py`: Main application entry point with argument parsing
- `pyproject.toml`: Project configuration and dependencies (version 0.5.10)
- `README.md`: User documentation
- `DEVELOP.md`: Developer guide with debugging info
- `INSTALL.md`: Installation instructions
- `CLAUDE.md`: Comprehensive AI assistant reference guide
- `ToDo.md`: Development task tracking
- `AI_AGENT.md`: This file (AI agent instructions)
- `renamer/`: Main package
- `app.py`: Main Textual application class with tree management, file operations, and command palette
- `settings.py`: Settings management with JSON storage
- `cache/`: **NEW** Unified cache subsystem (v0.7.0)
- `core.py`: Thread-safe Cache class
- `strategies.py`: Cache key generation strategies
- `managers.py`: CacheManager for operations
- `decorators.py`: Enhanced cache decorators
- `types.py`: Type definitions
- `secrets.py`: API keys and secrets (TMDB)
- `constants.py`: Application constants (media types, sources, resolutions, special editions)
- `screens.py`: Additional UI screens (OpenScreen, HelpScreen, RenameConfirmScreen, SettingsScreen)
- `bump.py`: Version bump utility
- `release.py`: Release automation script
- `extractors/`: Individual extractor classes
- `extractor.py`: MediaExtractor class coordinating all extractors
- `mediainfo_extractor.py`: PyMediaInfo-based extraction
- `filename_extractor.py`: Filename parsing with regex patterns
- `metadata_extractor.py`: Mutagen-based embedded metadata
- `fileinfo_extractor.py`: Basic file information
- `tmdb_extractor.py`: The Movie Database API integration
- `default_extractor.py`: Fallback extractor
- `formatters/`: Data formatting classes
- `formatter.py`: Base formatter interface
- `media_formatter.py`: Main formatter coordinating display
- `catalog_formatter.py`: Catalog mode formatting with TMDB data
- `proposed_name_formatter.py`: Generates rename suggestions
- `track_formatter.py`: Track information formatting
- `size_formatter.py`: File size formatting
- `date_formatter.py`: Timestamp formatting
- `duration_formatter.py`: Duration formatting
- `resolution_formatter.py`: Resolution formatting
- `text_formatter.py`: Text styling utilities
- `extension_formatter.py`: File extension formatting
- `helper_formatter.py`: Helper formatting utilities
- `special_info_formatter.py`: Special edition information
- `decorators/`: Utility decorators
- `caching.py`: Caching decorator for automatic method caching
- `test/`: Unit tests for extractors
- `test_filename_extractor.py`: Filename parsing tests
- `test_mediainfo_extractor.py`: MediaInfo extraction tests
- `test_mediainfo_frame_class.py`: Frame class detection tests
- `test_fileinfo_extractor.py`: File info tests
- `test_metadata_extractor.py`: Metadata extraction tests
- `test_filename_detection.py`: Filename pattern detection tests
- `filenames.txt`, `test_filenames.txt`: Sample test data
- `test_cases.json`, `test_mediainfo_frame_class.json`: Test fixtures
## Instructions for AI Agents
### Coding Standards
- Use type hints where possible
- Follow PEP 8 style guidelines
- Use descriptive variable and function names
- Add docstrings for functions and classes
- Handle exceptions appropriately
- Use pathlib for file operations
### Development Workflow
1. Read the current code and understand the architecture
2. Check the ToDo.md for pending tasks
3. Implement features incrementally
4. Test changes by running the app with `uv run python main.py [directory]`
5. Update tests as needed
6. Ensure backward compatibility
7. Update documentation (README.md, ToDo.md) when adding features
### Key Components
- `RenamerApp`: Main application class inheriting from Textual's App
- Manages the tree view and file operations
- Handles keyboard navigation and commands
- Coordinates metadata extraction and display
- Implements efficient tree updates for renamed files
- `MediaTree`: Custom Tree widget with file-specific styling (inherited from Textual Tree)
- `MediaExtractor`: Coordinates multiple specialized extractors
- `MediaFormatter`: Formats extracted data for TUI display
- Various extractor classes for different data sources
- Various formatter classes for different data types
- Screen classes for different UI states
### Extractor Architecture
Extractors are responsible for gathering raw data from different sources:
- Each extractor inherits from no base class but follows the pattern of `__init__(file_path)` and `extract_*()` methods
- The `MediaExtractor` class coordinates multiple extractors and provides a unified `get()` interface
- Extractors return raw data (strings, numbers, dicts) without formatting
### Formatter Architecture
Formatters are responsible for converting raw data into display strings:
- Each formatter provides static methods like `format_*()`
- The `MediaFormatter` coordinates formatters and applies them based on data types
- `ProposedNameFormatter` generates intelligent rename suggestions
- Formatters handle text styling, color coding, and human-readable representations
### Screen Architecture
The app uses multiple screens for different operations:
- `OpenScreen`: Directory selection with input validation
- `HelpScreen`: Comprehensive help with key bindings
- `RenameConfirmScreen`: File rename confirmation with error handling
### Completed Major Features
- ✅ Settings management with JSON configuration
- ✅ Mode toggle (technical/catalog)
- ✅ Caching system with TTL support
- ✅ TMDB integration for catalog data
- ✅ Poster display in terminal
- ✅ Settings UI screen
### Future Enhancements
- Metadata editing capabilities
- Batch rename operations
- Plugin system for custom extractors/formatters
- Advanced search and filtering
- Undo/redo functionality
- Blue highlighting for changed parts in proposed filename
- Exclude dev commands from distributed package
- Full genre name expansion (currently shows codes)
- Optimized poster quality and display
### Testing
- Run the app with `uv run python main.py [directory]`
- Test navigation, selection, and display
- Verify metadata extraction accuracy
- Test file renaming functionality
- Check for any errors or edge cases
- Run unit tests with `uv run pytest`
### Contribution Guidelines
- Make small, focused changes
- Update documentation as needed
- Ensure the app runs without errors
- Follow the existing code patterns
- Update tests for new functionality
- Update ToDo.md when completing tasks
- Update version numbers appropriately
## Important Files for AI Assistants
For comprehensive project information, AI assistants should refer to:
1. **CLAUDE.md**: Complete AI assistant reference guide (most comprehensive)
2. **AI_AGENT.md**: This file (concise instructions)
3. **DEVELOP.md**: Developer setup and debugging
4. **ToDo.md**: Current task list and completed items
5. **README.md**: User-facing documentation
This document should be updated as the project evolves.
---
**Last Updated**: 2025-12-31

225
CHANGELOG.md Normal file
View File

@@ -0,0 +1,225 @@
# Changelog
All notable changes to the Renamer project are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
---
## [Unreleased]
### Future Plans
See [REFACTORING_PROGRESS.md](REFACTORING_PROGRESS.md) and [ToDo.md](ToDo.md) for upcoming features and improvements.
---
## [0.7.0-dev] - 2026-01-01
### Major Refactoring (Phases 1-3)
This development version represents a significant refactoring effort focused on code quality, architecture, and maintainability.
---
### Phase 3: Code Quality (COMPLETED)
#### Added
- **Type Hints**: Complete type coverage for `DefaultExtractor` (21 methods)
- **Mypy Integration**: Added mypy>=1.0.0 as dev dependency for type checking
- **Comprehensive Docstrings**: Added module + class + method docstrings to 5 key files:
- `default_extractor.py` - 22 docstrings
- `extractor.py` - Enhanced with examples
- `fileinfo_extractor.py` - Enhanced with Args/Returns
- `metadata_extractor.py` - Enhanced with examples
- `formatter.py` - Enhanced FormatterApplier
#### Changed
- **Constants Reorganization**: Split monolithic `constants.py` into 8 logical modules:
- `media_constants.py` - Media types
- `source_constants.py` - Video sources
- `frame_constants.py` - Frame classes and quality indicators
- `moviedb_constants.py` - Database identifiers
- `edition_constants.py` - Special editions
- `lang_constants.py` - Skip words for language detection
- `year_constants.py` - Dynamic year validation
- `cyrillic_constants.py` - Character mappings
- **Dynamic Year Validation**: Replaced hardcoded year values with `is_valid_year()` function
- **Language Extraction**: Simplified using `langcodes.Language.get()` for dynamic validation (~80 lines removed)
#### Removed
- **Code Duplication**: Eliminated ~95 lines of duplicated code:
- ~80 lines of hardcoded language lists
- ~15 lines of duplicated movie DB pattern matching
- **Hardcoded Values**: Removed hardcoded quality indicators, year values, Cyrillic mappings
### Phase 2: Architecture Foundation (COMPLETED)
#### Added
- **Base Classes and Protocols** (409 lines):
- `DataExtractor` Protocol defining extractor interface (23 methods)
- `Formatter` ABCs: `DataFormatter`, `TextFormatter`, `MarkupFormatter`, `CompositeFormatter`
- **Service Layer** (935 lines):
- `FileTreeService`: Directory scanning and validation
- `MetadataService`: Thread-pooled metadata extraction with cancellation support
- `RenameService`: Filename validation, sanitization, and atomic renaming
- **Utility Modules** (953 lines):
- `PatternExtractor`: Centralized regex pattern matching
- `LanguageCodeExtractor`: Language code processing
- `FrameClassMatcher`: Resolution/frame class matching
- **Command Palette Integration**:
- `AppCommandProvider`: 8 main app commands
- `CacheCommandProvider`: 7 cache management commands
- Access via Ctrl+P
#### Improved
- **Thread Safety**: MetadataService uses ThreadPoolExecutor with Lock for concurrent operations
- **Testability**: Services can be tested independently of UI
- **Reusability**: Clear interfaces and separation of concerns
### Phase 1: Critical Bug Fixes (COMPLETED)
#### Fixed
- **Cache Key Generation Bug**: Fixed critical variable scoping issue in cache system
- **Resource Leaks**: Fixed file handle leaks in tests (proper context managers)
- **Exception Handling**: Replaced bare `except:` clauses with specific exceptions
#### Added
- **Thread Safety**: Added `threading.RLock` to cache for concurrent access
- **Logging**: Comprehensive logging throughout extractors and formatters:
- Debug: Language code conversions, metadata reads
- Warning: Network failures, API errors, MediaInfo parse failures
- Error: Formatter application failures
#### Changed
- **Unified Cache Subsystem** (500 lines):
- Modular architecture: `core.py`, `types.py`, `strategies.py`, `managers.py`, `decorators.py`
- 4 cache key strategies: `FilepathMethodStrategy`, `APIRequestStrategy`, `SimpleKeyStrategy`, `CustomStrategy`
- Enhanced decorators: `@cached_method()`, `@cached_api()`, `@cached_property()`
- Cache manager operations: `clear_all()`, `clear_by_prefix()`, `clear_expired()`, `compact_cache()`
---
### Phase 5: Test Coverage (PARTIALLY COMPLETED - 4/6)
#### Added
- **Service Tests** (30+ tests): FileTreeService, MetadataService, RenameService
- **Utility Tests** (70+ tests): PatternExtractor, LanguageCodeExtractor, FrameClassMatcher
- **Formatter Tests** (40+ tests): All formatter classes and FormatterApplier
- **Cache Tests** (18 tests): Cache subsystem functionality
- **Dataset Organization**:
- `filename_patterns.json`: 46 comprehensive test cases
- `frame_class_tests.json`: 25 frame class test cases
- Sample file generator: `fill_sample_mediafiles.py`
- Dataset loaders in `conftest.py`
#### Changed
- **Test Organization**: Consolidated test data into `renamer/test/datasets/`
- **Total Tests**: 560 tests (1 skipped), all passing
---
### Documentation Improvements
#### Added
- **ENGINEERING_GUIDE.md**: Comprehensive 900+ line technical reference
- **CHANGELOG.md**: This file
#### Changed
- **CLAUDE.md**: Streamlined to pointer to ENGINEERING_GUIDE.md
- **AI_AGENT.md**: Marked as deprecated, points to ENGINEERING_GUIDE.md
- **DEVELOP.md**: Streamlined with references to ENGINEERING_GUIDE.md
- **README.md**: Streamlined user guide with references
#### Removed
- Outdated version information from documentation files
- Duplicated content now in ENGINEERING_GUIDE.md
---
### Breaking Changes
#### Cache System
- **Cache key format changed**: Old cache files are invalid
- **Migration**: Users should clear cache: `rm -rf ~/.cache/renamer/`
- **Impact**: No data loss, just cache miss on first run after upgrade
#### Dependencies
- **Added**: mypy>=1.0.0 as dev dependency
---
### Statistics
#### Code Quality Metrics
- **Lines Added**: ~3,497 lines
- Phase 1: ~500 lines (cache subsystem)
- Phase 2: ~2,297 lines (base classes + services + utilities)
- Phase 3: ~200 lines (docstrings)
- Phase 5: ~500 lines (new tests)
- **Lines Removed**: ~290 lines through code duplication elimination
- **Net Gain**: ~3,207 lines of quality code
#### Test Coverage
- **Total Tests**: 560 (was 518)
- **New Tests**: +42 tests (+8%)
- **Pass Rate**: 100% (559 passed, 1 skipped)
#### Architecture Improvements
- ✅ Protocols and ABCs for consistent interfaces
- ✅ Service layer with dependency injection
- ✅ Thread pool for concurrent operations
- ✅ Utility modules for shared logic
- ✅ Command palette for unified access
- ✅ Type hints and mypy integration
- ✅ Comprehensive docstrings
---
## [0.6.0] - 2025-12-31
### Added
- Initial cache subsystem implementation
- Basic service layer structure
- Protocol definitions for extractors
### Changed
- Refactored cache key generation
- Improved error handling
---
## [0.5.10] - Previous Release
### Features
- Dual display modes (technical/catalog)
- TMDB integration with poster display
- Settings configuration UI
- Persistent caching with TTL
- Intelligent file renaming
- Color-coded information display
- Keyboard and mouse navigation
- Help screen with key bindings
---
## Version History Summary
- **0.7.0-dev** (2026-01-01): Major refactoring - code quality, architecture, testing
- **0.6.0** (2025-12-31): Cache improvements, service layer foundation
- **0.5.x**: Settings, caching, catalog mode, poster display
- **0.4.x**: TMDB integration
- **0.3.x**: Enhanced extractors and formatters
- **0.2.x**: Initial TUI with basic metadata
---
## Links
- [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md) - Complete technical documentation
- [REFACTORING_PROGRESS.md](REFACTORING_PROGRESS.md) - Future refactoring plans
- [ToDo.md](ToDo.md) - Current task list
---
**Last Updated**: 2026-01-01

547
CLAUDE.md
View File

@@ -1,537 +1,38 @@
# CLAUDE.md - AI Assistant Reference Guide
# CLAUDE.md - AI Assistant Reference
This document provides comprehensive project information for AI assistants (like Claude) working on the Renamer project.
**Version**: 0.7.0-dev
**Last Updated**: 2026-01-01
## Project Overview
> **📘 All technical documentation has been moved to [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)**
**Renamer** is a sophisticated Terminal User Interface (TUI) application for managing, viewing metadata, and renaming media files. Built with Python and the Textual framework, it provides an interactive, curses-like interface for media collection management.
## For AI Assistants
### Current Version
- **Version**: 0.7.0-dev (in development)
- **Python**: 3.11+
- **Status**: Major refactoring in progress - Phase 1 complete (critical bugs fixed, unified cache subsystem)
Please read **[ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)** for complete project documentation including:
## Project Purpose
- Architecture overview
- Core components
- Development setup
- Testing strategy
- Code standards
- AI assistant instructions
- Release process
Renamer serves two primary use cases:
1. **Technical Mode**: Detailed technical metadata viewing (video tracks, audio streams, codecs, bitrates)
2. **Catalog Mode**: Media library catalog view with TMDB integration (posters, ratings, descriptions, genres)
## Quick Commands
## Architecture Overview
### Core Components
#### Main Application (`renamer/app.py`)
- Main `RenamerApp` class inheriting from Textual's `App`
- Manages TUI layout with split view: file tree (left) and details panel (right)
- Handles keyboard/mouse navigation and user commands
- Coordinates file operations and metadata extraction
- Implements efficient tree updates for file renaming
#### Entry Point (`renamer/main.py`)
- Argument parsing for directory selection
- Application initialization and launch
#### Constants (`renamer/constants.py`)
Defines comprehensive dictionaries:
- `MEDIA_TYPES`: Supported video formats (mkv, avi, mov, mp4, etc.)
- `SOURCE_DICT`: Video source types (WEB-DL, BDRip, BluRay, etc.)
- `FRAME_CLASSES`: Resolution classifications (480p-8K)
- `MOVIE_DB_DICT`: Database identifiers (TMDB, IMDB, Trakt, TVDB)
- `SPECIAL_EDITIONS`: Edition types (Director's Cut, Extended, etc.)
### Extractor System (`renamer/extractors/`)
Modular architecture for gathering metadata from multiple sources:
#### Core Extractors
1. **MediaInfoExtractor** (`mediainfo_extractor.py`)
- Uses PyMediaInfo library
- Extracts detailed track information (video, audio, subtitle)
- Provides codec, bitrate, frame rate, resolution data
2. **FilenameExtractor** (`filename_extractor.py`)
- Parses metadata from filename patterns
- Detects year, resolution, source, codecs, edition info
- Uses regex patterns to extract structured data
3. **MetadataExtractor** (`metadata_extractor.py`)
- Reads embedded metadata using Mutagen
- Extracts tags, container format info
4. **FileInfoExtractor** (`fileinfo_extractor.py`)
- Basic file information (size, dates, permissions)
- MIME type detection via python-magic
5. **TMDBExtractor** (`tmdb_extractor.py`)
- The Movie Database API integration
- Fetches title, year, ratings, overview, genres, poster
- Supports movie and TV show data
6. **DefaultExtractor** (`default_extractor.py`)
- Fallback extractor providing minimal data
#### Extractor Coordinator (`extractor.py`)
- `MediaExtractor` class orchestrates all extractors
- Provides unified `get()` interface for data retrieval
- Caching support via decorators
### Formatter System (`renamer/formatters/`)
Transforms raw extracted data into formatted display strings:
#### Specialized Formatters
1. **MediaFormatter** (`media_formatter.py`)
- Main formatter coordinating all format operations
- Mode-aware (technical vs catalog)
- Applies color coding and styling
2. **CatalogFormatter** (`catalog_formatter.py`)
- Formats catalog mode display
- Renders TMDB data, ratings, genres, overview
- Terminal image display for posters (rich-pixels)
3. **TrackFormatter** (`track_formatter.py`)
- Video/audio/subtitle track formatting
- Color-coded track information
4. **ProposedNameFormatter** (`proposed_name_formatter.py`)
- Generates intelligent rename suggestions
- Pattern: `Title (Year) [Resolution Source Edition].ext`
- Sanitizes filenames (removes invalid characters)
5. **Utility Formatters**
- `SizeFormatter`: Human-readable file sizes
- `DateFormatter`: Timestamp formatting
- `DurationFormatter`: Duration in HH:MM:SS
- `ResolutionFormatter`: Resolution display
- `TextFormatter`: Text styling utilities
- `ExtensionFormatter`: File extension handling
- `SpecialInfoFormatter`: Edition/source formatting
- `HelperFormatter`: General formatting helpers
### Settings & Caching
#### Settings System (`renamer/settings.py`)
- JSON configuration stored in `~/.config/renamer/config.json`
- Configurable options:
- `mode`: "technical" or "catalog"
- `cache_ttl_extractors`: 21600s (6 hours)
- `cache_ttl_tmdb`: 21600s (6 hours)
- `cache_ttl_posters`: 2592000s (30 days)
- Automatic save/load with defaults
#### Cache System (`renamer/cache.py`)
- File-based cache with TTL support
- Location: `~/.cache/renamer/`
- Subdirectory organization (tmdb/, posters/, extractors/, general/)
- Supports JSON and pickle serialization
- In-memory cache for performance
- Image caching for TMDB posters
- Automatic expiration and cleanup
#### Unified Cache Subsystem (`renamer/cache/`)
**NEW in v0.7.0**: Complete cache subsystem rewrite with modular architecture.
**Directory Structure**:
```
renamer/cache/
├── __init__.py # Module exports and convenience functions
├── core.py # Core Cache class (thread-safe with RLock)
├── types.py # Type definitions (CacheEntry, CacheStats)
├── strategies.py # Cache key generation strategies
├── managers.py # CacheManager for operations
└── decorators.py # Enhanced cache decorators
```
**Cache Key Strategies**:
- `FilepathMethodStrategy`: For extractor methods (`extractor_{hash}_{method}`)
- `APIRequestStrategy`: For API responses (`api_{service}_{hash}`)
- `SimpleKeyStrategy`: For simple prefix+id patterns
- `CustomStrategy`: User-defined key generation
**Cache Decorators**:
- `@cached(strategy, ttl)`: Generic caching with configurable strategy
- `@cached_method(ttl)`: Method caching (backward compatible)
- `@cached_api(service, ttl)`: API response caching
- `@cached_property(ttl)`: Cached property decorator
**Cache Manager Operations**:
- `clear_all()`: Remove all cache entries
- `clear_by_prefix(prefix)`: Clear specific cache type (tmdb_, extractor_, poster_)
- `clear_expired()`: Remove expired entries
- `get_stats()`: Comprehensive statistics
- `clear_file_cache(file_path)`: Clear cache for specific file
- `compact_cache()`: Remove empty directories
**Command Palette Integration**:
- Access cache commands via Ctrl+P
- 7 commands: View Stats, Clear All, Clear Extractors, Clear TMDB, Clear Posters, Clear Expired, Compact
- Integrated using `CacheCommandProvider`
**Thread Safety**:
- All operations protected by `threading.RLock`
- Safe for concurrent extractor access
### Error Handling & Logging
**Exception Handling** (v0.7.0):
- No bare `except:` clauses (all use specific exception types)
- Language code conversions catch `(LookupError, ValueError, AttributeError)`
- Network errors catch `(requests.RequestException, ValueError)`
- All exceptions logged with context
**Logging Strategy**:
- **Warning level**: Network failures, API errors, MediaInfo parse failures (user-facing issues)
- **Debug level**: Language code conversions, metadata reads, MIME detection (technical details)
- **Error level**: Formatter application failures (logged via `FormatterApplier`)
**Logger Usage**:
```python
import logging
logger = logging.getLogger(__name__)
# Examples
logger.warning(f"TMDB API request failed for {url}: {e}")
logger.debug(f"Invalid language code '{lang_code}': {e}")
logger.error(f"Error applying {formatter.__name__}: {e}")
```
**Files with Logging**:
- `renamer/extractors/filename_extractor.py` - Language code conversion errors
- `renamer/extractors/mediainfo_extractor.py` - MediaInfo parse and language errors
- `renamer/extractors/metadata_extractor.py` - Mutagen and MIME detection errors
- `renamer/extractors/tmdb_extractor.py` - API request and poster download errors
- `renamer/formatters/formatter.py` - Formatter application errors
- `renamer/cache/core.py` - Cache operation errors
### UI Screens (`renamer/screens.py`)
Additional UI screens for user interaction:
1. **OpenScreen**: Directory selection dialog with validation
2. **HelpScreen**: Comprehensive help with key bindings
3. **RenameConfirmScreen**: File rename confirmation with error handling
4. **SettingsScreen**: Settings configuration interface
### Development Tools
#### Version Management (`renamer/bump.py`)
- `bump-version` command
- Auto-increments patch version in `pyproject.toml`
#### Release Automation (`renamer/release.py`)
- `release` command
- Runs: version bump → dependency sync → package build
## Key Features
### Current Features (v0.5.10)
- Recursive directory scanning for video files
- Tree view with expand/collapse navigation
- Dual-mode display (technical/catalog)
- Detailed metadata extraction from multiple sources
- Intelligent file renaming with preview
- TMDB integration with poster display
- Settings configuration UI
- Persistent caching with TTL
- Loading indicators and error handling
- Confirmation dialogs for file operations
- Color-coded information display
- Keyboard and mouse navigation
### Keyboard Commands
- `q`: Quit application
- `o`: Open directory
- `s`: Scan/rescan directory
- `f`: Refresh metadata for selected file
- `r`: Rename file with proposed name
- `p`: Toggle tree expansion
- `m`: Toggle mode (technical/catalog)
- `h`: Show help screen
- `ctrl+s`: Open settings
- `ctrl+p`: Open command palette
### Command Palette (v0.7.0)
**Access**: Press `ctrl+p` to open the command palette
**Available Commands**:
- **System Commands** (built-in from Textual):
- Toggle theme
- Show key bindings
- Other system operations
- **Cache Commands** (from `CacheCommandProvider`):
- Cache: View Statistics
- Cache: Clear All
- Cache: Clear Extractors
- Cache: Clear TMDB
- Cache: Clear Posters
- Cache: Clear Expired
- Cache: Compact
**Implementation**:
- Command palette extends built-in Textual commands
- Uses `COMMANDS = App.COMMANDS | {CacheCommandProvider}` pattern
- Future: Will add app operation commands (open, scan, rename, etc.)
## Technology Stack
### Core Dependencies
- **textual** (≥6.11.0): TUI framework
- **pymediainfo** (≥6.0.0): Media track analysis
- **mutagen** (≥1.47.0): Embedded metadata
- **python-magic** (≥0.4.27): MIME detection
- **langcodes** (≥3.5.1): Language code handling
- **requests** (≥2.31.0): HTTP for TMDB API
- **rich-pixels** (≥1.0.0): Terminal image display
- **pytest** (≥7.0.0): Testing framework
### System Requirements
- Python 3.11 or higher
- UV package manager (recommended)
- MediaInfo library (system dependency for pymediainfo)
## Development Workflow
### Setup
```bash
# Install UV
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone and sync
cd /path/to/renamer
uv sync
# Run from source
uv run python renamer/main.py [directory]
uv sync --extra dev # Setup
uv run pytest # Test
uv run renamer [dir] # Run
```
### Development Commands
```bash
uv run renamer # Run installed version
uv run pytest # Run tests
uv run bump-version # Increment version
uv run release # Build release (bump + sync + build)
uv build # Build wheel/tarball
uv tool install . # Install as global tool
```
## Essential Principles
### Debugging
```bash
# Enable formatter logging
FORMATTER_LOG=1 uv run renamer /path/to/directory
# Creates formatter.log with detailed call traces
```
### Testing
- Test files in `renamer/test/`
- Sample filenames in `test/filenames.txt` and `test/test_filenames.txt`
- Test cases in `test/test_cases.json`
- Run with: `uv run pytest`
## Code Style & Standards
### Python Standards
- Type hints encouraged
- PEP 8 style guidelines
- Descriptive variable/function names
- Docstrings for classes and functions
- Pathlib for file operations
- Proper exception handling
### Architecture Patterns
- Extractor pattern: Each extractor focuses on one data source
- Formatter pattern: Formatters handle display logic, extractors handle data
- Separation of concerns: Data extraction → formatting → display
- Dependency injection: Extractors and formatters are modular
- Configuration management: Settings class for all config
### Best Practices
- Avoid over-engineering (keep solutions simple)
- Only add features when explicitly requested
- Validate at system boundaries only (user input, external APIs)
- Don't add unnecessary error handling for internal code
- Trust framework guarantees
- Delete unused code completely (no backwards-compat hacks)
## File Operations
### Directory Scanning
- Recursive search for supported video formats
- File tree representation with hierarchical structure
- Efficient tree updates on file operations
### File Renaming
1. Select file in tree
2. Press `r` to initiate rename
3. Review proposed name (shows current vs proposed)
4. Confirm with `y` or cancel with `n`
5. Tree updates in-place without full reload
### Metadata Caching
- First extraction cached for 6 hours
- TMDB data cached for 6 hours
- Posters cached for 30 days
- Force refresh with `f` command
- Cache invalidated on file rename
## API Integration
### TMDB API
- API key stored in `renamer/secrets.py`
- Search endpoint for movie lookup by title/year
- Image base URL for poster downloads
- Handles rate limiting and errors gracefully
- Falls back to filename data if API unavailable
## Project Files
### Documentation
- `README.md`: User-facing documentation
- `AI_AGENT.md`: AI agent instructions (legacy)
- `DEVELOP.md`: Developer guide
- `INSTALL.md`: Installation instructions
- `ToDo.md`: Task tracking
- `CLAUDE.md`: This file (AI assistant reference)
### Configuration
- `pyproject.toml`: Project metadata, dependencies, build config
- `uv.lock`: Locked dependencies
### Build Artifacts
- `dist/`: Built wheels and tarballs
- `build/`: Build intermediates
- `renamer.egg-info/`: Package metadata
## Known Issues & Limitations
### Current Limitations
- TMDB API requires internet connection
- Poster display requires terminal with image support
- Some special characters in filenames need sanitization
- Large directories may have initial scan delay
### Future Enhancements (See ToDo.md)
- Metadata editing capabilities
- Batch rename operations
- Advanced search and filtering
- Undo/redo functionality
- Plugin system for custom extractors/formatters
- Full genre name expansion (currently shows codes)
- Improved poster quality/display optimization
## Contributing Guidelines
### Making Changes
1. Read existing code and understand architecture
2. Check `ToDo.md` for pending tasks
3. Implement features incrementally
4. Test with real media files
5. Ensure backward compatibility
6. Update documentation
7. Update tests as needed
8. Run `uv run release` before committing
### Commit Standards
- Clear, descriptive commit messages
- Focus on "why" not "what"
- One logical change per commit
- Reference related issues/tasks
### Code Review Checklist
- [ ] Follows PEP 8 style
- [ ] Type hints added where appropriate
- [ ] No unnecessary complexity
- [ ] Tests pass (`uv run pytest`)
- [ ] Documentation updated
- [ ] No security vulnerabilities (XSS, injection, etc.)
- [ ] Efficient resource usage (no memory leaks)
## Security Considerations
- Input sanitization for filenames (see `ProposedNameFormatter`)
- No shell command injection risks
- Safe file operations (pathlib, proper error handling)
- TMDB API key should not be committed (stored in `secrets.py`)
- Cache directory permissions should be user-only
## Performance Notes
- In-memory cache reduces repeated extraction overhead
- File cache persists across sessions
- Tree updates optimized for rename operations
- TMDB requests throttled to respect API limits
- Large directory scans use async/await patterns
## Special Notes for AI Assistants
### When Adding Features
1. **Always read relevant files first** - Never modify code you haven't read
2. **Check ToDo.md** - See if feature is already planned
3. **Understand existing patterns** - Follow established architecture
4. **Test with real files** - Use actual media files for testing
5. **Update documentation** - Keep docs in sync with code
### When Debugging
1. **Enable formatter logging** - Use `FORMATTER_LOG=1` for detailed traces
2. **Check cache state** - Clear cache if stale data suspected
3. **Verify file permissions** - Ensure read/write access
4. **Test with sample filenames** - Use test fixtures first
### When Refactoring
1. **Maintain backward compatibility** - Unless explicitly breaking change
2. **Update tests** - Reflect refactored code
3. **Check all formatters** - Formatting is centralized
4. **Verify extractor chain** - Ensure data flow intact
### Common Pitfalls to Avoid
- Don't create new files unless absolutely necessary (edit existing)
- Don't add features beyond what's requested
- Don't over-engineer solutions
- Don't skip testing with real files
- Don't forget to update version number for releases
- Don't commit secrets or API keys
- Don't use deprecated Textual APIs
## Project History
### Evolution
- Started as simple file renamer
- Added metadata extraction (MediaInfo, Mutagen)
- Expanded to TUI with Textual framework
- Added filename parsing intelligence
- Integrated TMDB for catalog mode
- Added settings and caching system
- Implemented poster display with rich-pixels
- Added dual-mode interface (technical/catalog)
### Version Milestones
- 0.2.x: Initial TUI with basic metadata
- 0.3.x: Enhanced extractors and formatters
- 0.4.x: Added TMDB integration
- 0.5.x: Settings, caching, catalog mode, poster display
## Resources
### External Documentation
- [Textual Documentation](https://textual.textualize.io/)
- [PyMediaInfo Documentation](https://pymediainfo.readthedocs.io/)
- [Mutagen Documentation](https://mutagen.readthedocs.io/)
- [TMDB API Documentation](https://developers.themoviedb.org/3)
- [UV Documentation](https://docs.astral.sh/uv/)
### Internal Documentation
- Main README: User guide and quick start
- DEVELOP.md: Developer setup and debugging
- INSTALL.md: Installation methods
- AI_AGENT.md: Legacy AI instructions (historical)
- ToDo.md: Current task list
1. **Read [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md) first**
2. Read files before modifying
3. Test everything (`uv run pytest`)
4. Follow existing patterns
5. Keep solutions simple
---
**Last Updated**: 2025-12-31
**For AI Assistant**: Claude (Anthropic)
**Project Maintainer**: sha
**Repository**: `/home/sha/bin/renamer`
**Full Documentation**: [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)

View File

@@ -1,220 +1,118 @@
# Developer Guide
This guide contains information for developers working on the Renamer project.
**Version**: 0.7.0-dev
**Last Updated**: 2026-01-01
**Current Version**: 0.5.10
> **📘 For complete development documentation, see [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)**
## Development Setup
### Prerequisites
- Python 3.11+
- UV package manager
### Install UV (if not already installed)
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
### Development Installation
```bash
# Clone the repository
git clone <repository-url>
cd renamer
# Install in development mode with all dependencies
uv sync
# Install the package in editable mode
uv pip install -e .
```
### Running in Development
```bash
# Run directly from source
uv run python renamer/main.py
# Or run with specific directory
uv run python renamer/main.py /path/to/directory
# Or use the installed command
uv run renamer
```
## Development Commands
The project includes several development commands defined in `pyproject.toml`:
### bump-version
Increments the patch version in `pyproject.toml` (e.g., 0.2.6 → 0.2.7).
```bash
uv run bump-version
```
### release
Runs a batch process: bump version, sync dependencies, and build the package.
```bash
uv run release
```
### Other Commands
- `uv sync`: Install/update dependencies
- `uv build`: Build the package
- `uv run pytest`: Run tests
## Debugging
### Formatter Logging
Enable detailed logging for formatter operations:
```bash
FORMATTER_LOG=1 uv run renamer /path/to/directory
```
This creates `formatter.log` in the current directory with:
- Formatter call sequences and ordering
- Input/output values for each formatter
- Caller information (file and line number)
- Any errors during formatting
- Timestamp for each operation
### Cache Inspection
Cache is stored in `~/.cache/renamer/` with subdirectories:
- `extractors/`: Extractor results cache
- `tmdb/`: TMDB API response cache
- `posters/`: Downloaded poster images
- `general/`: General purpose cache
To clear cache:
```bash
rm -rf ~/.cache/renamer/
```
### Settings Location
Settings are stored in `~/.config/renamer/config.json`:
```json
{
"mode": "technical",
"cache_ttl_extractors": 21600,
"cache_ttl_tmdb": 21600,
"cache_ttl_posters": 2592000
}
```
## Architecture
The application uses a modular architecture with clear separation of concerns:
### Core Application (`renamer/`)
- **app.py**: Main RenamerApp class (Textual App), tree management, file operations
- **main.py**: Entry point with argument parsing
- **constants.py**: Comprehensive constants (media types, sources, resolutions, editions)
- **settings.py**: Settings management with JSON persistence (`~/.config/renamer/`)
- **cache.py**: File-based caching system with TTL support (`~/.cache/renamer/`)
- **secrets.py**: API keys and secrets (TMDB)
### Extractors (`renamer/extractors/`)
Data extraction from multiple sources:
- **extractor.py**: MediaExtractor coordinator class
- **mediainfo_extractor.py**: PyMediaInfo for detailed track information
- **filename_extractor.py**: Regex-based filename parsing
- **metadata_extractor.py**: Mutagen for embedded metadata
- **fileinfo_extractor.py**: Basic file information (size, dates, MIME)
- **tmdb_extractor.py**: The Movie Database API integration
- **default_extractor.py**: Fallback extractor
### Formatters (`renamer/formatters/`)
Display formatting and rendering:
- **formatter.py**: Base formatter interface
- **media_formatter.py**: Main formatter coordinating all format operations
- **catalog_formatter.py**: Catalog mode display (TMDB data, posters)
- **proposed_name_formatter.py**: Intelligent rename suggestions
- **track_formatter.py**: Video/audio/subtitle track formatting
- **size_formatter.py**: Human-readable file sizes
- **date_formatter.py**: Timestamp formatting
- **duration_formatter.py**: Duration in HH:MM:SS format
- **resolution_formatter.py**: Resolution display
- **extension_formatter.py**: File extension handling
- **special_info_formatter.py**: Edition/source formatting
- **text_formatter.py**: Text styling utilities
- **helper_formatter.py**: General formatting helpers
### Screens (`renamer/screens.py`)
UI screens for user interaction:
- **OpenScreen**: Directory selection with validation
- **HelpScreen**: Comprehensive help with key bindings
- **RenameConfirmScreen**: File rename confirmation with preview
- **SettingsScreen**: Settings configuration UI
### Utilities
- **decorators/caching.py**: Caching decorator for automatic method caching
- **bump.py**: Version bump utility script
- **release.py**: Release automation (bump + sync + build)
## Testing
Run tests with:
```bash
uv run pytest
```
Test files are located in `renamer/test/` with sample filenames in `filenames.txt`.
## Building and Distribution
### Build the Package
```bash
uv build
```
### Install as Tool
```bash
uv tool install .
```
### Uninstall
```bash
uv tool uninstall renamer
```
## Code Style
The project follows Python best practices:
- **PEP 8**: Standard Python style guide
- **Type Hints**: Encouraged where appropriate
- **Docstrings**: For all classes and public methods
- **Descriptive Naming**: Clear variable and function names
- **Pathlib**: For all file operations
- **Error Handling**: Appropriate exception handling at boundaries
Consider using tools like:
- `ruff` for linting and formatting
- `mypy` for type checking
- `black` for consistent formatting
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Run tests: `uv run pytest`
5. Run the release process: `uv run release`
6. Submit a pull request
## Additional Documentation
For comprehensive project information:
- **[README.md](README.md)**: User guide and features
- **[CLAUDE.md](CLAUDE.md)**: Complete AI assistant reference
- **[AI_AGENT.md](AI_AGENT.md)**: AI agent instructions
- **[INSTALL.md](INSTALL.md)**: Installation methods
- **[ToDo.md](ToDo.md)**: Task list and priorities
## Project Resources
- **Cache Directory**: `~/.cache/renamer/`
- **Config Directory**: `~/.config/renamer/`
- **Test Files**: `renamer/test/`
- **Build Output**: `dist/` and `build/`
Quick reference for developers working on the Renamer project.
---
**Last Updated**: 2025-12-31
## Quick Setup
```bash
# Install UV
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone and setup
cd /home/sha/bin/renamer
uv sync --extra dev
```
---
## Essential Commands
```bash
# Run from source
uv run renamer [directory]
# Run tests
uv run pytest
# Run with coverage
uv run pytest --cov=renamer
# Type check
uv run mypy renamer/
# Version bump
uv run bump-version
# Full release
uv run release
# Build distribution
uv build
```
---
## Debugging
```bash
# Enable detailed logging
FORMATTER_LOG=1 uv run renamer /path/to/directory
# Check logs
cat formatter.log
# Clear cache
rm -rf ~/.cache/renamer/
```
---
## Testing
```bash
# All tests
uv run pytest
# Specific file
uv run pytest renamer/test/test_services.py
# Verbose
uv run pytest -xvs
# Generate sample files
uv run python renamer/test/fill_sample_mediafiles.py
```
See [ENGINEERING_GUIDE.md - Testing Strategy](ENGINEERING_GUIDE.md#testing-strategy)
---
## Release Process
```bash
# 1. Bump version
uv run bump-version
# 2. Run full release
uv run release
# 3. Test installation
uv tool install .
# 4. Manual testing
uv run renamer /path/to/test/media
```
See [ENGINEERING_GUIDE.md - Release Process](ENGINEERING_GUIDE.md#release-process)
---
## Documentation
- **[ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)** - Complete technical reference
- **[README.md](README.md)** - User guide
- **[INSTALL.md](INSTALL.md)** - Installation instructions
- **[CHANGELOG.md](CHANGELOG.md)** - Version history
- **[REFACTORING_PROGRESS.md](REFACTORING_PROGRESS.md)** - Future plans
- **[ToDo.md](ToDo.md)** - Current tasks
---
**For complete documentation, see [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)**

944
ENGINEERING_GUIDE.md Normal file
View File

@@ -0,0 +1,944 @@
# Renamer Engineering Guide
**Version**: 0.7.0-dev
**Last Updated**: 2026-01-01
**Python**: 3.11+
**Status**: Active Development
This is the comprehensive technical reference for the Renamer project. It contains all architectural information, implementation details, development workflows, and AI assistant instructions.
---
## Table of Contents
1. [Project Overview](#project-overview)
2. [Architecture](#architecture)
3. [Core Components](#core-components)
4. [Development Setup](#development-setup)
5. [Testing Strategy](#testing-strategy)
6. [Code Standards](#code-standards)
7. [AI Assistant Instructions](#ai-assistant-instructions)
8. [Release Process](#release-process)
---
## Project Overview
### Purpose
Renamer is a sophisticated Terminal User Interface (TUI) application for managing, viewing metadata, and renaming media files. Built with Python and the Textual framework.
**Dual-Mode Operation**:
- **Technical Mode**: Detailed technical metadata (video tracks, audio streams, codecs, bitrates)
- **Catalog Mode**: Media library catalog view with TMDB integration (posters, ratings, descriptions)
### Current Version
- **Version**: 0.7.0-dev (in development)
- **Python**: 3.11+
- **License**: Not specified
- **Repository**: `/home/sha/bin/renamer`
### Technology Stack
#### Core Dependencies
- **textual** (≥6.11.0): TUI framework
- **pymediainfo** (≥6.0.0): Media track analysis
- **mutagen** (≥1.47.0): Embedded metadata
- **python-magic** (≥0.4.27): MIME detection
- **langcodes** (≥3.5.1): Language code handling
- **requests** (≥2.31.0): HTTP for TMDB API
- **rich-pixels** (≥1.0.0): Terminal image display
- **pytest** (≥7.0.0): Testing framework
#### Dev Dependencies
- **mypy** (≥1.0.0): Type checking
#### System Requirements
- Python 3.11 or higher
- UV package manager (recommended)
- MediaInfo library (system dependency)
---
## Architecture
### Architectural Layers
```
┌─────────────────────────────────────────┐
│ TUI Layer (Textual) │
│ app.py, screens.py │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ Service Layer │
│ FileTreeService, MetadataService, │
│ RenameService │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ Extractor Layer │
│ MediaExtractor coordinates: │
│ - FilenameExtractor │
│ - MediaInfoExtractor │
│ - MetadataExtractor │
│ - FileInfoExtractor │
│ - TMDBExtractor │
│ - DefaultExtractor │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ Formatter Layer │
│ FormatterApplier coordinates: │
│ - DataFormatters (size, duration) │
│ - TextFormatters (case, style) │
│ - MarkupFormatters (colors, bold) │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ Utility & Cache Layer │
│ - PatternExtractor │
│ - LanguageCodeExtractor │
│ - FrameClassMatcher │
│ - Unified Cache Subsystem │
└─────────────────────────────────────────┘
```
### Design Patterns
1. **Protocol-Based Architecture**: `DataExtractor` Protocol defines extractor interface
2. **Coordinator Pattern**: `MediaExtractor` coordinates multiple extractors with priority system
3. **Strategy Pattern**: Cache key strategies for different data types
4. **Decorator Pattern**: `@cached_method()` for method-level caching
5. **Service Layer**: Business logic separated from UI
6. **Dependency Injection**: Services receive extractors/formatters as dependencies
---
## Core Components
### 1. Main Application (`renamer/app.py`)
**Class**: `RenamerApp(App)`
**Responsibilities**:
- TUI layout management (split view: file tree + details panel)
- Keyboard/mouse navigation
- Command palette integration (Ctrl+P)
- File operation coordination
- Efficient tree updates
**Key Features**:
- Two command providers: `AppCommandProvider`, `CacheCommandProvider`
- Dual-mode support (technical/catalog)
- Real-time metadata display
### 2. Service Layer (`renamer/services/`)
#### FileTreeService (`file_tree_service.py`)
- Directory scanning and validation
- Recursive tree building with filtering
- Media file detection (based on `MEDIA_TYPES`)
- Permission error handling
- Tree node searching by path
- Directory statistics
#### MetadataService (`metadata_service.py`)
- **Thread pool management** (ThreadPoolExecutor, configurable workers)
- **Thread-safe operations** with Lock
- Concurrent metadata extraction
- **Active extraction tracking** and cancellation
- Cache integration via decorators
- Synchronous and asynchronous modes
- Formatter coordination
- Error handling with callbacks
- Context manager support
#### RenameService (`rename_service.py`)
- Proposed name generation from metadata
- Filename validation and sanitization
- Invalid character removal (cross-platform)
- Reserved name checking (Windows compatibility)
- File conflict detection
- Atomic rename operations
- Dry-run mode
- Callback-based rename with success/error handlers
- Markup tag stripping
### 3. Extractor System (`renamer/extractors/`)
#### Base Protocol (`base.py`)
```python
class DataExtractor(Protocol):
"""Defines standard interface for all extractors"""
def extract_title(self) -> Optional[str]: ...
def extract_year(self) -> Optional[str]: ...
# ... 21 methods total
```
#### MediaExtractor (`extractor.py`)
**Coordinator class** managing priority-based extraction:
**Priority Order Examples**:
- Title: TMDB → Metadata → Filename → Default
- Year: Filename → Default
- Technical info: MediaInfo → Default
- File info: FileInfo → Default
**Usage**:
```python
extractor = MediaExtractor(Path("movie.mkv"))
title = extractor.get("title") # Tries sources in priority order
year = extractor.get("year", source="Filename") # Force specific source
```
#### Specialized Extractors
1. **FilenameExtractor** (`filename_extractor.py`)
- Parses metadata from filename patterns
- Detects year, resolution, source, codecs, edition
- Uses regex patterns and utility classes
- Handles Cyrillic normalization
- Extracts language codes with counts (e.g., "2xUKR_ENG")
2. **MediaInfoExtractor** (`mediainfo_extractor.py`)
- Uses PyMediaInfo library
- Extracts detailed track information
- Provides codec, bitrate, frame rate, resolution
- Frame class matching with tolerances
3. **MetadataExtractor** (`metadata_extractor.py`)
- Uses Mutagen library for embedded tags
- Extracts title, artist, duration
- Falls back to MIME type detection
- Handles multiple container formats
4. **FileInfoExtractor** (`fileinfo_extractor.py`)
- Basic file system information
- Size, modification time, paths
- Extension extraction
- Fast, no external dependencies
5. **TMDBExtractor** (`tmdb_extractor.py`)
- The Movie Database API integration
- Fetches title, year, ratings, overview, genres
- Downloads and caches posters
- Supports movies and TV shows
- Rate limiting and error handling
6. **DefaultExtractor** (`default_extractor.py`)
- Fallback extractor providing default values
- Returns None or empty collections
- Safe final fallback in extractor chain
### 4. Formatter System (`renamer/formatters/`)
#### Base Classes (`base.py`)
- `Formatter`: Base ABC with abstract `format()` method
- `DataFormatter`: For data transformations (sizes, durations, dates)
- `TextFormatter`: For text transformations (case changes)
- `MarkupFormatter`: For visual styling (colors, bold, links)
- `CompositeFormatter`: For chaining multiple formatters
#### FormatterApplier (`formatter.py`)
**Coordinator** ensuring correct formatter order:
**Order**: Data → Text → Markup
**Global Ordering**:
1. Data formatters (size, duration, date, track info)
2. Text formatters (uppercase, lowercase, camelcase)
3. Markup formatters (bold, colors, dim, underline)
**Usage**:
```python
formatters = [SizeFormatter.format_size, TextFormatter.bold]
result = FormatterApplier.apply_formatters(1024, formatters)
# Result: bold("1.00 KB")
```
#### Specialized Formatters
- **MediaFormatter**: Main coordinator, mode-aware (technical/catalog)
- **CatalogFormatter**: TMDB data, ratings, genres, poster display
- **TrackFormatter**: Video/audio/subtitle track formatting with colors
- **ProposedNameFormatter**: Intelligent rename suggestions
- **SizeFormatter**: Human-readable file sizes
- **DurationFormatter**: Duration in HH:MM:SS
- **DateFormatter**: Timestamp formatting
- **ResolutionFormatter**: Resolution display
- **ExtensionFormatter**: File extension handling
- **SpecialInfoFormatter**: Edition/source formatting
- **TextFormatter**: Text styling utilities
### 5. Utility Modules (`renamer/utils/`)
#### PatternExtractor (`pattern_utils.py`)
**Centralized regex pattern matching**:
- Movie database ID extraction (TMDB, IMDB, Trakt, TVDB)
- Year extraction and validation
- Quality indicator detection
- Source indicator detection
- Bracketed content manipulation
- Position finding for year/quality/source
**Example**:
```python
extractor = PatternExtractor()
db_info = extractor.extract_movie_db_ids("[tmdbid-12345]")
# Returns: {'type': 'tmdb', 'id': '12345'}
```
#### LanguageCodeExtractor (`language_utils.py`)
**Language code processing**:
- Extract from brackets: `[UKR_ENG]``['ukr', 'eng']`
- Extract standalone codes from filename
- Handle count patterns: `[2xUKR_ENG]`
- Convert to ISO 639-3 codes
- Skip quality indicators and file extensions
- Format as language counts: `"2ukr,eng"`
**Example**:
```python
extractor = LanguageCodeExtractor()
langs = extractor.extract_from_brackets("[2xUKR_ENG]")
# Returns: ['ukr', 'ukr', 'eng']
```
#### FrameClassMatcher (`frame_utils.py`)
**Resolution/frame class matching**:
- Multi-step matching algorithm
- Height and width tolerance
- Aspect ratio calculation
- Scan type detection (progressive/interlaced)
- Standard resolution checking
- Nominal height/typical widths lookup
**Matching Strategy**:
1. Exact height + width match
2. Height match with aspect ratio validation
3. Closest height match
4. Non-standard quality indicator detection
### 6. Constants (`renamer/constants/`)
**Modular organization** (8 files):
1. **media_constants.py**: `MEDIA_TYPES` - Supported video formats
2. **source_constants.py**: `SOURCE_DICT` - Video source types
3. **frame_constants.py**: `FRAME_CLASSES`, `NON_STANDARD_QUALITY_INDICATORS`
4. **moviedb_constants.py**: `MOVIE_DB_DICT` - Database identifiers
5. **edition_constants.py**: `SPECIAL_EDITIONS` - Edition types
6. **lang_constants.py**: `SKIP_WORDS` - Words to skip in language detection
7. **year_constants.py**: `is_valid_year()`, dynamic year validation
8. **cyrillic_constants.py**: `CYRILLIC_TO_ENGLISH` - Character mappings
**Backward Compatibility**: All constants exported via `__init__.py`
### 7. Cache Subsystem (`renamer/cache/`)
**Unified, modular architecture**:
```
renamer/cache/
├── __init__.py # Exports and convenience functions
├── core.py # Core Cache class (thread-safe with RLock)
├── types.py # CacheEntry, CacheStats TypedDicts
├── strategies.py # Cache key generation strategies
├── managers.py # CacheManager for operations
└── decorators.py # Enhanced cache decorators
```
#### Cache Key Strategies
- `FilepathMethodStrategy`: For extractor methods
- `APIRequestStrategy`: For API responses
- `SimpleKeyStrategy`: For simple prefix+id patterns
- `CustomStrategy`: User-defined key generation
#### Cache Decorators
```python
@cached_method(ttl=3600) # Method caching
def extract_title(self):
...
@cached_api(service="tmdb", ttl=21600) # API caching
def fetch_movie_data(self, movie_id):
...
```
#### Cache Manager Operations
- `clear_all()`: Remove all cache entries
- `clear_by_prefix(prefix)`: Clear specific cache type
- `clear_expired()`: Remove expired entries
- `get_stats()`: Comprehensive statistics
- `clear_file_cache(file_path)`: Clear cache for specific file
- `compact_cache()`: Remove empty directories
#### Command Palette Integration
Access via Ctrl+P:
- Cache: View Statistics
- Cache: Clear All
- Cache: Clear Extractors / TMDB / Posters
- Cache: Clear Expired / Compact
#### Thread Safety
- All operations protected by `threading.RLock`
- Safe for concurrent extractor access
- Memory cache synchronized with file cache
### 8. UI Screens (`renamer/screens.py`)
1. **OpenScreen**: Directory selection dialog with validation
2. **HelpScreen**: Comprehensive help with key bindings
3. **RenameConfirmScreen**: File rename confirmation with error handling
4. **SettingsScreen**: Settings configuration interface
### 9. Settings System (`renamer/settings.py`)
**Configuration**: `~/.config/renamer/config.json`
**Options**:
```json
{
"mode": "technical", // or "catalog"
"cache_ttl_extractors": 21600, // 6 hours
"cache_ttl_tmdb": 21600, // 6 hours
"cache_ttl_posters": 2592000 // 30 days
}
```
Automatic save/load with defaults.
---
## Development Setup
### Installation
```bash
# Install UV
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone and sync
cd /home/sha/bin/renamer
uv sync
# Install dev dependencies
uv sync --extra dev
# Run from source
uv run python renamer/main.py [directory]
```
### Development Commands
```bash
# Run installed version
uv run renamer [directory]
# Run tests
uv run pytest
# Run tests with coverage
uv run pytest --cov=renamer
# Type checking
uv run mypy renamer/extractors/default_extractor.py
# Version management
uv run bump-version # Increment patch version
uv run release # Bump + sync + build
# Build distribution
uv build # Create wheel and tarball
# Install as global tool
uv tool install .
```
### Debugging
```bash
# Enable formatter logging
FORMATTER_LOG=1 uv run renamer /path/to/directory
# Creates formatter.log with detailed call traces
```
---
## Testing Strategy
### Test Organization
```
renamer/test/
├── datasets/ # Test data
│ ├── filenames/
│ │ ├── filename_patterns.json # 46 test cases
│ │ └── sample_files/ # Legacy reference
│ ├── mediainfo/
│ │ └── frame_class_tests.json # 25 test cases
│ └── sample_mediafiles/ # Generated (in .gitignore)
├── conftest.py # Fixtures and dataset loaders
├── test_cache_subsystem.py # 18 cache tests
├── test_services.py # 30+ service tests
├── test_utils.py # 70+ utility tests
├── test_formatters.py # 40+ formatter tests
├── test_filename_detection.py # Comprehensive filename parsing
├── test_filename_extractor.py # 368 extractor tests
├── test_mediainfo_*.py # MediaInfo tests
├── test_fileinfo_extractor.py # File info tests
└── test_metadata_extractor.py # Metadata tests
```
### Test Statistics
- **Total Tests**: 560 (1 skipped)
- **Service Layer**: 30+ tests
- **Utilities**: 70+ tests
- **Formatters**: 40+ tests
- **Extractors**: 400+ tests
- **Cache**: 18 tests
### Sample File Generation
```bash
# Generate 46 test files from filename_patterns.json
uv run python renamer/test/fill_sample_mediafiles.py
```
### Test Fixtures
```python
# Load test datasets
patterns = load_filename_patterns()
frame_tests = load_frame_class_tests()
dataset = load_dataset("custom_name")
file_path = get_test_file_path("movie.mkv")
```
### Running Tests
```bash
# All tests
uv run pytest
# Specific test file
uv run pytest renamer/test/test_services.py
# With verbose output
uv run pytest -xvs
# With coverage
uv run pytest --cov=renamer --cov-report=html
```
---
## Code Standards
### Python Standards
- **Version**: Python 3.11+
- **Style**: PEP 8 guidelines
- **Type Hints**: Encouraged for all public APIs
- **Docstrings**: Google-style format
- **Pathlib**: For all file operations
- **Exception Handling**: Specific exceptions (no bare `except:`)
### Docstring Format
```python
def example_function(param1: int, param2: str) -> bool:
"""Brief description of function.
Longer description if needed, explaining behavior,
edge cases, or important details.
Args:
param1: Description of param1
param2: Description of param2
Returns:
Description of return value
Raises:
ValueError: When param1 is negative
Example:
>>> example_function(5, "test")
True
"""
pass
```
### Type Hints
```python
from typing import Optional
# Function type hints
def extract_title(self) -> Optional[str]:
...
# Union types (Python 3.10+)
def extract_movie_db(self) -> list[str] | None:
...
# Generic types
def extract_tracks(self) -> list[dict]:
...
```
### Logging Strategy
**Levels**:
- **Debug**: Language code conversions, metadata reads, MIME detection
- **Warning**: Network failures, API errors, MediaInfo parse failures
- **Error**: Formatter application failures
**Usage**:
```python
import logging
logger = logging.getLogger(__name__)
logger.debug(f"Converted {lang_code} to {iso3_code}")
logger.warning(f"TMDB API request failed: {e}")
logger.error(f"Error applying {formatter.__name__}: {e}")
```
### Error Handling
**Guidelines**:
- Catch specific exceptions: `(LookupError, ValueError, AttributeError)`
- Log all caught exceptions with context
- Network errors: `(requests.RequestException, ValueError)`
- Always close file handles (use context managers)
**Example**:
```python
try:
lang_obj = langcodes.Language.get(lang_code.lower())
return lang_obj.to_alpha3()
except (LookupError, ValueError, AttributeError) as e:
logger.debug(f"Invalid language code '{lang_code}': {e}")
return None
```
### Architecture Patterns
1. **Extractor Pattern**: Each extractor focuses on one data source
2. **Formatter Pattern**: Formatters handle display logic, extractors handle data
3. **Separation of Concerns**: Data extraction → formatting → display
4. **Dependency Injection**: Extractors and formatters are modular
5. **Configuration Management**: Settings class for all config
### Best Practices
- **Simplicity**: Avoid over-engineering, keep solutions simple
- **Minimal Changes**: Only modify what's explicitly requested
- **Validation**: Only at system boundaries (user input, external APIs)
- **Trust Internal Code**: Don't add unnecessary error handling
- **Delete Unused Code**: No backwards-compatibility hacks
- **No Premature Abstraction**: Three similar lines > premature abstraction
---
## AI Assistant Instructions
### Core Principles
1. **Read Before Modify**: Always read files before suggesting modifications
2. **Follow Existing Patterns**: Understand established architecture before changes
3. **Test Everything**: Run `uv run pytest` after all changes
4. **Simplicity First**: Avoid over-engineering solutions
5. **Document Changes**: Update relevant documentation
### When Adding Features
1. Read existing code and understand architecture
2. Check `REFACTORING_PROGRESS.md` for pending tasks
3. Implement features incrementally
4. Test with real media files
5. Ensure backward compatibility
6. Update documentation
7. Update tests as needed
8. Run `uv run release` before committing
### When Debugging
1. Enable formatter logging: `FORMATTER_LOG=1`
2. Check cache state (clear if stale data suspected)
3. Verify file permissions
4. Test with sample filenames first
5. Check logs in `formatter.log`
### When Refactoring
1. Maintain backward compatibility unless explicitly breaking
2. Update tests to reflect refactored code
3. Check all formatters (formatting is centralized)
4. Verify extractor chain (ensure data flow intact)
5. Run full test suite
### Common Pitfalls to Avoid
- ❌ Don't create new files unless absolutely necessary
- ❌ Don't add features beyond what's requested
- ❌ Don't skip testing with real files
- ❌ Don't forget to update version number for releases
- ❌ Don't commit secrets or API keys
- ❌ Don't use deprecated Textual APIs
- ❌ Don't use bare `except:` clauses
- ❌ Don't use command-line tools when specialized tools exist
### Tool Usage
- **Read files**: Use `Read` tool, not `cat`
- **Edit files**: Use `Edit` tool, not `sed`
- **Write files**: Use `Write` tool, not `echo >>`
- **Search files**: Use `Glob` tool, not `find`
- **Search content**: Use `Grep` tool, not `grep`
- **Run commands**: Use `Bash` tool for terminal operations only
### Git Workflow
**Commit Standards**:
- Clear, descriptive messages
- Focus on "why" not "what"
- One logical change per commit
**Commit Message Format**:
```
type: Brief description (imperative mood)
Longer explanation if needed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
```
**Safety Protocol**:
- ❌ NEVER update git config
- ❌ NEVER run destructive commands without explicit request
- ❌ NEVER skip hooks (--no-verify, --no-gpg-sign)
- ❌ NEVER force push to main/master
- ❌ Avoid `git commit --amend` unless conditions met
### Creating Pull Requests
1. Run `git status`, `git diff`, `git log` to understand changes
2. Analyze ALL commits that will be included
3. Draft comprehensive PR summary
4. Create PR using:
```bash
gh pr create --title "Title" --body "$(cat <<'EOF'
## Summary
- Bullet points of changes
## Test plan
- Testing checklist
🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"
```
---
## Release Process
### Version Management
**Version Scheme**: SemVer (MAJOR.MINOR.PATCH)
**Commands**:
```bash
# Bump patch version (0.6.0 → 0.6.1)
uv run bump-version
# Full release process
uv run release # Bump + sync + build
```
### Release Checklist
- [ ] All tests passing: `uv run pytest`
- [ ] Type checking passes: `uv run mypy renamer/`
- [ ] Documentation updated (CHANGELOG.md, README.md)
- [ ] Version bumped in `pyproject.toml`
- [ ] Dependencies synced: `uv sync`
- [ ] Build successful: `uv build`
- [ ] Install test: `uv tool install .`
- [ ] Manual testing with real media files
### Build Artifacts
```
dist/
├── renamer-0.7.0-py3-none-any.whl # Wheel distribution
└── renamer-0.7.0.tar.gz # Source distribution
```
---
## API Integration
### TMDB API
**Configuration**:
- API key stored in `renamer/secrets.py`
- Base URL: `https://api.themoviedb.org/3/`
- Image base URL for poster downloads
**Endpoints Used**:
- Search: `/search/movie`
- Movie details: `/movie/{id}`
**Rate Limiting**: Handled gracefully with error fallback
**Caching**:
- API responses cached for 6 hours
- Posters cached for 30 days
- Cache location: `~/.cache/renamer/tmdb/`, `~/.cache/renamer/posters/`
---
## File Operations
### Directory Scanning
- Recursive search for supported video formats
- File tree representation with hierarchical structure
- Efficient tree updates on file operations
- Permission error handling
### File Renaming
**Process**:
1. Select file in tree
2. Press `r` to initiate rename
3. Review proposed name (current vs proposed)
4. Confirm with `y` or cancel with `n`
5. Tree updates in-place without full reload
**Proposed Name Format**:
```
Title (Year) [Resolution Source Edition].ext
```
**Sanitization**:
- Invalid characters removed (cross-platform)
- Reserved names checked (Windows compatibility)
- Markup tags stripped
- Length validation
### Metadata Caching
- First extraction cached for 6 hours
- TMDB data cached for 6 hours
- Posters cached for 30 days
- Force refresh with `f` command
- Cache invalidated on file rename
---
## Keyboard Commands
| Key | Action |
|-----|--------|
| `q` | Quit application |
| `o` | Open directory |
| `s` | Scan/rescan directory |
| `f` | Refresh metadata for selected file |
| `r` | Rename file with proposed name |
| `p` | Toggle tree expansion |
| `m` | Toggle mode (technical/catalog) |
| `h` | Show help screen |
| `Ctrl+S` | Open settings |
| `Ctrl+P` | Open command palette |
---
## Known Issues & Limitations
### Current Limitations
- TMDB API requires internet connection
- Poster display requires terminal with image support
- Some special characters in filenames need sanitization
- Large directories may have initial scan delay
### Performance Notes
- In-memory cache reduces repeated extraction overhead
- File cache persists across sessions
- Tree updates optimized for rename operations
- TMDB requests throttled to respect API limits
- Large directory scans use async/await patterns
---
## Security Considerations
- Input sanitization for filenames (see `ProposedNameFormatter`)
- No shell command injection risks
- Safe file operations (pathlib, proper error handling)
- TMDB API key should not be committed (stored in `secrets.py`)
- Cache directory permissions should be user-only
---
## Project History
### Evolution
- Started as simple file renamer
- Added metadata extraction (MediaInfo, Mutagen)
- Expanded to TUI with Textual framework
- Added filename parsing intelligence
- Integrated TMDB for catalog mode
- Added settings and caching system
- Implemented poster display with rich-pixels
- Added dual-mode interface (technical/catalog)
- Phase 1-3 refactoring (2025-12-31 to 2026-01-01)
### Version Milestones
- **0.2.x**: Initial TUI with basic metadata
- **0.3.x**: Enhanced extractors and formatters
- **0.4.x**: Added TMDB integration
- **0.5.x**: Settings, caching, catalog mode, poster display
- **0.6.0**: Cache subsystem, service layer, protocols
- **0.7.0-dev**: Complete refactoring (in progress)
---
## Resources
### External Documentation
- [Textual Documentation](https://textual.textualize.io/)
- [PyMediaInfo Documentation](https://pymediainfo.readthedocs.io/)
- [Mutagen Documentation](https://mutagen.readthedocs.io/)
- [TMDB API Documentation](https://developers.themoviedb.org/3)
- [UV Documentation](https://docs.astral.sh/uv/)
- [Python Type Hints](https://docs.python.org/3/library/typing.html)
- [Mypy Documentation](https://mypy.readthedocs.io/)
### Internal Documentation
- **README.md**: User guide and quick start
- **INSTALL.md**: Installation methods
- **DEVELOP.md**: Developer setup and debugging
- **CHANGELOG.md**: Version history and changes
- **REFACTORING_PROGRESS.md**: Future refactoring plans
- **ToDo.md**: Current task list
---
**Last Updated**: 2026-01-01
**Maintainer**: sha
**For**: AI Assistants and Developers
**Repository**: `/home/sha/bin/renamer`

232
README.md
View File

@@ -1,118 +1,182 @@
# Renamer - Media File Renamer and Metadata Viewer
A powerful terminal-based (TUI) application for managing media collections. Scan directories, view detailed metadata, browse TMDB catalog information with posters, and intelligently rename files. Built with Python and Textual.
**Version**: 0.7.0-dev
**Version**: 0.5.10
A powerful Terminal User Interface (TUI) for managing media collections. View detailed metadata, browse TMDB catalog with posters, and intelligently rename files.
> **📘 For complete documentation, see [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)**
---
## Features
### Core Capabilities
- **Dual Display Modes**: Switch between Technical (codec/track details) and Catalog (TMDB metadata with posters)
- **Recursive Directory Scanning**: Finds all video files in nested directories
- **Tree View Navigation**: Keyboard and mouse support with expand/collapse
- **Multi-Source Metadata**: Combines MediaInfo, filename parsing, embedded tags, and TMDB API
- **Intelligent Renaming**: Proposes standardized names based on extracted metadata
- **Persistent Settings**: Configurable mode and cache TTLs saved to `~/.config/renamer/`
- **Advanced Caching**: File-based cache with TTL (6h extractors, 6h TMDB, 30d posters)
- **Terminal Poster Display**: View movie posters in your terminal using rich-pixels
- **Color-Coded Display**: Visual highlighting for different data types
- **Confirmation Dialogs**: Safe file operations with preview and confirmation
- **Extensible Architecture**: Modular extractor and formatter system for easy extension
- **Dual Display Modes**: Technical (codecs/tracks) or Catalog (TMDB with posters)
- **Multi-Source Metadata**: MediaInfo, filename parsing, embedded tags, TMDB API
- **Intelligent Renaming**: Standardized names from metadata
- **Advanced Caching**: 6h extractors, 6h TMDB, 30d posters
- **Terminal Posters**: View movie posters in your terminal
- **Tree View Navigation**: Keyboard and mouse support
## Installation
---
### Prerequisites
- Python 3.11+
- UV package manager
## Quick Start
### Installation
### Install UV (if not already installed)
```bash
# Install UV
curl -LsSf https://astral.sh/uv/install.sh | sh
```
### Install the Application
```bash
# Clone or download the project
# Install Renamer
cd /path/to/renamer
# Install dependencies and build
uv sync
# Install as a global tool
uv tool install .
```
## Usage
See [INSTALL.md](INSTALL.md) for detailed installation instructions.
### Usage
### Running the App
```bash
# Scan current directory
renamer
# Scan specific directory
renamer /path/to/media/directory
renamer /path/to/media
```
### Keyboard Commands
- **q**: Quit the application
- **o**: Open directory selection dialog
- **s**: Scan/rescan current directory
- **f**: Force refresh metadata for selected file (bypass cache)
- **r**: Rename selected file with proposed name
- **p**: Toggle tree expansion (expand/collapse all)
- **h**: Show help screen
- **^p**: Open command palette (settings, mode toggle)
- **Settings**: Access via action bar (top-right corner)
---
### Navigation
- Use arrow keys to navigate the file tree
- Right arrow: Expand directory
- Left arrow: Collapse directory or go to parent
- Mouse clicks supported
- Select a video file to view its details in the right panel
## Keyboard Commands
### File Renaming
1. Select a media file in the tree
2. Press **r** to initiate rename
3. Review the proposed new name in the confirmation dialog
4. Press **y** to confirm or **n** to cancel
5. The file will be renamed and the tree updated automatically (cache invalidated)
| Key | Action |
|-----|--------|
| `q` | Quit |
| `o` | Open directory |
| `s` | Scan/rescan |
| `f` | Refresh metadata |
| `r` | Rename file |
| `m` | Toggle mode (technical/catalog) |
| `p` | Toggle tree expansion |
| `h` | Show help |
| `Ctrl+S` | Settings |
| `Ctrl+P` | Command palette |
### Display Modes
- **Technical Mode**: Shows codec details, bitrates, track information, resolutions
- **Catalog Mode**: Shows TMDB data including title, year, rating, overview, genres, and poster
- Toggle between modes via Settings menu or command palette (^p)
---
## Display Modes
### Technical Mode
- Video tracks (codec, bitrate, resolution, frame rate)
- Audio tracks (codec, channels, sample rate, language)
- Subtitle tracks (format, language)
- File information (size, modification time, path)
### Catalog Mode
- TMDB title, year, rating
- Overview/description
- Genres
- Poster image (if terminal supports)
- Technical metadata
Toggle with `m` key.
---
## File Renaming
**Proposed Format**: `Title (Year) [Resolution Source Edition].ext`
**Example**: `The Matrix (1999) [1080p BluRay].mkv`
1. Press `r` on selected file
2. Review proposed name
3. Confirm with `y` or cancel with `n`
---
## Configuration
**Location**: `~/.config/renamer/config.json`
```json
{
"mode": "technical",
"cache_ttl_extractors": 21600,
"cache_ttl_tmdb": 21600,
"cache_ttl_posters": 2592000
}
```
Access via `Ctrl+S` or edit file directly.
---
## Requirements
- **Python**: 3.11+
- **UV**: Package manager
- **MediaInfo**: System library (for technical metadata)
- **Internet**: For TMDB catalog mode
---
## Project Structure
```
renamer/
├── app.py # Main TUI application
├── services/ # Business logic
├── extractors/ # Metadata extraction
├── formatters/ # Display formatting
├── utils/ # Shared utilities
├── cache/ # Caching subsystem
└── constants/ # Configuration constants
```
See [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md) for complete architecture documentation.
---
## Development
For development setup, architecture details, debugging information, and contribution guidelines, see [DEVELOP.md](DEVELOP.md).
```bash
# Setup
uv sync --extra dev
## Supported Video Formats
- .mkv
- .avi
- .mov
- .mp4
- .wmv
- .flv
- .webm
- .m4v
- .3gp
- .ogv
# Run tests
uv run pytest
## Dependencies
- **textual** ≥6.11.0: TUI framework
- **pymediainfo** ≥6.0.0: Detailed media track information
- **mutagen** ≥1.47.0: Embedded metadata extraction
- **python-magic** ≥0.4.27: MIME type detection
- **langcodes** ≥3.5.1: Language code handling
- **requests** ≥2.31.0: HTTP client for TMDB API
- **rich-pixels** ≥1.0.0: Terminal image display
- **pytest** ≥7.0.0: Testing framework
# Run from source
uv run renamer [directory]
```
### System Requirements
- **Python**: 3.11 or higher
- **MediaInfo Library**: System dependency for pymediainfo
- Ubuntu/Debian: `sudo apt install libmediainfo-dev`
- Fedora/CentOS: `sudo dnf install libmediainfo-devel`
- Arch Linux: `sudo pacman -S libmediainfo`
- macOS/Windows: Automatically handled by pymediainfo
See [DEVELOP.md](DEVELOP.md) for development documentation.
---
## Documentation
- **[ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)** - Complete technical reference
- **[INSTALL.md](INSTALL.md)** - Installation instructions
- **[DEVELOP.md](DEVELOP.md)** - Development guide
- **[CHANGELOG.md](CHANGELOG.md)** - Version history
- **[CLAUDE.md](CLAUDE.md)** - AI assistant reference
---
## License
Not specified
---
## Credits
- Built with [Textual](https://textual.textualize.io/)
- Metadata from [MediaInfo](https://mediaarea.net/en/MediaInfo)
- Catalog data from [TMDB](https://www.themoviedb.org/)
---
**For complete documentation, see [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)**

File diff suppressed because it is too large Load Diff

272
ToDo.md
View File

@@ -1,135 +1,165 @@
Project: Media File Renamer and Metadata Viewer (Python TUI with Textual)
# Renamer - Future Tasks
**Current Version**: 0.5.10
**Version**: 0.7.0-dev
**Last Updated**: 2026-01-01
## TODO Steps:
1. ✅ Set up Python project structure with UV package manager
2. ✅ Install dependencies: textual, mutagen, pymediainfo, python-magic, pathlib for file handling
3. ✅ Implement recursive directory scanning for video files (*.mkv, *.avi, *.mov, *.mp4, *.wmv, *.flv, *.webm, etc.)
4. ✅ Detect real media container type using mutagen and python-magic
5. ✅ Create Textual TUI application with split layout (left: file tree, right: file details)
6. ✅ Implement file tree display with navigation (keyboard arrows, mouse support)
7. ✅ Add bottom command bar with 'quit', 'open directory', 'scan' commands
8. ✅ Display file details on right side: file size, extension from filename, extension from metadata, file date
9. ✅ Add functionality to select files in the tree and update right panel
10. ✅ Implement detailed metadata display including video/audio/subtitle tracks with colors
11. ✅ Add custom tree styling with file icons and colored guides
12. ✅ Add scrollable details panel
13. ✅ Handle markup escaping for file names with brackets
14. ✅ Implement file renaming functionality with confirmation dialog
15. ✅ Add proposed name generation based on metadata extraction
16. ✅ Add help screen with key bindings and usage information
17. ✅ Add tree expansion/collapse toggle functionality
18. ✅ Add file refresh functionality to reload metadata for selected file
19. ✅ Optimize tree updates to avoid full reloads after renaming
20. ✅ Add loading indicators for metadata extraction
21. ✅ Add error handling for file operations and metadata extraction
22. 🔄 Implement blue highlighting for changed parts in proposed filename display (show differences between current and proposed names)
23. 🔄 Implement build script to exclude dev commands (bump-version, release) from distributed package
24. 📋 Implement metadata editing capabilities (future enhancement)
25. 📋 Add batch rename operations (future enhancement)
27. 📋 Add advanced search and filtering capabilities (future enhancement)
28. 📋 Implement undo/redo functionality for file operations (future enhancement)
> **📋 For completed work, see [CHANGELOG.md](CHANGELOG.md)**
>
> **📋 For refactoring plans, see [REFACTORING_PROGRESS.md](REFACTORING_PROGRESS.md)**
This file tracks future feature enhancements and improvements.
---
## Media Catalog Mode Implementation Plan
**New big app evolution step: Add media catalog mode with settings, caching, and enhanced TMDB display.**
### Phase 1: Settings Management Foundation
1. ✅ Create settings module (`renamer/settings.py`) for JSON config in `~/.config/renamer/config.json` with schema: mode, cache TTLs
2. ✅ Integrate settings into app startup (load/save on launch/exit)
3. ✅ Add settings window to UI with fields for mode and TTLs
4. ✅ Add "Open Settings" command to command panel
5. ✅ Order setting menu item in the action bar by right side, close to the sysytem menu item ^p palette
### Phase 2: Mode Toggle and UI Switching
5. ✅ Add "Toggle Mode" command to switch between "technical" and "catalog" modes
6. ✅ Modify right pane for mode-aware display (technical vs catalog info)
7. ✅ Persist and restore mode state from settings
### Phase 3: Caching System
8. ✅ Create caching module (`renamer/cache.py`) for file-based cache with TTL support
9. ✅ Integrate caching into extractors (check cache first, store results)
10. ✅ Add refresh command to force re-extraction and cache update
11. ✅ Handle cache cleanup on file rename (invalidate old filename)
### Phase 4: Media Catalog Display
12. ✅ Update TMDB extractor for catalog data: title, year, duration, rates, overview, genres codes, poster_path
13. ✅ Create catalog formatter (`formatters/catalog_formatter.py`) for beautiful display
14. ✅ Integrate catalog display into right pane
### Phase 5: Poster Handling and Display
15. ✅ Add poster caching (images in cache dir with 1-month TTL)
16. ✅ Implement terminal image display (using rich-pixels library)
### Phase 6: Polish and Documentation
17. ✅ Create comprehensive CLAUDE.md for AI assistants
18. ✅ Update all markdown documentation files
19. ✅ Ensure version consistency across all files
### Additional TODOs from Plan
- 📋 Retrieve full movie details from TMDB (currently basic data only)
- 📋 Expand genres to full names instead of codes (currently shows genre IDs)
- 📋 Optimize poster quality and display (improve image rendering)
- 📋 Add TV show support (currently movie-focused)
- 📋 Implement blue highlighting for filename differences
- 📋 Build script to exclude dev commands from distribution
---
## Recently Completed (v0.5.x)
### Version 0.5.10
- Complete media catalog mode implementation
- TMDB integration with poster display
- Settings system with persistent JSON storage
- Advanced caching with TTL support
- Dual-mode display (technical/catalog)
- Settings UI screen
### Version 0.4.x
- Enhanced extractor system
- TMDB extractor foundation
- Improved formatter architecture
### Version 0.3.x
- Expanded metadata extraction
- Multiple formatter types
- Special edition detection
### Version 0.2.x
- Initial TUI implementation
- Basic metadata extraction
- File tree navigation
- Rename functionality
---
## Development Priorities
## Priority Tasks
### High Priority
1. 🔄 Blue highlighting for filename differences (UX improvement)
2. 🔄 Build script for clean distribution packages
3. 📋 Genre ID to name expansion (TMDB lookup)
- [ ] **Phase 4: Refactor to New Architecture**
- Refactor existing extractors to use Protocol
- Refactor existing formatters to use base classes
- Integrate RenamerApp with services
- Update all imports and dependencies
- See [REFACTORING_PROGRESS.md](REFACTORING_PROGRESS.md) for details
- [ ] **Complete Test Coverage**
- Add UI screen tests
- Add app integration tests
- Increase coverage to >90%
### Medium Priority
1. 📋 Batch rename operations
2. 📋 Advanced search/filtering
3. 📋 TV show support
### Low Priority (Future)
1. 📋 Metadata editing
2. 📋 Plugin system
3. 📋 Undo/redo functionality
4. 📋 Configuration profiles
- [ ] **Metadata Editing Capabilities**
- Edit embedded metadata tags
- Batch editing support
- Validation and preview
- [ ] **Batch Rename Operations**
- Select multiple files
- Preview all changes
- Bulk rename with rollback
- [ ] **Advanced Search and Filtering**
- Filter by resolution, codec, year
- Search by TMDB metadata
- Save filter presets
---
**Legend:**
- ✅ Completed
- 🔄 In Progress / Partially Complete
- 📋 Planned / Future Enhancement
## Feature Enhancements
**Last Updated**: 2025-12-31
### UI Improvements
- [ ] **Blue Highlighting for Filename Differences**
- Show changed parts in proposed filename
- Color-code additions, removals, changes
- Side-by-side comparison view
- [ ] **Enhanced Poster Display**
- Optimize image quality
- Support for fanart/backdrops
- Poster cache management UI
- [ ] **Progress Indicators**
- Show scan progress
- Batch operation progress bars
- Background task status
### TMDB Integration
- [ ] **Full Movie Details**
- Cast and crew information
- Production companies
- Budget and revenue data
- Release dates by region
- [ ] **Genre Name Expansion**
- Show full genre names instead of IDs
- Genre-based filtering
- Multi-genre support
- [ ] **TV Show Support**
- Episode and season metadata
- TV show renaming patterns
- Episode numbering detection
- [ ] **Collection/Series Support**
- Detect movie collections
- Group related media
- Collection-based renaming
### Technical Improvements
- [ ] **Undo/Redo Functionality**
- Track file operations history
- Undo renames
- Redo operations
- Operation log
- [ ] **Performance Optimization**
- Lazy loading for large directories
- Virtual scrolling in tree view
- Background metadata extraction
- Smart cache invalidation
### Build and Distribution
- [ ] **Build Script Improvements**
- Exclude dev commands from distribution
- Automated release workflow
- Cross-platform testing
- [ ] **Package Distribution**
- PyPI publication
- Homebrew formula
- AUR package
- Docker image
---
## Potential Future Features
### Advanced Features
- [ ] Subtitle downloading and management
- [ ] NFO file generation
- [ ] Integration with media servers (Plex, Jellyfin, Emby)
- [ ] Watch history tracking
- [ ] Duplicate detection
- [ ] Quality comparison (upgrade detection)
### Integrations
- [ ] Multiple database support (TVDB, Trakt, AniDB)
- [ ] Custom API integrations
- [ ] Local database option (offline mode)
- [ ] Webhook support for automation
### Export/Import
- [ ] Export catalog to CSV/JSON
- [ ] Import rename mappings
- [ ] Backup/restore settings
- [ ] Configuration profiles
---
## Known Issues
See [REFACTORING_PROGRESS.md](REFACTORING_PROGRESS.md) for current limitations and planned fixes.
---
## Contributing
Before working on any task:
1. Check [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md) for architecture details
2. Review [CHANGELOG.md](CHANGELOG.md) for recent changes
3. Read [DEVELOP.md](DEVELOP.md) for development setup
4. Run tests: `uv run pytest`
5. Follow code standards in [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md#code-standards)
---
**Last Updated**: 2026-01-01

View File

@@ -1,6 +0,0 @@
# Decorators package
# Import from new unified cache module
from renamer.cache import cached_method, cached, cached_api, cached_property
# Keep backward compatibility
__all__ = ['cached_method', 'cached', 'cached_api', 'cached_property']

View File

@@ -1,57 +0,0 @@
"""Caching decorators for extractors."""
import hashlib
import json
from pathlib import Path
from typing import Any, Callable, Optional
from renamer.cache import Cache
# Global cache instance
_cache = Cache()
def cached_method(ttl_seconds: int = 3600) -> Callable:
"""Decorator to cache method results with TTL.
Caches the result of a method call using a global file-based cache.
The cache key includes class name, method name, instance identifier, and parameters hash.
Args:
ttl_seconds: Time to live for cached results in seconds (default 1 hour)
Returns:
The decorated method with caching
"""
def decorator(func: Callable) -> Callable:
def wrapper(self, *args, **kwargs) -> Any:
# Generate cache key: class_name.method_name.instance_id.param_hash
class_name = self.__class__.__name__
method_name = func.__name__
# Use instance identifier (file_path for extractors)
instance_id = getattr(self, 'file_path', str(id(self)))
# If instance_id contains path separators, hash it to avoid creating subdirs
if '/' in str(instance_id) or '\\' in str(instance_id):
instance_id = hashlib.md5(str(instance_id).encode('utf-8')).hexdigest()
# Create hash from args and kwargs only if they exist (excluding self)
if args or kwargs:
param_str = json.dumps((args, kwargs), sort_keys=True, default=str)
param_hash = hashlib.md5(param_str.encode('utf-8')).hexdigest()
cache_key = f"{class_name}.{method_name}.{instance_id}.{param_hash}"
else:
cache_key = f"{class_name}.{method_name}.{instance_id}"
# Try to get from cache
cached_result = _cache.get_object(cache_key)
if cached_result is not None:
return cached_result
# Compute result and cache it
result = func(self, *args, **kwargs)
_cache.set_object(cache_key, result, ttl_seconds)
return result
return wrapper
return decorator

View File

@@ -235,19 +235,22 @@ class TestCacheManager:
manager.compact_cache()
class TestBackwardCompatibility:
"""Test backward compatibility with old import paths."""
def test_import_from_decorators(self):
"""Test importing from renamer.decorators still works."""
from renamer.decorators import cached_method
assert cached_method is not None
class TestCachePackageImports:
"""Test cache package import paths."""
def test_import_cache_from_package(self):
"""Test importing Cache from renamer.cache package."""
from renamer.cache import Cache as PackageCache
assert PackageCache is not None
def test_import_decorators_from_cache(self):
"""Test importing decorators from renamer.cache."""
from renamer.cache import cached_method, cached, cached_api, cached_property
assert cached_method is not None
assert cached is not None
assert cached_api is not None
assert cached_property is not None
def test_create_cache_convenience_function(self):
"""Test the create_cache convenience function."""
from renamer.cache import create_cache