mirror of
https://github.com/shadoll/moma.git
synced 2026-08-28 03:27:34 +00:00
feat: Update .gitignore, AGENTS.md, README.md, CHANGELOG.md, and REFACTORING_PROGRESS.md for improved clarity and organization
This commit is contained in:
@@ -7,6 +7,7 @@ wheels/
|
|||||||
*.log
|
*.log
|
||||||
# Virtual environments
|
# Virtual environments
|
||||||
.venv
|
.venv
|
||||||
|
venv/
|
||||||
# Test-generated files
|
# Test-generated files
|
||||||
src/test/datasets/sample_mediafiles/
|
src/test/datasets/sample_mediafiles/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ moma is a sophisticated Terminal User Interface (TUI) application for managing,
|
|||||||
```
|
```
|
||||||
┌─────────────────────────────────────────┐
|
┌─────────────────────────────────────────┐
|
||||||
│ TUI Layer (Textual) │
|
│ TUI Layer (Textual) │
|
||||||
│ app.py, screens.py │
|
│ app.py, views/ │
|
||||||
└─────────────────────────────────────────┘
|
└─────────────────────────────────────────┘
|
||||||
↓
|
↓
|
||||||
┌─────────────────────────────────────────┐
|
┌─────────────────────────────────────────┐
|
||||||
@@ -241,8 +241,8 @@ year = extractor.get("year", source="Filename") # Force specific source
|
|||||||
- `MarkupFormatter`: For visual styling (colors, bold, links)
|
- `MarkupFormatter`: For visual styling (colors, bold, links)
|
||||||
- `CompositeFormatter`: For chaining multiple formatters
|
- `CompositeFormatter`: For chaining multiple formatters
|
||||||
|
|
||||||
#### FormatterApplier (`formatter.py`)
|
#### FormatterApplier
|
||||||
**Coordinator** ensuring correct formatter order:
|
Formatters are applied via decorator modules (`*_decorators.py`) using the base classes in `base.py`.
|
||||||
|
|
||||||
**Order**: Data → Text → Markup
|
**Order**: Data → Text → Markup
|
||||||
|
|
||||||
@@ -251,25 +251,17 @@ year = extractor.get("year", source="Filename") # Force specific source
|
|||||||
2. Text formatters (uppercase, lowercase, camelcase)
|
2. Text formatters (uppercase, lowercase, camelcase)
|
||||||
3. Markup formatters (bold, colors, dim, underline)
|
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
|
#### Specialized Formatters
|
||||||
- **MediaFormatter**: Main coordinator, mode-aware (technical/catalog)
|
- **CatalogFormatter** (`catalog_formatter.py`): TMDB data, ratings, genres, poster display
|
||||||
- **CatalogFormatter**: TMDB data, ratings, genres, poster display
|
- **TrackFormatter** (`track_formatter.py`): Video/audio/subtitle track formatting with colors
|
||||||
- **TrackFormatter**: Video/audio/subtitle track formatting with colors
|
- **SizeFormatter** (`size_formatter.py`): Human-readable file sizes
|
||||||
- **ProposedNameFormatter**: Intelligent rename suggestions
|
- **DurationFormatter** (`duration_formatter.py`): Duration in HH:MM:SS
|
||||||
- **SizeFormatter**: Human-readable file sizes
|
- **DateFormatter** (`date_formatter.py`): Timestamp formatting
|
||||||
- **DurationFormatter**: Duration in HH:MM:SS
|
- **ResolutionFormatter** (`resolution_formatter.py`): Resolution display
|
||||||
- **DateFormatter**: Timestamp formatting
|
- **ExtensionFormatter** (`extension_formatter.py`): File extension handling
|
||||||
- **ResolutionFormatter**: Resolution display
|
- **SpecialInfoFormatter** (`special_info_formatter.py`): Edition/source formatting
|
||||||
- **ExtensionFormatter**: File extension handling
|
- **TextFormatter** (`text_formatter.py`): Text styling utilities
|
||||||
- **SpecialInfoFormatter**: Edition/source formatting
|
- **Decorator modules** (`*_decorators.py`): Reusable display decorators per formatter type
|
||||||
- **TextFormatter**: Text styling utilities
|
|
||||||
|
|
||||||
### 5. Utility Modules (`src/utils/`)
|
### 5. Utility Modules (`src/utils/`)
|
||||||
|
|
||||||
@@ -391,7 +383,7 @@ Access via Ctrl+P:
|
|||||||
1. **OpenScreen** (`open_screen.py`): Directory selection dialog with validation
|
1. **OpenScreen** (`open_screen.py`): Directory selection dialog with validation
|
||||||
2. **HelpScreen** (`help_screen.py`): Comprehensive help with key bindings
|
2. **HelpScreen** (`help_screen.py`): Comprehensive help with key bindings
|
||||||
3. **RenameConfirmScreen** (`rename_confirm_screen.py`): File rename confirmation with error handling
|
3. **RenameConfirmScreen** (`rename_confirm_screen.py`): File rename confirmation with error handling
|
||||||
4. **ConvertConfirmScreen** (`convert_confirm_screen.py`): AVI/MP4/WebM → MKV conversion confirmation
|
4. **ConvertConfirmScreen** (`convert_confirm_screen.py`): AVI/MPG/MPEG/MP4/WebM → MKV conversion confirmation
|
||||||
5. **DeleteConfirmScreen** (`delete_confirm_screen.py`): File deletion confirmation
|
5. **DeleteConfirmScreen** (`delete_confirm_screen.py`): File deletion confirmation
|
||||||
6. **SettingsScreen** (`settings_screen.py`): Settings configuration interface
|
6. **SettingsScreen** (`settings_screen.py`): Settings configuration interface
|
||||||
|
|
||||||
@@ -402,10 +394,13 @@ Access via Ctrl+P:
|
|||||||
**Options**:
|
**Options**:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mode": "technical", // or "catalog"
|
"mode": "technical", // "technical" or "catalog"
|
||||||
"cache_ttl_extractors": 21600, // 6 hours
|
"poster": "no", // "no", "pseudo" (ASCII art), "viu", "richpixels"
|
||||||
"cache_ttl_tmdb": 21600, // 6 hours
|
"hevc_crf": 23, // HEVC quality: 18=lossless, 23=high, 28=balanced
|
||||||
"cache_ttl_posters": 2592000 // 30 days
|
"hevc_preset": "fast", // HEVC speed: ultrafast, veryfast, faster, fast, medium, slow
|
||||||
|
"cache_ttl_extractors": 21600, // 6 hours in seconds
|
||||||
|
"cache_ttl_tmdb": 21600, // 6 hours in seconds
|
||||||
|
"cache_ttl_posters": 2592000 // 30 days in seconds
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -779,8 +774,8 @@ uv run release # Bump + sync + build
|
|||||||
|
|
||||||
```
|
```
|
||||||
dist/
|
dist/
|
||||||
├── moma-0.7.0-py3-none-any.whl # Wheel distribution
|
├── moma-0.8.11-py3-none-any.whl # Wheel distribution
|
||||||
└── moma-0.7.0.tar.gz # Source distribution
|
└── moma-0.8.11.tar.gz # Source distribution
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -852,13 +847,16 @@ Title (Year) [Resolution Source Edition].ext
|
|||||||
|-----|--------|
|
|-----|--------|
|
||||||
| `q` | Quit application |
|
| `q` | Quit application |
|
||||||
| `o` | Open directory |
|
| `o` | Open directory |
|
||||||
| `s` | Scan/rescan directory |
|
| `s` | Scan current node's directory |
|
||||||
|
| `Ctrl+S` | Scan entire directory tree |
|
||||||
| `f` | Refresh metadata for selected file |
|
| `f` | Refresh metadata for selected file |
|
||||||
| `r` | Rename file with proposed name |
|
| `r` | Rename file with proposed name |
|
||||||
| `p` | Toggle tree expansion |
|
| `c` | Convert to MKV |
|
||||||
|
| `d` | Delete selected file |
|
||||||
|
| `t` | Toggle tree expansion |
|
||||||
| `m` | Toggle mode (technical/catalog) |
|
| `m` | Toggle mode (technical/catalog) |
|
||||||
|
| `p` | Settings |
|
||||||
| `h` | Show help screen |
|
| `h` | Show help screen |
|
||||||
| `Ctrl+S` | Open settings |
|
|
||||||
| `Ctrl+P` | Open command palette |
|
| `Ctrl+P` | Open command palette |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -884,7 +882,7 @@ Title (Year) [Resolution Source Edition].ext
|
|||||||
|
|
||||||
## Security Considerations
|
## Security Considerations
|
||||||
|
|
||||||
- Input sanitization for filenames (see `ProposedNameFormatter`)
|
- Input sanitization for filenames (see `ProposedFilenameView`)
|
||||||
- No shell command injection risks
|
- No shell command injection risks
|
||||||
- Safe file operations (pathlib, proper error handling)
|
- Safe file operations (pathlib, proper error handling)
|
||||||
- TMDB API key should not be committed (stored in `secrets.py`)
|
- TMDB API key should not be committed (stored in `secrets.py`)
|
||||||
|
|||||||
+1
-1
@@ -117,7 +117,7 @@ Significant refactoring focused on code quality, architecture, and maintainabili
|
|||||||
- `LanguageCodeExtractor`: Language code processing
|
- `LanguageCodeExtractor`: Language code processing
|
||||||
- `FrameClassMatcher`: Resolution/frame class matching
|
- `FrameClassMatcher`: Resolution/frame class matching
|
||||||
- **Command Palette Integration**:
|
- **Command Palette Integration**:
|
||||||
- `AppCommandProvider`: 8 main app commands
|
- `AppCommandProvider`: 11 main app commands (open, scan_local, scan, refresh, rename, convert, delete, toggle_mode, expand, settings, help)
|
||||||
- `CacheCommandProvider`: 7 cache management commands
|
- `CacheCommandProvider`: 7 cache management commands
|
||||||
- Access via Ctrl+P
|
- Access via Ctrl+P
|
||||||
|
|
||||||
|
|||||||
@@ -52,13 +52,16 @@ moma /path/to/media
|
|||||||
|-----|--------|
|
|-----|--------|
|
||||||
| `q` | Quit |
|
| `q` | Quit |
|
||||||
| `o` | Open directory |
|
| `o` | Open directory |
|
||||||
| `s` | Scan/rescan |
|
| `s` | Scan current node |
|
||||||
|
| `Ctrl+S` | Scan entire tree |
|
||||||
| `f` | Refresh metadata |
|
| `f` | Refresh metadata |
|
||||||
| `r` | Rename file |
|
| `r` | Rename file |
|
||||||
|
| `c` | Convert to MKV |
|
||||||
|
| `d` | Delete file |
|
||||||
|
| `t` | Toggle tree expansion |
|
||||||
| `m` | Toggle mode (technical/catalog) |
|
| `m` | Toggle mode (technical/catalog) |
|
||||||
| `p` | Toggle tree expansion |
|
| `p` | Settings |
|
||||||
| `h` | Show help |
|
| `h` | Show help |
|
||||||
| `Ctrl+S` | Settings |
|
|
||||||
| `Ctrl+P` | Command palette |
|
| `Ctrl+P` | Command palette |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -101,13 +104,16 @@ Toggle with `m` key.
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mode": "technical",
|
"mode": "technical",
|
||||||
|
"poster": "no",
|
||||||
|
"hevc_crf": 23,
|
||||||
|
"hevc_preset": "fast",
|
||||||
"cache_ttl_extractors": 21600,
|
"cache_ttl_extractors": 21600,
|
||||||
"cache_ttl_tmdb": 21600,
|
"cache_ttl_tmdb": 21600,
|
||||||
"cache_ttl_posters": 2592000
|
"cache_ttl_posters": 2592000
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Access via `Ctrl+S` or edit file directly.
|
Access via `p` (Settings screen) or edit file directly.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -19,94 +19,17 @@ This document tracks the future refactoring plan for moma v0.8.x+.
|
|||||||
|
|
||||||
## Pending Phases
|
## Pending Phases
|
||||||
|
|
||||||
### Phase 3.6: Cleanup and Preparation (0/2)
|
### Phase 3.6: Cleanup and Preparation (2/2 COMPLETED)
|
||||||
|
|
||||||
**Goal**: Clean up remaining issues before major refactoring.
|
|
||||||
|
|
||||||
**Status**: NOT STARTED
|
|
||||||
**Priority**: HIGH (Must complete before Phase 4)
|
|
||||||
|
|
||||||
#### 3.6.1 Refactor ProposedNameFormatter to Use Decorator Pattern
|
#### 3.6.1 Refactor ProposedNameFormatter to Use Decorator Pattern
|
||||||
**Status**: NOT STARTED
|
**Status**: ✅ COMPLETED
|
||||||
|
|
||||||
**Current Issue**: `ProposedNameFormatter` stores extracted values in `__init__` as instance variables, creating unnecessary coupling.
|
The class was renamed `ProposedFilenameView` and moved to `src/views/proposed_filename.py`. It now uses the decorator pattern with `@conditional_decorators`, `@text_decorators`, etc. — consistent with the rest of the formatter system.
|
||||||
|
|
||||||
**Goal**: Convert to functional/decorator pattern similar to other formatters.
|
|
||||||
|
|
||||||
**Current Code**:
|
|
||||||
```python
|
|
||||||
class ProposedNameFormatter:
|
|
||||||
def __init__(self, extractor):
|
|
||||||
self.__order = extractor.get('order')
|
|
||||||
self.__title = extractor.get('title')
|
|
||||||
# ... more instance variables
|
|
||||||
|
|
||||||
def rename_line(self) -> str:
|
|
||||||
return f"{self.__order}{self.__title}..."
|
|
||||||
```
|
|
||||||
|
|
||||||
**Target Design**:
|
|
||||||
```python
|
|
||||||
class ProposedNameFormatter:
|
|
||||||
@staticmethod
|
|
||||||
def format_proposed_name(extractor) -> str:
|
|
||||||
"""Generate proposed filename from extractor data"""
|
|
||||||
# Direct formatting without storing state
|
|
||||||
order = format_order(extractor.get('order'))
|
|
||||||
title = format_title(extractor.get('title'))
|
|
||||||
return f"{order}{title}..."
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def format_proposed_name_with_color(file_path, extractor) -> str:
|
|
||||||
"""Format proposed name with color highlighting"""
|
|
||||||
proposed = ProposedNameFormatter.format_proposed_name(extractor)
|
|
||||||
# Color logic here
|
|
||||||
```
|
|
||||||
|
|
||||||
**Benefits**:
|
|
||||||
- Stateless, pure functions
|
|
||||||
- Easier to test
|
|
||||||
- Consistent with other formatters
|
|
||||||
- Can use `@cached()` decorator if needed
|
|
||||||
- No coupling to extractor instance
|
|
||||||
|
|
||||||
**Files to Modify**:
|
|
||||||
- `src/formatters/proposed_name_formatter.py`
|
|
||||||
- Update all usages in `app.py`, `screens.py`, etc.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 3.6.2 Clean Up Decorators Directory
|
#### 3.6.2 Clean Up Decorators Directory
|
||||||
**Status**: NOT STARTED
|
**Status**: ✅ COMPLETED
|
||||||
|
|
||||||
**Current Issue**: `src/decorators/` directory contains legacy `caching.py` file that's no longer used. All cache decorators were moved to `src/cache/decorators.py` in Phase 1.
|
`src/decorators/` directory no longer exists. All cache decorators live in `src/cache/decorators.py`.
|
||||||
|
|
||||||
**Current Structure**:
|
|
||||||
```
|
|
||||||
src/decorators/
|
|
||||||
├── caching.py # ⚠️ LEGACY - Remove
|
|
||||||
└── __init__.py # Import from src.cache
|
|
||||||
```
|
|
||||||
|
|
||||||
**Actions**:
|
|
||||||
1. **Verify no direct imports** of `src.decorators.caching`
|
|
||||||
2. **Remove `caching.py`** - All functionality now in `src/cache/decorators.py`
|
|
||||||
3. **Keep `__init__.py`** for backward compatibility (imports from `src.cache`)
|
|
||||||
4. **Update any direct imports** to use `from src.cache import cached_method`
|
|
||||||
|
|
||||||
**Verification**:
|
|
||||||
```bash
|
|
||||||
# Check for direct imports of old caching module
|
|
||||||
grep -r "from src.decorators.caching" src/
|
|
||||||
grep -r "import src.decorators.caching" src/
|
|
||||||
|
|
||||||
# Should only find imports from __init__.py that re-export from src.cache
|
|
||||||
```
|
|
||||||
|
|
||||||
**Benefits**:
|
|
||||||
- Removes dead code
|
|
||||||
- Clarifies that all caching is in `src/cache/`
|
|
||||||
- Maintains backward compatibility via `__init__.py`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user