Files
renamer/ENGINEERING_GUIDE.md
sHa 60f32a7e8c 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.
2026-01-02 08:12:28 +00:00

945 lines
27 KiB
Markdown

# 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`