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:
208
AI_AGENT.md
208
AI_AGENT.md
@@ -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
225
CHANGELOG.md
Normal 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
547
CLAUDE.md
@@ -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
|
Please read **[ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)** for complete project documentation including:
|
||||||
- **Version**: 0.7.0-dev (in development)
|
|
||||||
- **Python**: 3.11+
|
|
||||||
- **Status**: Major refactoring in progress - Phase 1 complete (critical bugs fixed, unified cache subsystem)
|
|
||||||
|
|
||||||
## Project Purpose
|
- Architecture overview
|
||||||
|
- Core components
|
||||||
|
- Development setup
|
||||||
|
- Testing strategy
|
||||||
|
- Code standards
|
||||||
|
- AI assistant instructions
|
||||||
|
- Release process
|
||||||
|
|
||||||
Renamer serves two primary use cases:
|
## Quick Commands
|
||||||
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)
|
|
||||||
|
|
||||||
## 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
|
```bash
|
||||||
# Install UV
|
uv sync --extra dev # Setup
|
||||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
uv run pytest # Test
|
||||||
|
uv run renamer [dir] # Run
|
||||||
# Clone and sync
|
|
||||||
cd /path/to/renamer
|
|
||||||
uv sync
|
|
||||||
|
|
||||||
# Run from source
|
|
||||||
uv run python renamer/main.py [directory]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Development Commands
|
## Essential Principles
|
||||||
```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
|
|
||||||
```
|
|
||||||
|
|
||||||
### Debugging
|
1. **Read [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md) first**
|
||||||
```bash
|
2. Read files before modifying
|
||||||
# Enable formatter logging
|
3. Test everything (`uv run pytest`)
|
||||||
FORMATTER_LOG=1 uv run renamer /path/to/directory
|
4. Follow existing patterns
|
||||||
# Creates formatter.log with detailed call traces
|
5. Keep solutions simple
|
||||||
```
|
|
||||||
|
|
||||||
### 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
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Last Updated**: 2025-12-31
|
**Full Documentation**: [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)
|
||||||
**For AI Assistant**: Claude (Anthropic)
|
|
||||||
**Project Maintainer**: sha
|
|
||||||
**Repository**: `/home/sha/bin/renamer`
|
|
||||||
|
|||||||
324
DEVELOP.md
324
DEVELOP.md
@@ -1,220 +1,118 @@
|
|||||||
# Developer Guide
|
# 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
|
Quick reference for developers working on the Renamer project.
|
||||||
|
|
||||||
### 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/`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**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
944
ENGINEERING_GUIDE.md
Normal 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
232
README.md
@@ -1,118 +1,182 @@
|
|||||||
# Renamer - Media File Renamer and Metadata Viewer
|
# 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
|
## Features
|
||||||
|
|
||||||
### Core Capabilities
|
- **Dual Display Modes**: Technical (codecs/tracks) or Catalog (TMDB with posters)
|
||||||
- **Dual Display Modes**: Switch between Technical (codec/track details) and Catalog (TMDB metadata with posters)
|
- **Multi-Source Metadata**: MediaInfo, filename parsing, embedded tags, TMDB API
|
||||||
- **Recursive Directory Scanning**: Finds all video files in nested directories
|
- **Intelligent Renaming**: Standardized names from metadata
|
||||||
- **Tree View Navigation**: Keyboard and mouse support with expand/collapse
|
- **Advanced Caching**: 6h extractors, 6h TMDB, 30d posters
|
||||||
- **Multi-Source Metadata**: Combines MediaInfo, filename parsing, embedded tags, and TMDB API
|
- **Terminal Posters**: View movie posters in your terminal
|
||||||
- **Intelligent Renaming**: Proposes standardized names based on extracted metadata
|
- **Tree View Navigation**: Keyboard and mouse support
|
||||||
- **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
|
|
||||||
|
|
||||||
## Installation
|
---
|
||||||
|
|
||||||
### Prerequisites
|
## Quick Start
|
||||||
- Python 3.11+
|
|
||||||
- UV package manager
|
### Installation
|
||||||
|
|
||||||
### Install UV (if not already installed)
|
|
||||||
```bash
|
```bash
|
||||||
|
# Install UV
|
||||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
```
|
|
||||||
|
|
||||||
### Install the Application
|
# Install Renamer
|
||||||
```bash
|
|
||||||
# Clone or download the project
|
|
||||||
cd /path/to/renamer
|
cd /path/to/renamer
|
||||||
|
|
||||||
# Install dependencies and build
|
|
||||||
uv sync
|
uv sync
|
||||||
|
|
||||||
# Install as a global tool
|
|
||||||
uv tool install .
|
uv tool install .
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
See [INSTALL.md](INSTALL.md) for detailed installation instructions.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
### Running the App
|
|
||||||
```bash
|
```bash
|
||||||
# Scan current directory
|
# Scan current directory
|
||||||
renamer
|
renamer
|
||||||
|
|
||||||
# Scan specific directory
|
# 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
|
## Keyboard Commands
|
||||||
- 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
|
|
||||||
|
|
||||||
### File Renaming
|
| Key | Action |
|
||||||
1. Select a media file in the tree
|
|-----|--------|
|
||||||
2. Press **r** to initiate rename
|
| `q` | Quit |
|
||||||
3. Review the proposed new name in the confirmation dialog
|
| `o` | Open directory |
|
||||||
4. Press **y** to confirm or **n** to cancel
|
| `s` | Scan/rescan |
|
||||||
5. The file will be renamed and the tree updated automatically (cache invalidated)
|
| `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
|
## Display Modes
|
||||||
- Toggle between modes via Settings menu or command palette (^p)
|
|
||||||
|
### 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
|
## 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
|
# Run tests
|
||||||
- .mkv
|
uv run pytest
|
||||||
- .avi
|
|
||||||
- .mov
|
|
||||||
- .mp4
|
|
||||||
- .wmv
|
|
||||||
- .flv
|
|
||||||
- .webm
|
|
||||||
- .m4v
|
|
||||||
- .3gp
|
|
||||||
- .ogv
|
|
||||||
|
|
||||||
## Dependencies
|
# Run from source
|
||||||
- **textual** ≥6.11.0: TUI framework
|
uv run renamer [directory]
|
||||||
- **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
|
|
||||||
|
|
||||||
### System Requirements
|
See [DEVELOP.md](DEVELOP.md) for development documentation.
|
||||||
- **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`
|
## Documentation
|
||||||
- Arch Linux: `sudo pacman -S libmediainfo`
|
|
||||||
- macOS/Windows: Automatically handled by pymediainfo
|
- **[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
272
ToDo.md
@@ -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:
|
> **📋 For completed work, see [CHANGELOG.md](CHANGELOG.md)**
|
||||||
1. ✅ Set up Python project structure with UV package manager
|
>
|
||||||
2. ✅ Install dependencies: textual, mutagen, pymediainfo, python-magic, pathlib for file handling
|
> **📋 For refactoring plans, see [REFACTORING_PROGRESS.md](REFACTORING_PROGRESS.md)**
|
||||||
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
|
This file tracks future feature enhancements and improvements.
|
||||||
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)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Media Catalog Mode Implementation Plan
|
## Priority Tasks
|
||||||
|
|
||||||
**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
|
|
||||||
|
|
||||||
### High Priority
|
### High Priority
|
||||||
1. 🔄 Blue highlighting for filename differences (UX improvement)
|
|
||||||
2. 🔄 Build script for clean distribution packages
|
- [ ] **Phase 4: Refactor to New Architecture**
|
||||||
3. 📋 Genre ID to name expansion (TMDB lookup)
|
- 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
|
### Medium Priority
|
||||||
1. 📋 Batch rename operations
|
|
||||||
2. 📋 Advanced search/filtering
|
|
||||||
3. 📋 TV show support
|
|
||||||
|
|
||||||
### Low Priority (Future)
|
- [ ] **Metadata Editing Capabilities**
|
||||||
1. 📋 Metadata editing
|
- Edit embedded metadata tags
|
||||||
2. 📋 Plugin system
|
- Batch editing support
|
||||||
3. 📋 Undo/redo functionality
|
- Validation and preview
|
||||||
4. 📋 Configuration profiles
|
|
||||||
|
- [ ] **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:**
|
## Feature Enhancements
|
||||||
- ✅ Completed
|
|
||||||
- 🔄 In Progress / Partially Complete
|
|
||||||
- 📋 Planned / Future Enhancement
|
|
||||||
|
|
||||||
**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
|
||||||
|
|||||||
@@ -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']
|
|
||||||
@@ -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
|
|
||||||
@@ -235,19 +235,22 @@ class TestCacheManager:
|
|||||||
manager.compact_cache()
|
manager.compact_cache()
|
||||||
|
|
||||||
|
|
||||||
class TestBackwardCompatibility:
|
class TestCachePackageImports:
|
||||||
"""Test backward compatibility with old import paths."""
|
"""Test cache package 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
|
|
||||||
|
|
||||||
def test_import_cache_from_package(self):
|
def test_import_cache_from_package(self):
|
||||||
"""Test importing Cache from renamer.cache package."""
|
"""Test importing Cache from renamer.cache package."""
|
||||||
from renamer.cache import Cache as PackageCache
|
from renamer.cache import Cache as PackageCache
|
||||||
assert PackageCache is not None
|
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):
|
def test_create_cache_convenience_function(self):
|
||||||
"""Test the create_cache convenience function."""
|
"""Test the create_cache convenience function."""
|
||||||
from renamer.cache import create_cache
|
from renamer.cache import create_cache
|
||||||
|
|||||||
Reference in New Issue
Block a user