- Move phase/plan docs into docs/ - Move legacy node:test files into tests/legacy/ with README - Remove .backup file, test audit artifacts, and unused AI prompt/skill files - Remove broken iOS GitHub workflows (reference missing MovieMapper-iOS/)
320 lines
8.3 KiB
Markdown
320 lines
8.3 KiB
Markdown
# MovieMapper Feature Specification
|
|
|
|
## Project Overview
|
|
A desktop application for organizing and managing movie and TV show collections with intelligent file mapping using TheTVDB API.
|
|
|
|
## Current State
|
|
- Electron-based application (v40.4.1)
|
|
- TheTVDB v4 API integration with bearer token authentication
|
|
- FFmpeg-based media file metadata extraction
|
|
- Basic file renaming and directory navigation
|
|
- Audit logging to `.audit` files
|
|
|
|
## Target Architecture
|
|
- **Main Process**: Rust backend with Node.js Electron bridge
|
|
- **Renderer Process**: Electron web UI (unchanged)
|
|
- **Performance**: Native Rust for CPU-intensive operations
|
|
|
|
## Core Features
|
|
|
|
### 1. Directory Scanning (Rust Implementation)
|
|
**Priority**: High
|
|
**Status**: Current - Node.js, Target - Rust
|
|
|
|
**Requirements**:
|
|
- Non-recursive directory scanning
|
|
- Media file detection (mp4, mkv, avi, mov, flv, webm)
|
|
- FFmpeg metadata extraction (duration, quality, FPS)
|
|
- Progress callback support for UI updates
|
|
- Permission error handling
|
|
|
|
**API**:
|
|
```rust
|
|
pub struct FileMetadata {
|
|
pub path: String,
|
|
pub name: String,
|
|
pub size: u64,
|
|
pub modified: SystemTime,
|
|
pub duration: String,
|
|
pub quality: String,
|
|
pub fps: String,
|
|
pub is_folder: bool,
|
|
}
|
|
|
|
pub fn scan_directory(
|
|
directory_path: &str,
|
|
progress_callback: Option<Box<dyn Fn(u32, u32, &str) + Send>>
|
|
) -> Result<Vec<FileMetadata>, ScanError>;
|
|
```
|
|
|
|
### 2. FFmpeg Integration (Rust Implementation)
|
|
**Priority**: High
|
|
**Status**: Current - fluent-ffmpeg, Target - ffmpeg-kit or rust-ffmpeg
|
|
|
|
**Requirements**:
|
|
- ffprobe for metadata extraction
|
|
- Duration calculation (mm:ss format)
|
|
- Video quality detection (4K, 1440p, 1080p, 720p, 480p)
|
|
- Frame rate extraction
|
|
- Graceful error handling for corrupted files
|
|
|
|
**API**:
|
|
```rust
|
|
pub struct VideoStreamInfo {
|
|
pub width: u32,
|
|
pub height: u32,
|
|
pub codec: String,
|
|
pub frame_rate: f64,
|
|
}
|
|
|
|
pub struct AudioStreamInfo {
|
|
pub codec: String,
|
|
pub channels: u32,
|
|
pub sample_rate: u32,
|
|
}
|
|
|
|
pub struct MediaInfo {
|
|
pub duration: f64, // seconds
|
|
pub format: String,
|
|
pub video_streams: Vec<VideoStreamInfo>,
|
|
pub audio_streams: Vec<AudioStreamInfo>,
|
|
}
|
|
|
|
pub fn probe_file(path: &str) -> Result<MediaInfo, ProbeError>;
|
|
```
|
|
|
|
### 3. TheTVDB API Integration (Rust Implementation)
|
|
**Priority**: High
|
|
**Status**: Current - axios, Target - reqwest with async/await
|
|
|
|
**Requirements**:
|
|
- TVDB v4 API authentication (apikey → token)
|
|
- Show search with query
|
|
- Show details with seasons
|
|
- Episode listing per season
|
|
- Token caching (30-day validity)
|
|
- Rate limiting handling
|
|
|
|
**API**:
|
|
```rust
|
|
pub struct Show {
|
|
pub id: u64,
|
|
pub name: String,
|
|
pub status: Option<String>,
|
|
pub first_aired: Option<String>,
|
|
pub overview: Option<String>,
|
|
pub image: Option<String>,
|
|
pub slug: Option<String>,
|
|
}
|
|
|
|
pub struct Season {
|
|
pub id: u64,
|
|
pub number: u32,
|
|
pub episode_count: u32,
|
|
}
|
|
|
|
pub struct Episode {
|
|
pub id: u64,
|
|
pub name: String,
|
|
pub number: u32,
|
|
pub season_number: u32,
|
|
pub aired: Option<String>,
|
|
pub overview: Option<String>,
|
|
}
|
|
|
|
pub struct TVDBClient {
|
|
token: Option<String>,
|
|
api_key: String,
|
|
}
|
|
|
|
impl TVDBClient {
|
|
pub fn new(api_key: String) -> Self;
|
|
pub async fn search(&self, query: &str) -> Result<Vec<Show>, TVDBError>;
|
|
pub async fn get_show_details(&self, show_id: u64) -> Result<Show, TVDBError>;
|
|
pub async fn get_seasons(&self, show_id: u64) -> Result<Vec<Season>, TVDBError>;
|
|
pub async fn get_episodes(&self, show_id: u64, season_number: u32) -> Result<Vec<Episode>, TVDBError>;
|
|
}
|
|
```
|
|
|
|
### 4. File Operations (Rust Implementation)
|
|
**Priority**: High
|
|
**Status**: Current - Node.js fs, Target - std::fs + tokio
|
|
|
|
**Requirements**:
|
|
- File renaming with atomic operations
|
|
- Directory creation (recursive)
|
|
- File movement to folder (extras, commentary, etc.)
|
|
- Audit log writing
|
|
- Conflict detection (duplicate files)
|
|
|
|
**API**:
|
|
```rust
|
|
pub struct AuditLogEntry {
|
|
pub timestamp: String,
|
|
pub action: AuditAction,
|
|
pub details: HashMap<String, String>,
|
|
}
|
|
|
|
pub enum AuditAction {
|
|
RenameFile { old_path: String, new_path: String },
|
|
MoveFile { original_path: String, new_path: String, folder: String },
|
|
}
|
|
|
|
pub struct FileManager {
|
|
base_path: String,
|
|
}
|
|
|
|
impl FileManager {
|
|
pub fn new(base_path: &str) -> Self;
|
|
pub async fn rename_file(&self, old_path: &str, new_name: &str) -> Result<(), FileError>;
|
|
pub async fn move_to_folder(&self, file_path: &str, folder_name: &str) -> Result<String, FileError>;
|
|
pub async fn write_audit_log(&self, action: AuditAction) -> Result<(), FileError>;
|
|
}
|
|
```
|
|
|
|
### 5. File Mapping/Batch Rename (Rust Implementation)
|
|
**Priority**: High
|
|
**Status**: Current - Node.js, Target - Rust
|
|
|
|
**Requirements**:
|
|
- Parse show name from folder
|
|
- Extract season number (multiple formats: "Season 01", "S01", etc.)
|
|
- Map files to episodes using TVDB data
|
|
- Handle single episodes and episode ranges (1-3)
|
|
- Quality suffix support
|
|
- Folder naming with TVDB ID
|
|
|
|
**API**:
|
|
```rust
|
|
pub struct EpisodeMapping {
|
|
pub show_name: String,
|
|
pub season_number: u32,
|
|
pub episodes: Vec<EpisodeRange>,
|
|
pub quality: Option<String>,
|
|
}
|
|
|
|
pub struct EpisodeRange {
|
|
pub start: u32,
|
|
pub end: u32,
|
|
}
|
|
|
|
pub struct MappingResult {
|
|
pub success_count: u32,
|
|
pub error_count: u32,
|
|
pub renamed_files: Vec<String>,
|
|
}
|
|
|
|
pub async fn begin_mapping(
|
|
directory: &str,
|
|
files: Vec<MediaFile>,
|
|
tvdb_id: u64,
|
|
client: &TVDBClient
|
|
) -> Result<MappingResult, MappingError>;
|
|
```
|
|
|
|
### 6. IPC Bridge (Rust Implementation)
|
|
**Priority**: Medium
|
|
**Status**: Current - Direct ipcMain/handle, Target - Node.js addon or IPC socket
|
|
|
|
**Requirements**:
|
|
- Node.js native addon or IPC interface
|
|
- Async message handling
|
|
- Progress event streaming
|
|
- Error propagation
|
|
|
|
**API**:
|
|
```rust
|
|
#[repr(C)]
|
|
pub struct IpcMessage {
|
|
pub channel: *const c_char,
|
|
pub data: *const c_char,
|
|
}
|
|
|
|
pub type IpcCallback = extern "C" fn(channel: *const c_char, data: *const c_char);
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn init_ipc(callback: IpcCallback);
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn handle_request(channel: *const c_char, data: *const c_char) -> *const c_char;
|
|
```
|
|
|
|
## Implementation Phases
|
|
|
|
### Phase 1: Core Foundation (Weeks 1-2)
|
|
- [ ] Set up Rust project structure
|
|
- [ ] Implement FileMetadata and scan_directory
|
|
- [ ] Integrate FFmpeg for metadata extraction
|
|
- [ ] Create basic error types
|
|
- [ ] Write unit tests for core utilities
|
|
|
|
### Phase 2: API Integration (Weeks 2-3)
|
|
- [ ] Implement TVDBClient with authentication
|
|
- [ ] Add show search functionality
|
|
- [ ] Implement show details and episode fetching
|
|
- [ ] Add token caching mechanism
|
|
- [ ] Write integration tests
|
|
|
|
### Phase 3: File Operations (Weeks 3-4)
|
|
- [ ] Implement FileManager with async operations
|
|
- [ ] Add audit logging
|
|
- [ ] Implement file movement and renaming
|
|
- [ ] Add conflict detection
|
|
- [ ] Write integration tests
|
|
|
|
### Phase 4: File Mapping (Weeks 4-5)
|
|
- [ ] Implement begin_mapping logic
|
|
- [ ] Add episode range handling
|
|
- [ ] Implement quality suffix logic
|
|
- [ ] Add folder naming with TVDB ID
|
|
- [ ] Write integration tests
|
|
|
|
### Phase 5: IPC Bridge (Weeks 5-6)
|
|
- [ ] Create Node.js native addon
|
|
- [ ] Implement message handling
|
|
- [ ] Add progress streaming
|
|
- [ ] Handle async callbacks
|
|
- [ ] Write integration tests
|
|
|
|
### Phase 6: Testing & Documentation (Weeks 6-7)
|
|
- [ ] Comprehensive integration tests
|
|
- [ ] Performance benchmarks
|
|
- [ ] Documentation
|
|
- [ ] Migration guide
|
|
|
|
## Technical Decisions
|
|
|
|
### FFmpeg Integration
|
|
**Option A**: ffmpeg-kit (prebuilt binaries)
|
|
- Pros: Easy setup, cross-platform
|
|
- Cons: Larger binary size
|
|
|
|
**Option B**: rust-ffmpeg (FFmpeg C bindings)
|
|
- Pros: Full control, smaller binary
|
|
- Cons: Build complexity, dependency management
|
|
|
|
**Decision**: ffmpeg-kit for rapid development and reliability
|
|
|
|
### Async Runtime
|
|
- tokio for async operations
|
|
- Standard library for sync operations
|
|
- Cross-platform async file I/O
|
|
|
|
### Error Handling
|
|
- Custom error types with meaningful messages
|
|
- Consistent error propagation
|
|
- Detailed logging for debugging
|
|
|
|
### Testing Strategy
|
|
- Unit tests for pure functions
|
|
- Integration tests for file operations
|
|
- Mock TVDB API for API tests
|
|
- Benchmark tests for performance-critical paths
|
|
|
|
## Success Criteria
|
|
- [ ] All features work identically to Node.js version
|
|
- [ ] Performance improvement for large directories
|
|
- [ ] Memory usage below Node.js baseline
|
|
- [ ] No crashes or memory leaks
|
|
- [ ] All tests passing
|
|
- [ ] Documentation complete |