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
|
||||
- **Version**: 0.7.0-dev (in development)
|
||||
- **Python**: 3.11+
|
||||
- **Status**: Major refactoring in progress - Phase 1 complete (critical bugs fixed, unified cache subsystem)
|
||||
Please read **[ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)** for complete project documentation including:
|
||||
|
||||
## Project Purpose
|
||||
- Architecture overview
|
||||
- Core components
|
||||
- Development setup
|
||||
- Testing strategy
|
||||
- Code standards
|
||||
- AI assistant instructions
|
||||
- Release process
|
||||
|
||||
Renamer serves two primary use cases:
|
||||
1. **Technical Mode**: Detailed technical metadata viewing (video tracks, audio streams, codecs, bitrates)
|
||||
2. **Catalog Mode**: Media library catalog view with TMDB integration (posters, ratings, descriptions, genres)
|
||||
## Quick Commands
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Core Components
|
||||
|
||||
#### Main Application (`renamer/app.py`)
|
||||
- Main `RenamerApp` class inheriting from Textual's `App`
|
||||
- Manages TUI layout with split view: file tree (left) and details panel (right)
|
||||
- Handles keyboard/mouse navigation and user commands
|
||||
- Coordinates file operations and metadata extraction
|
||||
- Implements efficient tree updates for file renaming
|
||||
|
||||
#### Entry Point (`renamer/main.py`)
|
||||
- Argument parsing for directory selection
|
||||
- Application initialization and launch
|
||||
|
||||
#### Constants (`renamer/constants.py`)
|
||||
Defines comprehensive dictionaries:
|
||||
- `MEDIA_TYPES`: Supported video formats (mkv, avi, mov, mp4, etc.)
|
||||
- `SOURCE_DICT`: Video source types (WEB-DL, BDRip, BluRay, etc.)
|
||||
- `FRAME_CLASSES`: Resolution classifications (480p-8K)
|
||||
- `MOVIE_DB_DICT`: Database identifiers (TMDB, IMDB, Trakt, TVDB)
|
||||
- `SPECIAL_EDITIONS`: Edition types (Director's Cut, Extended, etc.)
|
||||
|
||||
### Extractor System (`renamer/extractors/`)
|
||||
|
||||
Modular architecture for gathering metadata from multiple sources:
|
||||
|
||||
#### Core Extractors
|
||||
1. **MediaInfoExtractor** (`mediainfo_extractor.py`)
|
||||
- Uses PyMediaInfo library
|
||||
- Extracts detailed track information (video, audio, subtitle)
|
||||
- Provides codec, bitrate, frame rate, resolution data
|
||||
|
||||
2. **FilenameExtractor** (`filename_extractor.py`)
|
||||
- Parses metadata from filename patterns
|
||||
- Detects year, resolution, source, codecs, edition info
|
||||
- Uses regex patterns to extract structured data
|
||||
|
||||
3. **MetadataExtractor** (`metadata_extractor.py`)
|
||||
- Reads embedded metadata using Mutagen
|
||||
- Extracts tags, container format info
|
||||
|
||||
4. **FileInfoExtractor** (`fileinfo_extractor.py`)
|
||||
- Basic file information (size, dates, permissions)
|
||||
- MIME type detection via python-magic
|
||||
|
||||
5. **TMDBExtractor** (`tmdb_extractor.py`)
|
||||
- The Movie Database API integration
|
||||
- Fetches title, year, ratings, overview, genres, poster
|
||||
- Supports movie and TV show data
|
||||
|
||||
6. **DefaultExtractor** (`default_extractor.py`)
|
||||
- Fallback extractor providing minimal data
|
||||
|
||||
#### Extractor Coordinator (`extractor.py`)
|
||||
- `MediaExtractor` class orchestrates all extractors
|
||||
- Provides unified `get()` interface for data retrieval
|
||||
- Caching support via decorators
|
||||
|
||||
### Formatter System (`renamer/formatters/`)
|
||||
|
||||
Transforms raw extracted data into formatted display strings:
|
||||
|
||||
#### Specialized Formatters
|
||||
1. **MediaFormatter** (`media_formatter.py`)
|
||||
- Main formatter coordinating all format operations
|
||||
- Mode-aware (technical vs catalog)
|
||||
- Applies color coding and styling
|
||||
|
||||
2. **CatalogFormatter** (`catalog_formatter.py`)
|
||||
- Formats catalog mode display
|
||||
- Renders TMDB data, ratings, genres, overview
|
||||
- Terminal image display for posters (rich-pixels)
|
||||
|
||||
3. **TrackFormatter** (`track_formatter.py`)
|
||||
- Video/audio/subtitle track formatting
|
||||
- Color-coded track information
|
||||
|
||||
4. **ProposedNameFormatter** (`proposed_name_formatter.py`)
|
||||
- Generates intelligent rename suggestions
|
||||
- Pattern: `Title (Year) [Resolution Source Edition].ext`
|
||||
- Sanitizes filenames (removes invalid characters)
|
||||
|
||||
5. **Utility Formatters**
|
||||
- `SizeFormatter`: Human-readable file sizes
|
||||
- `DateFormatter`: Timestamp formatting
|
||||
- `DurationFormatter`: Duration in HH:MM:SS
|
||||
- `ResolutionFormatter`: Resolution display
|
||||
- `TextFormatter`: Text styling utilities
|
||||
- `ExtensionFormatter`: File extension handling
|
||||
- `SpecialInfoFormatter`: Edition/source formatting
|
||||
- `HelperFormatter`: General formatting helpers
|
||||
|
||||
### Settings & Caching
|
||||
|
||||
#### Settings System (`renamer/settings.py`)
|
||||
- JSON configuration stored in `~/.config/renamer/config.json`
|
||||
- Configurable options:
|
||||
- `mode`: "technical" or "catalog"
|
||||
- `cache_ttl_extractors`: 21600s (6 hours)
|
||||
- `cache_ttl_tmdb`: 21600s (6 hours)
|
||||
- `cache_ttl_posters`: 2592000s (30 days)
|
||||
- Automatic save/load with defaults
|
||||
|
||||
#### Cache System (`renamer/cache.py`)
|
||||
- File-based cache with TTL support
|
||||
- Location: `~/.cache/renamer/`
|
||||
- Subdirectory organization (tmdb/, posters/, extractors/, general/)
|
||||
- Supports JSON and pickle serialization
|
||||
- In-memory cache for performance
|
||||
- Image caching for TMDB posters
|
||||
- Automatic expiration and cleanup
|
||||
|
||||
#### Unified Cache Subsystem (`renamer/cache/`)
|
||||
|
||||
**NEW in v0.7.0**: Complete cache subsystem rewrite with modular architecture.
|
||||
|
||||
**Directory Structure**:
|
||||
```
|
||||
renamer/cache/
|
||||
├── __init__.py # Module exports and convenience functions
|
||||
├── core.py # Core Cache class (thread-safe with RLock)
|
||||
├── types.py # Type definitions (CacheEntry, CacheStats)
|
||||
├── strategies.py # Cache key generation strategies
|
||||
├── managers.py # CacheManager for operations
|
||||
└── decorators.py # Enhanced cache decorators
|
||||
```
|
||||
|
||||
**Cache Key Strategies**:
|
||||
- `FilepathMethodStrategy`: For extractor methods (`extractor_{hash}_{method}`)
|
||||
- `APIRequestStrategy`: For API responses (`api_{service}_{hash}`)
|
||||
- `SimpleKeyStrategy`: For simple prefix+id patterns
|
||||
- `CustomStrategy`: User-defined key generation
|
||||
|
||||
**Cache Decorators**:
|
||||
- `@cached(strategy, ttl)`: Generic caching with configurable strategy
|
||||
- `@cached_method(ttl)`: Method caching (backward compatible)
|
||||
- `@cached_api(service, ttl)`: API response caching
|
||||
- `@cached_property(ttl)`: Cached property decorator
|
||||
|
||||
**Cache Manager Operations**:
|
||||
- `clear_all()`: Remove all cache entries
|
||||
- `clear_by_prefix(prefix)`: Clear specific cache type (tmdb_, extractor_, poster_)
|
||||
- `clear_expired()`: Remove expired entries
|
||||
- `get_stats()`: Comprehensive statistics
|
||||
- `clear_file_cache(file_path)`: Clear cache for specific file
|
||||
- `compact_cache()`: Remove empty directories
|
||||
|
||||
**Command Palette Integration**:
|
||||
- Access cache commands via Ctrl+P
|
||||
- 7 commands: View Stats, Clear All, Clear Extractors, Clear TMDB, Clear Posters, Clear Expired, Compact
|
||||
- Integrated using `CacheCommandProvider`
|
||||
|
||||
**Thread Safety**:
|
||||
- All operations protected by `threading.RLock`
|
||||
- Safe for concurrent extractor access
|
||||
|
||||
### Error Handling & Logging
|
||||
|
||||
**Exception Handling** (v0.7.0):
|
||||
- No bare `except:` clauses (all use specific exception types)
|
||||
- Language code conversions catch `(LookupError, ValueError, AttributeError)`
|
||||
- Network errors catch `(requests.RequestException, ValueError)`
|
||||
- All exceptions logged with context
|
||||
|
||||
**Logging Strategy**:
|
||||
- **Warning level**: Network failures, API errors, MediaInfo parse failures (user-facing issues)
|
||||
- **Debug level**: Language code conversions, metadata reads, MIME detection (technical details)
|
||||
- **Error level**: Formatter application failures (logged via `FormatterApplier`)
|
||||
|
||||
**Logger Usage**:
|
||||
```python
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Examples
|
||||
logger.warning(f"TMDB API request failed for {url}: {e}")
|
||||
logger.debug(f"Invalid language code '{lang_code}': {e}")
|
||||
logger.error(f"Error applying {formatter.__name__}: {e}")
|
||||
```
|
||||
|
||||
**Files with Logging**:
|
||||
- `renamer/extractors/filename_extractor.py` - Language code conversion errors
|
||||
- `renamer/extractors/mediainfo_extractor.py` - MediaInfo parse and language errors
|
||||
- `renamer/extractors/metadata_extractor.py` - Mutagen and MIME detection errors
|
||||
- `renamer/extractors/tmdb_extractor.py` - API request and poster download errors
|
||||
- `renamer/formatters/formatter.py` - Formatter application errors
|
||||
- `renamer/cache/core.py` - Cache operation errors
|
||||
|
||||
### UI Screens (`renamer/screens.py`)
|
||||
|
||||
Additional UI screens for user interaction:
|
||||
|
||||
1. **OpenScreen**: Directory selection dialog with validation
|
||||
2. **HelpScreen**: Comprehensive help with key bindings
|
||||
3. **RenameConfirmScreen**: File rename confirmation with error handling
|
||||
4. **SettingsScreen**: Settings configuration interface
|
||||
|
||||
### Development Tools
|
||||
|
||||
#### Version Management (`renamer/bump.py`)
|
||||
- `bump-version` command
|
||||
- Auto-increments patch version in `pyproject.toml`
|
||||
|
||||
#### Release Automation (`renamer/release.py`)
|
||||
- `release` command
|
||||
- Runs: version bump → dependency sync → package build
|
||||
|
||||
## Key Features
|
||||
|
||||
### Current Features (v0.5.10)
|
||||
- Recursive directory scanning for video files
|
||||
- Tree view with expand/collapse navigation
|
||||
- Dual-mode display (technical/catalog)
|
||||
- Detailed metadata extraction from multiple sources
|
||||
- Intelligent file renaming with preview
|
||||
- TMDB integration with poster display
|
||||
- Settings configuration UI
|
||||
- Persistent caching with TTL
|
||||
- Loading indicators and error handling
|
||||
- Confirmation dialogs for file operations
|
||||
- Color-coded information display
|
||||
- Keyboard and mouse navigation
|
||||
|
||||
### Keyboard Commands
|
||||
- `q`: Quit application
|
||||
- `o`: Open directory
|
||||
- `s`: Scan/rescan directory
|
||||
- `f`: Refresh metadata for selected file
|
||||
- `r`: Rename file with proposed name
|
||||
- `p`: Toggle tree expansion
|
||||
- `m`: Toggle mode (technical/catalog)
|
||||
- `h`: Show help screen
|
||||
- `ctrl+s`: Open settings
|
||||
- `ctrl+p`: Open command palette
|
||||
|
||||
### Command Palette (v0.7.0)
|
||||
**Access**: Press `ctrl+p` to open the command palette
|
||||
|
||||
**Available Commands**:
|
||||
- **System Commands** (built-in from Textual):
|
||||
- Toggle theme
|
||||
- Show key bindings
|
||||
- Other system operations
|
||||
|
||||
- **Cache Commands** (from `CacheCommandProvider`):
|
||||
- Cache: View Statistics
|
||||
- Cache: Clear All
|
||||
- Cache: Clear Extractors
|
||||
- Cache: Clear TMDB
|
||||
- Cache: Clear Posters
|
||||
- Cache: Clear Expired
|
||||
- Cache: Compact
|
||||
|
||||
**Implementation**:
|
||||
- Command palette extends built-in Textual commands
|
||||
- Uses `COMMANDS = App.COMMANDS | {CacheCommandProvider}` pattern
|
||||
- Future: Will add app operation commands (open, scan, rename, etc.)
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Core Dependencies
|
||||
- **textual** (≥6.11.0): TUI framework
|
||||
- **pymediainfo** (≥6.0.0): Media track analysis
|
||||
- **mutagen** (≥1.47.0): Embedded metadata
|
||||
- **python-magic** (≥0.4.27): MIME detection
|
||||
- **langcodes** (≥3.5.1): Language code handling
|
||||
- **requests** (≥2.31.0): HTTP for TMDB API
|
||||
- **rich-pixels** (≥1.0.0): Terminal image display
|
||||
- **pytest** (≥7.0.0): Testing framework
|
||||
|
||||
### System Requirements
|
||||
- Python 3.11 or higher
|
||||
- UV package manager (recommended)
|
||||
- MediaInfo library (system dependency for pymediainfo)
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Setup
|
||||
```bash
|
||||
# Install UV
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# Clone and sync
|
||||
cd /path/to/renamer
|
||||
uv sync
|
||||
|
||||
# Run from source
|
||||
uv run python renamer/main.py [directory]
|
||||
uv sync --extra dev # Setup
|
||||
uv run pytest # Test
|
||||
uv run renamer [dir] # Run
|
||||
```
|
||||
|
||||
### Development Commands
|
||||
```bash
|
||||
uv run renamer # Run installed version
|
||||
uv run pytest # Run tests
|
||||
uv run bump-version # Increment version
|
||||
uv run release # Build release (bump + sync + build)
|
||||
uv build # Build wheel/tarball
|
||||
uv tool install . # Install as global tool
|
||||
```
|
||||
## Essential Principles
|
||||
|
||||
### Debugging
|
||||
```bash
|
||||
# Enable formatter logging
|
||||
FORMATTER_LOG=1 uv run renamer /path/to/directory
|
||||
# Creates formatter.log with detailed call traces
|
||||
```
|
||||
|
||||
### Testing
|
||||
- Test files in `renamer/test/`
|
||||
- Sample filenames in `test/filenames.txt` and `test/test_filenames.txt`
|
||||
- Test cases in `test/test_cases.json`
|
||||
- Run with: `uv run pytest`
|
||||
|
||||
## Code Style & Standards
|
||||
|
||||
### Python Standards
|
||||
- Type hints encouraged
|
||||
- PEP 8 style guidelines
|
||||
- Descriptive variable/function names
|
||||
- Docstrings for classes and functions
|
||||
- Pathlib for file operations
|
||||
- Proper exception handling
|
||||
|
||||
### Architecture Patterns
|
||||
- Extractor pattern: Each extractor focuses on one data source
|
||||
- Formatter pattern: Formatters handle display logic, extractors handle data
|
||||
- Separation of concerns: Data extraction → formatting → display
|
||||
- Dependency injection: Extractors and formatters are modular
|
||||
- Configuration management: Settings class for all config
|
||||
|
||||
### Best Practices
|
||||
- Avoid over-engineering (keep solutions simple)
|
||||
- Only add features when explicitly requested
|
||||
- Validate at system boundaries only (user input, external APIs)
|
||||
- Don't add unnecessary error handling for internal code
|
||||
- Trust framework guarantees
|
||||
- Delete unused code completely (no backwards-compat hacks)
|
||||
|
||||
## File Operations
|
||||
|
||||
### Directory Scanning
|
||||
- Recursive search for supported video formats
|
||||
- File tree representation with hierarchical structure
|
||||
- Efficient tree updates on file operations
|
||||
|
||||
### File Renaming
|
||||
1. Select file in tree
|
||||
2. Press `r` to initiate rename
|
||||
3. Review proposed name (shows current vs proposed)
|
||||
4. Confirm with `y` or cancel with `n`
|
||||
5. Tree updates in-place without full reload
|
||||
|
||||
### Metadata Caching
|
||||
- First extraction cached for 6 hours
|
||||
- TMDB data cached for 6 hours
|
||||
- Posters cached for 30 days
|
||||
- Force refresh with `f` command
|
||||
- Cache invalidated on file rename
|
||||
|
||||
## API Integration
|
||||
|
||||
### TMDB API
|
||||
- API key stored in `renamer/secrets.py`
|
||||
- Search endpoint for movie lookup by title/year
|
||||
- Image base URL for poster downloads
|
||||
- Handles rate limiting and errors gracefully
|
||||
- Falls back to filename data if API unavailable
|
||||
|
||||
## Project Files
|
||||
|
||||
### Documentation
|
||||
- `README.md`: User-facing documentation
|
||||
- `AI_AGENT.md`: AI agent instructions (legacy)
|
||||
- `DEVELOP.md`: Developer guide
|
||||
- `INSTALL.md`: Installation instructions
|
||||
- `ToDo.md`: Task tracking
|
||||
- `CLAUDE.md`: This file (AI assistant reference)
|
||||
|
||||
### Configuration
|
||||
- `pyproject.toml`: Project metadata, dependencies, build config
|
||||
- `uv.lock`: Locked dependencies
|
||||
|
||||
### Build Artifacts
|
||||
- `dist/`: Built wheels and tarballs
|
||||
- `build/`: Build intermediates
|
||||
- `renamer.egg-info/`: Package metadata
|
||||
|
||||
## Known Issues & Limitations
|
||||
|
||||
### Current Limitations
|
||||
- TMDB API requires internet connection
|
||||
- Poster display requires terminal with image support
|
||||
- Some special characters in filenames need sanitization
|
||||
- Large directories may have initial scan delay
|
||||
|
||||
### Future Enhancements (See ToDo.md)
|
||||
- Metadata editing capabilities
|
||||
- Batch rename operations
|
||||
- Advanced search and filtering
|
||||
- Undo/redo functionality
|
||||
- Plugin system for custom extractors/formatters
|
||||
- Full genre name expansion (currently shows codes)
|
||||
- Improved poster quality/display optimization
|
||||
|
||||
## Contributing Guidelines
|
||||
|
||||
### Making Changes
|
||||
1. Read existing code and understand architecture
|
||||
2. Check `ToDo.md` for pending tasks
|
||||
3. Implement features incrementally
|
||||
4. Test with real media files
|
||||
5. Ensure backward compatibility
|
||||
6. Update documentation
|
||||
7. Update tests as needed
|
||||
8. Run `uv run release` before committing
|
||||
|
||||
### Commit Standards
|
||||
- Clear, descriptive commit messages
|
||||
- Focus on "why" not "what"
|
||||
- One logical change per commit
|
||||
- Reference related issues/tasks
|
||||
|
||||
### Code Review Checklist
|
||||
- [ ] Follows PEP 8 style
|
||||
- [ ] Type hints added where appropriate
|
||||
- [ ] No unnecessary complexity
|
||||
- [ ] Tests pass (`uv run pytest`)
|
||||
- [ ] Documentation updated
|
||||
- [ ] No security vulnerabilities (XSS, injection, etc.)
|
||||
- [ ] Efficient resource usage (no memory leaks)
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Input sanitization for filenames (see `ProposedNameFormatter`)
|
||||
- No shell command injection risks
|
||||
- Safe file operations (pathlib, proper error handling)
|
||||
- TMDB API key should not be committed (stored in `secrets.py`)
|
||||
- Cache directory permissions should be user-only
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- In-memory cache reduces repeated extraction overhead
|
||||
- File cache persists across sessions
|
||||
- Tree updates optimized for rename operations
|
||||
- TMDB requests throttled to respect API limits
|
||||
- Large directory scans use async/await patterns
|
||||
|
||||
## Special Notes for AI Assistants
|
||||
|
||||
### When Adding Features
|
||||
1. **Always read relevant files first** - Never modify code you haven't read
|
||||
2. **Check ToDo.md** - See if feature is already planned
|
||||
3. **Understand existing patterns** - Follow established architecture
|
||||
4. **Test with real files** - Use actual media files for testing
|
||||
5. **Update documentation** - Keep docs in sync with code
|
||||
|
||||
### When Debugging
|
||||
1. **Enable formatter logging** - Use `FORMATTER_LOG=1` for detailed traces
|
||||
2. **Check cache state** - Clear cache if stale data suspected
|
||||
3. **Verify file permissions** - Ensure read/write access
|
||||
4. **Test with sample filenames** - Use test fixtures first
|
||||
|
||||
### When Refactoring
|
||||
1. **Maintain backward compatibility** - Unless explicitly breaking change
|
||||
2. **Update tests** - Reflect refactored code
|
||||
3. **Check all formatters** - Formatting is centralized
|
||||
4. **Verify extractor chain** - Ensure data flow intact
|
||||
|
||||
### Common Pitfalls to Avoid
|
||||
- Don't create new files unless absolutely necessary (edit existing)
|
||||
- Don't add features beyond what's requested
|
||||
- Don't over-engineer solutions
|
||||
- Don't skip testing with real files
|
||||
- Don't forget to update version number for releases
|
||||
- Don't commit secrets or API keys
|
||||
- Don't use deprecated Textual APIs
|
||||
|
||||
## Project History
|
||||
|
||||
### Evolution
|
||||
- Started as simple file renamer
|
||||
- Added metadata extraction (MediaInfo, Mutagen)
|
||||
- Expanded to TUI with Textual framework
|
||||
- Added filename parsing intelligence
|
||||
- Integrated TMDB for catalog mode
|
||||
- Added settings and caching system
|
||||
- Implemented poster display with rich-pixels
|
||||
- Added dual-mode interface (technical/catalog)
|
||||
|
||||
### Version Milestones
|
||||
- 0.2.x: Initial TUI with basic metadata
|
||||
- 0.3.x: Enhanced extractors and formatters
|
||||
- 0.4.x: Added TMDB integration
|
||||
- 0.5.x: Settings, caching, catalog mode, poster display
|
||||
|
||||
## Resources
|
||||
|
||||
### External Documentation
|
||||
- [Textual Documentation](https://textual.textualize.io/)
|
||||
- [PyMediaInfo Documentation](https://pymediainfo.readthedocs.io/)
|
||||
- [Mutagen Documentation](https://mutagen.readthedocs.io/)
|
||||
- [TMDB API Documentation](https://developers.themoviedb.org/3)
|
||||
- [UV Documentation](https://docs.astral.sh/uv/)
|
||||
|
||||
### Internal Documentation
|
||||
- Main README: User guide and quick start
|
||||
- DEVELOP.md: Developer setup and debugging
|
||||
- INSTALL.md: Installation methods
|
||||
- AI_AGENT.md: Legacy AI instructions (historical)
|
||||
- ToDo.md: Current task list
|
||||
1. **Read [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md) first**
|
||||
2. Read files before modifying
|
||||
3. Test everything (`uv run pytest`)
|
||||
4. Follow existing patterns
|
||||
5. Keep solutions simple
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-31
|
||||
**For AI Assistant**: Claude (Anthropic)
|
||||
**Project Maintainer**: sha
|
||||
**Repository**: `/home/sha/bin/renamer`
|
||||
**Full Documentation**: [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)
|
||||
|
||||
324
DEVELOP.md
324
DEVELOP.md
@@ -1,220 +1,118 @@
|
||||
# Developer Guide
|
||||
|
||||
This guide contains information for developers working on the Renamer project.
|
||||
**Version**: 0.7.0-dev
|
||||
**Last Updated**: 2026-01-01
|
||||
|
||||
**Current Version**: 0.5.10
|
||||
> **📘 For complete development documentation, see [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)**
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Prerequisites
|
||||
- Python 3.11+
|
||||
- UV package manager
|
||||
|
||||
### Install UV (if not already installed)
|
||||
```bash
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
```
|
||||
|
||||
### Development Installation
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone <repository-url>
|
||||
cd renamer
|
||||
|
||||
# Install in development mode with all dependencies
|
||||
uv sync
|
||||
|
||||
# Install the package in editable mode
|
||||
uv pip install -e .
|
||||
```
|
||||
|
||||
### Running in Development
|
||||
```bash
|
||||
# Run directly from source
|
||||
uv run python renamer/main.py
|
||||
|
||||
# Or run with specific directory
|
||||
uv run python renamer/main.py /path/to/directory
|
||||
|
||||
# Or use the installed command
|
||||
uv run renamer
|
||||
```
|
||||
|
||||
## Development Commands
|
||||
|
||||
The project includes several development commands defined in `pyproject.toml`:
|
||||
|
||||
### bump-version
|
||||
Increments the patch version in `pyproject.toml` (e.g., 0.2.6 → 0.2.7).
|
||||
```bash
|
||||
uv run bump-version
|
||||
```
|
||||
|
||||
### release
|
||||
Runs a batch process: bump version, sync dependencies, and build the package.
|
||||
```bash
|
||||
uv run release
|
||||
```
|
||||
|
||||
### Other Commands
|
||||
- `uv sync`: Install/update dependencies
|
||||
- `uv build`: Build the package
|
||||
- `uv run pytest`: Run tests
|
||||
|
||||
## Debugging
|
||||
|
||||
### Formatter Logging
|
||||
Enable detailed logging for formatter operations:
|
||||
```bash
|
||||
FORMATTER_LOG=1 uv run renamer /path/to/directory
|
||||
```
|
||||
|
||||
This creates `formatter.log` in the current directory with:
|
||||
- Formatter call sequences and ordering
|
||||
- Input/output values for each formatter
|
||||
- Caller information (file and line number)
|
||||
- Any errors during formatting
|
||||
- Timestamp for each operation
|
||||
|
||||
### Cache Inspection
|
||||
Cache is stored in `~/.cache/renamer/` with subdirectories:
|
||||
- `extractors/`: Extractor results cache
|
||||
- `tmdb/`: TMDB API response cache
|
||||
- `posters/`: Downloaded poster images
|
||||
- `general/`: General purpose cache
|
||||
|
||||
To clear cache:
|
||||
```bash
|
||||
rm -rf ~/.cache/renamer/
|
||||
```
|
||||
|
||||
### Settings Location
|
||||
Settings are stored in `~/.config/renamer/config.json`:
|
||||
```json
|
||||
{
|
||||
"mode": "technical",
|
||||
"cache_ttl_extractors": 21600,
|
||||
"cache_ttl_tmdb": 21600,
|
||||
"cache_ttl_posters": 2592000
|
||||
}
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
The application uses a modular architecture with clear separation of concerns:
|
||||
|
||||
### Core Application (`renamer/`)
|
||||
- **app.py**: Main RenamerApp class (Textual App), tree management, file operations
|
||||
- **main.py**: Entry point with argument parsing
|
||||
- **constants.py**: Comprehensive constants (media types, sources, resolutions, editions)
|
||||
- **settings.py**: Settings management with JSON persistence (`~/.config/renamer/`)
|
||||
- **cache.py**: File-based caching system with TTL support (`~/.cache/renamer/`)
|
||||
- **secrets.py**: API keys and secrets (TMDB)
|
||||
|
||||
### Extractors (`renamer/extractors/`)
|
||||
Data extraction from multiple sources:
|
||||
- **extractor.py**: MediaExtractor coordinator class
|
||||
- **mediainfo_extractor.py**: PyMediaInfo for detailed track information
|
||||
- **filename_extractor.py**: Regex-based filename parsing
|
||||
- **metadata_extractor.py**: Mutagen for embedded metadata
|
||||
- **fileinfo_extractor.py**: Basic file information (size, dates, MIME)
|
||||
- **tmdb_extractor.py**: The Movie Database API integration
|
||||
- **default_extractor.py**: Fallback extractor
|
||||
|
||||
### Formatters (`renamer/formatters/`)
|
||||
Display formatting and rendering:
|
||||
- **formatter.py**: Base formatter interface
|
||||
- **media_formatter.py**: Main formatter coordinating all format operations
|
||||
- **catalog_formatter.py**: Catalog mode display (TMDB data, posters)
|
||||
- **proposed_name_formatter.py**: Intelligent rename suggestions
|
||||
- **track_formatter.py**: Video/audio/subtitle track formatting
|
||||
- **size_formatter.py**: Human-readable file sizes
|
||||
- **date_formatter.py**: Timestamp formatting
|
||||
- **duration_formatter.py**: Duration in HH:MM:SS format
|
||||
- **resolution_formatter.py**: Resolution display
|
||||
- **extension_formatter.py**: File extension handling
|
||||
- **special_info_formatter.py**: Edition/source formatting
|
||||
- **text_formatter.py**: Text styling utilities
|
||||
- **helper_formatter.py**: General formatting helpers
|
||||
|
||||
### Screens (`renamer/screens.py`)
|
||||
UI screens for user interaction:
|
||||
- **OpenScreen**: Directory selection with validation
|
||||
- **HelpScreen**: Comprehensive help with key bindings
|
||||
- **RenameConfirmScreen**: File rename confirmation with preview
|
||||
- **SettingsScreen**: Settings configuration UI
|
||||
|
||||
### Utilities
|
||||
- **decorators/caching.py**: Caching decorator for automatic method caching
|
||||
- **bump.py**: Version bump utility script
|
||||
- **release.py**: Release automation (bump + sync + build)
|
||||
|
||||
## Testing
|
||||
|
||||
Run tests with:
|
||||
```bash
|
||||
uv run pytest
|
||||
```
|
||||
|
||||
Test files are located in `renamer/test/` with sample filenames in `filenames.txt`.
|
||||
|
||||
## Building and Distribution
|
||||
|
||||
### Build the Package
|
||||
```bash
|
||||
uv build
|
||||
```
|
||||
|
||||
### Install as Tool
|
||||
```bash
|
||||
uv tool install .
|
||||
```
|
||||
|
||||
### Uninstall
|
||||
```bash
|
||||
uv tool uninstall renamer
|
||||
```
|
||||
|
||||
## Code Style
|
||||
|
||||
The project follows Python best practices:
|
||||
- **PEP 8**: Standard Python style guide
|
||||
- **Type Hints**: Encouraged where appropriate
|
||||
- **Docstrings**: For all classes and public methods
|
||||
- **Descriptive Naming**: Clear variable and function names
|
||||
- **Pathlib**: For all file operations
|
||||
- **Error Handling**: Appropriate exception handling at boundaries
|
||||
|
||||
Consider using tools like:
|
||||
- `ruff` for linting and formatting
|
||||
- `mypy` for type checking
|
||||
- `black` for consistent formatting
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch
|
||||
3. Make your changes
|
||||
4. Run tests: `uv run pytest`
|
||||
5. Run the release process: `uv run release`
|
||||
6. Submit a pull request
|
||||
|
||||
## Additional Documentation
|
||||
|
||||
For comprehensive project information:
|
||||
- **[README.md](README.md)**: User guide and features
|
||||
- **[CLAUDE.md](CLAUDE.md)**: Complete AI assistant reference
|
||||
- **[AI_AGENT.md](AI_AGENT.md)**: AI agent instructions
|
||||
- **[INSTALL.md](INSTALL.md)**: Installation methods
|
||||
- **[ToDo.md](ToDo.md)**: Task list and priorities
|
||||
|
||||
## Project Resources
|
||||
|
||||
- **Cache Directory**: `~/.cache/renamer/`
|
||||
- **Config Directory**: `~/.config/renamer/`
|
||||
- **Test Files**: `renamer/test/`
|
||||
- **Build Output**: `dist/` and `build/`
|
||||
Quick reference for developers working on the Renamer project.
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-31
|
||||
## Quick Setup
|
||||
|
||||
```bash
|
||||
# Install UV
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# Clone and setup
|
||||
cd /home/sha/bin/renamer
|
||||
uv sync --extra dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Essential Commands
|
||||
|
||||
```bash
|
||||
# Run from source
|
||||
uv run renamer [directory]
|
||||
|
||||
# Run tests
|
||||
uv run pytest
|
||||
|
||||
# Run with coverage
|
||||
uv run pytest --cov=renamer
|
||||
|
||||
# Type check
|
||||
uv run mypy renamer/
|
||||
|
||||
# Version bump
|
||||
uv run bump-version
|
||||
|
||||
# Full release
|
||||
uv run release
|
||||
|
||||
# Build distribution
|
||||
uv build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
```bash
|
||||
# Enable detailed logging
|
||||
FORMATTER_LOG=1 uv run renamer /path/to/directory
|
||||
|
||||
# Check logs
|
||||
cat formatter.log
|
||||
|
||||
# Clear cache
|
||||
rm -rf ~/.cache/renamer/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# All tests
|
||||
uv run pytest
|
||||
|
||||
# Specific file
|
||||
uv run pytest renamer/test/test_services.py
|
||||
|
||||
# Verbose
|
||||
uv run pytest -xvs
|
||||
|
||||
# Generate sample files
|
||||
uv run python renamer/test/fill_sample_mediafiles.py
|
||||
```
|
||||
|
||||
See [ENGINEERING_GUIDE.md - Testing Strategy](ENGINEERING_GUIDE.md#testing-strategy)
|
||||
|
||||
---
|
||||
|
||||
## Release Process
|
||||
|
||||
```bash
|
||||
# 1. Bump version
|
||||
uv run bump-version
|
||||
|
||||
# 2. Run full release
|
||||
uv run release
|
||||
|
||||
# 3. Test installation
|
||||
uv tool install .
|
||||
|
||||
# 4. Manual testing
|
||||
uv run renamer /path/to/test/media
|
||||
```
|
||||
|
||||
See [ENGINEERING_GUIDE.md - Release Process](ENGINEERING_GUIDE.md#release-process)
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
- **[ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)** - Complete technical reference
|
||||
- **[README.md](README.md)** - User guide
|
||||
- **[INSTALL.md](INSTALL.md)** - Installation instructions
|
||||
- **[CHANGELOG.md](CHANGELOG.md)** - Version history
|
||||
- **[REFACTORING_PROGRESS.md](REFACTORING_PROGRESS.md)** - Future plans
|
||||
- **[ToDo.md](ToDo.md)** - Current tasks
|
||||
|
||||
---
|
||||
|
||||
**For complete documentation, see [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)**
|
||||
|
||||
944
ENGINEERING_GUIDE.md
Normal file
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
|
||||
|
||||
A powerful terminal-based (TUI) application for managing media collections. Scan directories, view detailed metadata, browse TMDB catalog information with posters, and intelligently rename files. Built with Python and Textual.
|
||||
**Version**: 0.7.0-dev
|
||||
|
||||
**Version**: 0.5.10
|
||||
A powerful Terminal User Interface (TUI) for managing media collections. View detailed metadata, browse TMDB catalog with posters, and intelligently rename files.
|
||||
|
||||
> **📘 For complete documentation, see [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)**
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Core Capabilities
|
||||
- **Dual Display Modes**: Switch between Technical (codec/track details) and Catalog (TMDB metadata with posters)
|
||||
- **Recursive Directory Scanning**: Finds all video files in nested directories
|
||||
- **Tree View Navigation**: Keyboard and mouse support with expand/collapse
|
||||
- **Multi-Source Metadata**: Combines MediaInfo, filename parsing, embedded tags, and TMDB API
|
||||
- **Intelligent Renaming**: Proposes standardized names based on extracted metadata
|
||||
- **Persistent Settings**: Configurable mode and cache TTLs saved to `~/.config/renamer/`
|
||||
- **Advanced Caching**: File-based cache with TTL (6h extractors, 6h TMDB, 30d posters)
|
||||
- **Terminal Poster Display**: View movie posters in your terminal using rich-pixels
|
||||
- **Color-Coded Display**: Visual highlighting for different data types
|
||||
- **Confirmation Dialogs**: Safe file operations with preview and confirmation
|
||||
- **Extensible Architecture**: Modular extractor and formatter system for easy extension
|
||||
- **Dual Display Modes**: Technical (codecs/tracks) or Catalog (TMDB with posters)
|
||||
- **Multi-Source Metadata**: MediaInfo, filename parsing, embedded tags, TMDB API
|
||||
- **Intelligent Renaming**: Standardized names from metadata
|
||||
- **Advanced Caching**: 6h extractors, 6h TMDB, 30d posters
|
||||
- **Terminal Posters**: View movie posters in your terminal
|
||||
- **Tree View Navigation**: Keyboard and mouse support
|
||||
|
||||
## Installation
|
||||
---
|
||||
|
||||
### Prerequisites
|
||||
- Python 3.11+
|
||||
- UV package manager
|
||||
## Quick Start
|
||||
|
||||
### Installation
|
||||
|
||||
### Install UV (if not already installed)
|
||||
```bash
|
||||
# Install UV
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
```
|
||||
|
||||
### Install the Application
|
||||
```bash
|
||||
# Clone or download the project
|
||||
# Install Renamer
|
||||
cd /path/to/renamer
|
||||
|
||||
# Install dependencies and build
|
||||
uv sync
|
||||
|
||||
# Install as a global tool
|
||||
uv tool install .
|
||||
```
|
||||
|
||||
## Usage
|
||||
See [INSTALL.md](INSTALL.md) for detailed installation instructions.
|
||||
|
||||
### Usage
|
||||
|
||||
### Running the App
|
||||
```bash
|
||||
# Scan current directory
|
||||
renamer
|
||||
|
||||
# Scan specific directory
|
||||
renamer /path/to/media/directory
|
||||
renamer /path/to/media
|
||||
```
|
||||
|
||||
### Keyboard Commands
|
||||
- **q**: Quit the application
|
||||
- **o**: Open directory selection dialog
|
||||
- **s**: Scan/rescan current directory
|
||||
- **f**: Force refresh metadata for selected file (bypass cache)
|
||||
- **r**: Rename selected file with proposed name
|
||||
- **p**: Toggle tree expansion (expand/collapse all)
|
||||
- **h**: Show help screen
|
||||
- **^p**: Open command palette (settings, mode toggle)
|
||||
- **Settings**: Access via action bar (top-right corner)
|
||||
---
|
||||
|
||||
### Navigation
|
||||
- Use arrow keys to navigate the file tree
|
||||
- Right arrow: Expand directory
|
||||
- Left arrow: Collapse directory or go to parent
|
||||
- Mouse clicks supported
|
||||
- Select a video file to view its details in the right panel
|
||||
## Keyboard Commands
|
||||
|
||||
### File Renaming
|
||||
1. Select a media file in the tree
|
||||
2. Press **r** to initiate rename
|
||||
3. Review the proposed new name in the confirmation dialog
|
||||
4. Press **y** to confirm or **n** to cancel
|
||||
5. The file will be renamed and the tree updated automatically (cache invalidated)
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `q` | Quit |
|
||||
| `o` | Open directory |
|
||||
| `s` | Scan/rescan |
|
||||
| `f` | Refresh metadata |
|
||||
| `r` | Rename file |
|
||||
| `m` | Toggle mode (technical/catalog) |
|
||||
| `p` | Toggle tree expansion |
|
||||
| `h` | Show help |
|
||||
| `Ctrl+S` | Settings |
|
||||
| `Ctrl+P` | Command palette |
|
||||
|
||||
### Display Modes
|
||||
- **Technical Mode**: Shows codec details, bitrates, track information, resolutions
|
||||
- **Catalog Mode**: Shows TMDB data including title, year, rating, overview, genres, and poster
|
||||
- Toggle between modes via Settings menu or command palette (^p)
|
||||
---
|
||||
|
||||
## Display Modes
|
||||
|
||||
### Technical Mode
|
||||
- Video tracks (codec, bitrate, resolution, frame rate)
|
||||
- Audio tracks (codec, channels, sample rate, language)
|
||||
- Subtitle tracks (format, language)
|
||||
- File information (size, modification time, path)
|
||||
|
||||
### Catalog Mode
|
||||
- TMDB title, year, rating
|
||||
- Overview/description
|
||||
- Genres
|
||||
- Poster image (if terminal supports)
|
||||
- Technical metadata
|
||||
|
||||
Toggle with `m` key.
|
||||
|
||||
---
|
||||
|
||||
## File Renaming
|
||||
|
||||
**Proposed Format**: `Title (Year) [Resolution Source Edition].ext`
|
||||
|
||||
**Example**: `The Matrix (1999) [1080p BluRay].mkv`
|
||||
|
||||
1. Press `r` on selected file
|
||||
2. Review proposed name
|
||||
3. Confirm with `y` or cancel with `n`
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
**Location**: `~/.config/renamer/config.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"mode": "technical",
|
||||
"cache_ttl_extractors": 21600,
|
||||
"cache_ttl_tmdb": 21600,
|
||||
"cache_ttl_posters": 2592000
|
||||
}
|
||||
```
|
||||
|
||||
Access via `Ctrl+S` or edit file directly.
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Python**: 3.11+
|
||||
- **UV**: Package manager
|
||||
- **MediaInfo**: System library (for technical metadata)
|
||||
- **Internet**: For TMDB catalog mode
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
renamer/
|
||||
├── app.py # Main TUI application
|
||||
├── services/ # Business logic
|
||||
├── extractors/ # Metadata extraction
|
||||
├── formatters/ # Display formatting
|
||||
├── utils/ # Shared utilities
|
||||
├── cache/ # Caching subsystem
|
||||
└── constants/ # Configuration constants
|
||||
```
|
||||
|
||||
See [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md) for complete architecture documentation.
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
For development setup, architecture details, debugging information, and contribution guidelines, see [DEVELOP.md](DEVELOP.md).
|
||||
```bash
|
||||
# Setup
|
||||
uv sync --extra dev
|
||||
|
||||
## Supported Video Formats
|
||||
- .mkv
|
||||
- .avi
|
||||
- .mov
|
||||
- .mp4
|
||||
- .wmv
|
||||
- .flv
|
||||
- .webm
|
||||
- .m4v
|
||||
- .3gp
|
||||
- .ogv
|
||||
# Run tests
|
||||
uv run pytest
|
||||
|
||||
## Dependencies
|
||||
- **textual** ≥6.11.0: TUI framework
|
||||
- **pymediainfo** ≥6.0.0: Detailed media track information
|
||||
- **mutagen** ≥1.47.0: Embedded metadata extraction
|
||||
- **python-magic** ≥0.4.27: MIME type detection
|
||||
- **langcodes** ≥3.5.1: Language code handling
|
||||
- **requests** ≥2.31.0: HTTP client for TMDB API
|
||||
- **rich-pixels** ≥1.0.0: Terminal image display
|
||||
- **pytest** ≥7.0.0: Testing framework
|
||||
# Run from source
|
||||
uv run renamer [directory]
|
||||
```
|
||||
|
||||
### System Requirements
|
||||
- **Python**: 3.11 or higher
|
||||
- **MediaInfo Library**: System dependency for pymediainfo
|
||||
- Ubuntu/Debian: `sudo apt install libmediainfo-dev`
|
||||
- Fedora/CentOS: `sudo dnf install libmediainfo-devel`
|
||||
- Arch Linux: `sudo pacman -S libmediainfo`
|
||||
- macOS/Windows: Automatically handled by pymediainfo
|
||||
See [DEVELOP.md](DEVELOP.md) for development documentation.
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
- **[ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)** - Complete technical reference
|
||||
- **[INSTALL.md](INSTALL.md)** - Installation instructions
|
||||
- **[DEVELOP.md](DEVELOP.md)** - Development guide
|
||||
- **[CHANGELOG.md](CHANGELOG.md)** - Version history
|
||||
- **[CLAUDE.md](CLAUDE.md)** - AI assistant reference
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
Not specified
|
||||
|
||||
---
|
||||
|
||||
## Credits
|
||||
|
||||
- Built with [Textual](https://textual.textualize.io/)
|
||||
- Metadata from [MediaInfo](https://mediaarea.net/en/MediaInfo)
|
||||
- Catalog data from [TMDB](https://www.themoviedb.org/)
|
||||
|
||||
---
|
||||
|
||||
**For complete documentation, see [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md)**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
272
ToDo.md
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:
|
||||
1. ✅ Set up Python project structure with UV package manager
|
||||
2. ✅ Install dependencies: textual, mutagen, pymediainfo, python-magic, pathlib for file handling
|
||||
3. ✅ Implement recursive directory scanning for video files (*.mkv, *.avi, *.mov, *.mp4, *.wmv, *.flv, *.webm, etc.)
|
||||
4. ✅ Detect real media container type using mutagen and python-magic
|
||||
5. ✅ Create Textual TUI application with split layout (left: file tree, right: file details)
|
||||
6. ✅ Implement file tree display with navigation (keyboard arrows, mouse support)
|
||||
7. ✅ Add bottom command bar with 'quit', 'open directory', 'scan' commands
|
||||
8. ✅ Display file details on right side: file size, extension from filename, extension from metadata, file date
|
||||
9. ✅ Add functionality to select files in the tree and update right panel
|
||||
10. ✅ Implement detailed metadata display including video/audio/subtitle tracks with colors
|
||||
11. ✅ Add custom tree styling with file icons and colored guides
|
||||
12. ✅ Add scrollable details panel
|
||||
13. ✅ Handle markup escaping for file names with brackets
|
||||
14. ✅ Implement file renaming functionality with confirmation dialog
|
||||
15. ✅ Add proposed name generation based on metadata extraction
|
||||
16. ✅ Add help screen with key bindings and usage information
|
||||
17. ✅ Add tree expansion/collapse toggle functionality
|
||||
18. ✅ Add file refresh functionality to reload metadata for selected file
|
||||
19. ✅ Optimize tree updates to avoid full reloads after renaming
|
||||
20. ✅ Add loading indicators for metadata extraction
|
||||
21. ✅ Add error handling for file operations and metadata extraction
|
||||
22. 🔄 Implement blue highlighting for changed parts in proposed filename display (show differences between current and proposed names)
|
||||
23. 🔄 Implement build script to exclude dev commands (bump-version, release) from distributed package
|
||||
24. 📋 Implement metadata editing capabilities (future enhancement)
|
||||
25. 📋 Add batch rename operations (future enhancement)
|
||||
27. 📋 Add advanced search and filtering capabilities (future enhancement)
|
||||
28. 📋 Implement undo/redo functionality for file operations (future enhancement)
|
||||
> **📋 For completed work, see [CHANGELOG.md](CHANGELOG.md)**
|
||||
>
|
||||
> **📋 For refactoring plans, see [REFACTORING_PROGRESS.md](REFACTORING_PROGRESS.md)**
|
||||
|
||||
This file tracks future feature enhancements and improvements.
|
||||
|
||||
---
|
||||
|
||||
## Media Catalog Mode Implementation Plan
|
||||
|
||||
**New big app evolution step: Add media catalog mode with settings, caching, and enhanced TMDB display.**
|
||||
|
||||
### Phase 1: Settings Management Foundation
|
||||
1. ✅ Create settings module (`renamer/settings.py`) for JSON config in `~/.config/renamer/config.json` with schema: mode, cache TTLs
|
||||
2. ✅ Integrate settings into app startup (load/save on launch/exit)
|
||||
3. ✅ Add settings window to UI with fields for mode and TTLs
|
||||
4. ✅ Add "Open Settings" command to command panel
|
||||
5. ✅ Order setting menu item in the action bar by right side, close to the sysytem menu item ^p palette
|
||||
|
||||
### Phase 2: Mode Toggle and UI Switching
|
||||
5. ✅ Add "Toggle Mode" command to switch between "technical" and "catalog" modes
|
||||
6. ✅ Modify right pane for mode-aware display (technical vs catalog info)
|
||||
7. ✅ Persist and restore mode state from settings
|
||||
|
||||
### Phase 3: Caching System
|
||||
8. ✅ Create caching module (`renamer/cache.py`) for file-based cache with TTL support
|
||||
9. ✅ Integrate caching into extractors (check cache first, store results)
|
||||
10. ✅ Add refresh command to force re-extraction and cache update
|
||||
11. ✅ Handle cache cleanup on file rename (invalidate old filename)
|
||||
|
||||
### Phase 4: Media Catalog Display
|
||||
12. ✅ Update TMDB extractor for catalog data: title, year, duration, rates, overview, genres codes, poster_path
|
||||
13. ✅ Create catalog formatter (`formatters/catalog_formatter.py`) for beautiful display
|
||||
14. ✅ Integrate catalog display into right pane
|
||||
|
||||
### Phase 5: Poster Handling and Display
|
||||
15. ✅ Add poster caching (images in cache dir with 1-month TTL)
|
||||
16. ✅ Implement terminal image display (using rich-pixels library)
|
||||
|
||||
### Phase 6: Polish and Documentation
|
||||
17. ✅ Create comprehensive CLAUDE.md for AI assistants
|
||||
18. ✅ Update all markdown documentation files
|
||||
19. ✅ Ensure version consistency across all files
|
||||
|
||||
### Additional TODOs from Plan
|
||||
- 📋 Retrieve full movie details from TMDB (currently basic data only)
|
||||
- 📋 Expand genres to full names instead of codes (currently shows genre IDs)
|
||||
- 📋 Optimize poster quality and display (improve image rendering)
|
||||
- 📋 Add TV show support (currently movie-focused)
|
||||
- 📋 Implement blue highlighting for filename differences
|
||||
- 📋 Build script to exclude dev commands from distribution
|
||||
|
||||
---
|
||||
|
||||
## Recently Completed (v0.5.x)
|
||||
|
||||
### Version 0.5.10
|
||||
- Complete media catalog mode implementation
|
||||
- TMDB integration with poster display
|
||||
- Settings system with persistent JSON storage
|
||||
- Advanced caching with TTL support
|
||||
- Dual-mode display (technical/catalog)
|
||||
- Settings UI screen
|
||||
|
||||
### Version 0.4.x
|
||||
- Enhanced extractor system
|
||||
- TMDB extractor foundation
|
||||
- Improved formatter architecture
|
||||
|
||||
### Version 0.3.x
|
||||
- Expanded metadata extraction
|
||||
- Multiple formatter types
|
||||
- Special edition detection
|
||||
|
||||
### Version 0.2.x
|
||||
- Initial TUI implementation
|
||||
- Basic metadata extraction
|
||||
- File tree navigation
|
||||
- Rename functionality
|
||||
|
||||
---
|
||||
|
||||
## Development Priorities
|
||||
## Priority Tasks
|
||||
|
||||
### High Priority
|
||||
1. 🔄 Blue highlighting for filename differences (UX improvement)
|
||||
2. 🔄 Build script for clean distribution packages
|
||||
3. 📋 Genre ID to name expansion (TMDB lookup)
|
||||
|
||||
- [ ] **Phase 4: Refactor to New Architecture**
|
||||
- Refactor existing extractors to use Protocol
|
||||
- Refactor existing formatters to use base classes
|
||||
- Integrate RenamerApp with services
|
||||
- Update all imports and dependencies
|
||||
- See [REFACTORING_PROGRESS.md](REFACTORING_PROGRESS.md) for details
|
||||
|
||||
- [ ] **Complete Test Coverage**
|
||||
- Add UI screen tests
|
||||
- Add app integration tests
|
||||
- Increase coverage to >90%
|
||||
|
||||
### Medium Priority
|
||||
1. 📋 Batch rename operations
|
||||
2. 📋 Advanced search/filtering
|
||||
3. 📋 TV show support
|
||||
|
||||
### Low Priority (Future)
|
||||
1. 📋 Metadata editing
|
||||
2. 📋 Plugin system
|
||||
3. 📋 Undo/redo functionality
|
||||
4. 📋 Configuration profiles
|
||||
- [ ] **Metadata Editing Capabilities**
|
||||
- Edit embedded metadata tags
|
||||
- Batch editing support
|
||||
- Validation and preview
|
||||
|
||||
- [ ] **Batch Rename Operations**
|
||||
- Select multiple files
|
||||
- Preview all changes
|
||||
- Bulk rename with rollback
|
||||
|
||||
- [ ] **Advanced Search and Filtering**
|
||||
- Filter by resolution, codec, year
|
||||
- Search by TMDB metadata
|
||||
- Save filter presets
|
||||
|
||||
---
|
||||
|
||||
**Legend:**
|
||||
- ✅ Completed
|
||||
- 🔄 In Progress / Partially Complete
|
||||
- 📋 Planned / Future Enhancement
|
||||
## Feature Enhancements
|
||||
|
||||
**Last Updated**: 2025-12-31
|
||||
### UI Improvements
|
||||
|
||||
- [ ] **Blue Highlighting for Filename Differences**
|
||||
- Show changed parts in proposed filename
|
||||
- Color-code additions, removals, changes
|
||||
- Side-by-side comparison view
|
||||
|
||||
- [ ] **Enhanced Poster Display**
|
||||
- Optimize image quality
|
||||
- Support for fanart/backdrops
|
||||
- Poster cache management UI
|
||||
|
||||
- [ ] **Progress Indicators**
|
||||
- Show scan progress
|
||||
- Batch operation progress bars
|
||||
- Background task status
|
||||
|
||||
### TMDB Integration
|
||||
|
||||
- [ ] **Full Movie Details**
|
||||
- Cast and crew information
|
||||
- Production companies
|
||||
- Budget and revenue data
|
||||
- Release dates by region
|
||||
|
||||
- [ ] **Genre Name Expansion**
|
||||
- Show full genre names instead of IDs
|
||||
- Genre-based filtering
|
||||
- Multi-genre support
|
||||
|
||||
- [ ] **TV Show Support**
|
||||
- Episode and season metadata
|
||||
- TV show renaming patterns
|
||||
- Episode numbering detection
|
||||
|
||||
- [ ] **Collection/Series Support**
|
||||
- Detect movie collections
|
||||
- Group related media
|
||||
- Collection-based renaming
|
||||
|
||||
### Technical Improvements
|
||||
|
||||
- [ ] **Undo/Redo Functionality**
|
||||
- Track file operations history
|
||||
- Undo renames
|
||||
- Redo operations
|
||||
- Operation log
|
||||
|
||||
- [ ] **Performance Optimization**
|
||||
- Lazy loading for large directories
|
||||
- Virtual scrolling in tree view
|
||||
- Background metadata extraction
|
||||
- Smart cache invalidation
|
||||
|
||||
### Build and Distribution
|
||||
|
||||
- [ ] **Build Script Improvements**
|
||||
- Exclude dev commands from distribution
|
||||
- Automated release workflow
|
||||
- Cross-platform testing
|
||||
|
||||
- [ ] **Package Distribution**
|
||||
- PyPI publication
|
||||
- Homebrew formula
|
||||
- AUR package
|
||||
- Docker image
|
||||
|
||||
---
|
||||
|
||||
## Potential Future Features
|
||||
|
||||
### Advanced Features
|
||||
|
||||
- [ ] Subtitle downloading and management
|
||||
- [ ] NFO file generation
|
||||
- [ ] Integration with media servers (Plex, Jellyfin, Emby)
|
||||
- [ ] Watch history tracking
|
||||
- [ ] Duplicate detection
|
||||
- [ ] Quality comparison (upgrade detection)
|
||||
|
||||
### Integrations
|
||||
|
||||
- [ ] Multiple database support (TVDB, Trakt, AniDB)
|
||||
- [ ] Custom API integrations
|
||||
- [ ] Local database option (offline mode)
|
||||
- [ ] Webhook support for automation
|
||||
|
||||
### Export/Import
|
||||
|
||||
- [ ] Export catalog to CSV/JSON
|
||||
- [ ] Import rename mappings
|
||||
- [ ] Backup/restore settings
|
||||
- [ ] Configuration profiles
|
||||
|
||||
---
|
||||
|
||||
## Known Issues
|
||||
|
||||
See [REFACTORING_PROGRESS.md](REFACTORING_PROGRESS.md) for current limitations and planned fixes.
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Before working on any task:
|
||||
|
||||
1. Check [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md) for architecture details
|
||||
2. Review [CHANGELOG.md](CHANGELOG.md) for recent changes
|
||||
3. Read [DEVELOP.md](DEVELOP.md) for development setup
|
||||
4. Run tests: `uv run pytest`
|
||||
5. Follow code standards in [ENGINEERING_GUIDE.md](ENGINEERING_GUIDE.md#code-standards)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-01-01
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
class TestBackwardCompatibility:
|
||||
"""Test backward compatibility with old import paths."""
|
||||
|
||||
def test_import_from_decorators(self):
|
||||
"""Test importing from renamer.decorators still works."""
|
||||
from renamer.decorators import cached_method
|
||||
assert cached_method is not None
|
||||
class TestCachePackageImports:
|
||||
"""Test cache package import paths."""
|
||||
|
||||
def test_import_cache_from_package(self):
|
||||
"""Test importing Cache from renamer.cache package."""
|
||||
from renamer.cache import Cache as PackageCache
|
||||
assert PackageCache is not None
|
||||
|
||||
def test_import_decorators_from_cache(self):
|
||||
"""Test importing decorators from renamer.cache."""
|
||||
from renamer.cache import cached_method, cached, cached_api, cached_property
|
||||
assert cached_method is not None
|
||||
assert cached is not None
|
||||
assert cached_api is not None
|
||||
assert cached_property is not None
|
||||
|
||||
def test_create_cache_convenience_function(self):
|
||||
"""Test the create_cache convenience function."""
|
||||
from renamer.cache import create_cache
|
||||
|
||||
Reference in New Issue
Block a user