- Implement core Rust backend with FFmpeg integration - Add TheTVDB API client with token caching - Implement directory scanner with progress callbacks - Create file manager with rename and move operations - Add audit logging functionality - Implement file mapping for TV episode renaming - Build Node.js native addon via NAPI - Include comprehensive unit and integration tests - Update gitignore to exclude build artifacts and temp files Resolves #TBD
489 lines
12 KiB
Markdown
489 lines
12 KiB
Markdown
# MovieMapper Rust Implementation Plan
|
|
|
|
## Overview
|
|
This document outlines the implementation plan for a Rust-based version of MovieMapper. The Rust implementation will focus on the business logic layer while maintaining compatibility with the existing Electron frontend.
|
|
|
|
## Project Structure
|
|
```
|
|
Rust/
|
|
├── src/
|
|
│ ├── lib.rs
|
|
│ ├── main.rs
|
|
│ ├── model/
|
|
│ │ ├── mod.rs
|
|
│ │ ├── file.rs
|
|
│ │ ├── show.rs
|
|
│ │ └── episode.rs
|
|
│ ├── service/
|
|
│ │ ├── mod.rs
|
|
│ │ ├── file_scanner.rs
|
|
│ │ ├── file_metadata.rs
|
|
│ │ ├── tvdb_api.rs
|
|
│ │ ├── file_mapper.rs
|
|
│ │ ├── audit_logger.rs
|
|
│ │ └── tag_manager.rs
|
|
│ ├── utils/
|
|
│ │ ├── mod.rs
|
|
│ │ ├── ffmpeg.rs
|
|
│ │ ├── path.rs
|
|
│ │ └── error.rs
|
|
│ └── config/
|
|
│ ├── mod.rs
|
|
│ └── settings.rs
|
|
├── tests/
|
|
│ ├── unit/
|
|
│ │ ├── file_scanner_tests.rs
|
|
│ │ ├── file_metadata_tests.rs
|
|
│ │ ├── tvdb_api_tests.rs
|
|
│ │ ├── file_mapper_tests.rs
|
|
│ │ ├── audit_logger_tests.rs
|
|
│ │ └── tag_manager_tests.rs
|
|
│ ├── integration/
|
|
│ │ ├── integration_tests.rs
|
|
│ │ └── end_to_end_tests.rs
|
|
│ └── fixtures/
|
|
│ ├── test_files/
|
|
│ └── test_data.json
|
|
├── Cargo.toml
|
|
├── Cargo.lock
|
|
├── FEATURES.md (copied from root)
|
|
└── README.md
|
|
```
|
|
|
|
## Phase 1: Project Setup and Core Model (Week 1)
|
|
|
|
### Tasks
|
|
1. Initialize Rust project with `cargo new`
|
|
2. Configure `Cargo.toml` with dependencies
|
|
3. Create model structs
|
|
4. Implement basic error handling
|
|
5. Set up testing framework
|
|
|
|
### Dependencies
|
|
```toml
|
|
[dependencies]
|
|
serde = { version = "1.0", features = ["derive"] }
|
|
serde_json = "1.0"
|
|
tokio = { version = "1.0", features = ["full"] }
|
|
reqwest = { version = "0.11", features = ["json"] }
|
|
thiserror = "1.0"
|
|
anyhow = "1.0"
|
|
chrono = { version = "0.4", features = ["serde"] }
|
|
notify = "6.1"
|
|
tracing = "0.1"
|
|
tracing-subscriber = "0.3"
|
|
ffmpeg-next = "5.0"
|
|
dirs = "5.0"
|
|
dotenv = "0.15"
|
|
|
|
[dev-dependencies]
|
|
tempfile = "3.10"
|
|
tokio-test = "0.4"
|
|
```
|
|
|
|
### Model Structs
|
|
|
|
```rust
|
|
// src/model/file.rs
|
|
pub struct MediaFile {
|
|
pub path: PathBuf,
|
|
pub name: String,
|
|
pub size: u64,
|
|
pub modified: DateTime<Utc>,
|
|
pub duration: String,
|
|
pub quality: String,
|
|
pub fps: String,
|
|
pub is_folder: bool,
|
|
pub is_problematic: bool,
|
|
pub tags: Vec<String>,
|
|
}
|
|
|
|
// src/model/show.rs
|
|
pub struct Show {
|
|
pub id: i64,
|
|
pub series_name: String,
|
|
pub status: String,
|
|
pub first_aired: Option<String>,
|
|
pub overview: String,
|
|
pub image: String,
|
|
pub slug: String,
|
|
}
|
|
|
|
// src/model/episode.rs
|
|
pub struct Episode {
|
|
pub id: i64,
|
|
pub name: String,
|
|
pub number: i32,
|
|
pub season_number: i32,
|
|
pub aired: Option<String>,
|
|
pub runtime: Option<i32>,
|
|
}
|
|
```
|
|
|
|
### Implementation Checklist
|
|
- [x] Initialize Rust project
|
|
- [x] Configure Cargo.toml
|
|
- [x] Create model structs (File, Show, Episode, Season)
|
|
- [x] Implement custom error types with `thiserror`
|
|
- [x] Set up basic logging with `tracing`
|
|
- [x] Create unit test structure
|
|
|
|
---
|
|
|
|
## Phase 2: File Scanning and Metadata Extraction (Week 2)
|
|
|
|
### Tasks
|
|
1. Implement directory scanning
|
|
2. Integrate FFmpeg for metadata extraction
|
|
3. Implement progress reporting
|
|
4. Handle problematic files gracefully
|
|
5. Write unit tests for scanning logic
|
|
|
|
### Key Functions
|
|
|
|
```rust
|
|
// src/service/file_scanner.rs
|
|
pub struct FileScanner {
|
|
extensions: Vec<String>,
|
|
}
|
|
|
|
impl FileScanner {
|
|
pub fn new() -> Self;
|
|
pub async fn scan_directory(
|
|
&self,
|
|
path: &Path,
|
|
progress_callback: Option<&mut dyn FnMut(usize, usize, &str)>,
|
|
) -> Result<Vec<MediaFile>, ScannerError>;
|
|
pub fn is_media_file(&self, path: &Path) -> bool;
|
|
}
|
|
|
|
// src/service/file_metadata.rs
|
|
pub struct MetadataExtractor;
|
|
|
|
impl MetadataExtractor {
|
|
pub async fn extract_duration(&self, path: &Path) -> Result<String, MetadataError>;
|
|
pub async fn extract_quality(&self, path: &Path) -> Result<QualityInfo, MetadataError>;
|
|
pub async fn extract_metadata(&self, path: &Path) -> Result<MediaFileMetadata, MetadataError>;
|
|
}
|
|
```
|
|
|
|
### Implementation Checklist
|
|
- [x] Implement directory scanning (non-recursive)
|
|
- [x] Integrate FFmpeg for metadata extraction
|
|
- [x] Handle permission errors gracefully
|
|
- [x] Implement progress callback support
|
|
- [x] Add tests for file scanning
|
|
- [x] Add tests for metadata extraction
|
|
- [x] Test with problematic files
|
|
|
|
---
|
|
|
|
## Phase 3: TVDB API Integration (Week 3)
|
|
|
|
### Tasks
|
|
1. Implement authentication flow
|
|
2. Implement search functionality
|
|
3. Implement show details fetch
|
|
4. Implement season/episode fetch
|
|
5. Handle API errors and edge cases
|
|
6. Write API integration tests
|
|
|
|
### Key Functions
|
|
|
|
```rust
|
|
// src/service/tvdb_api.rs
|
|
pub struct TVDBClient {
|
|
base_url: String,
|
|
api_key: String,
|
|
token: Option<String>,
|
|
}
|
|
|
|
impl TVDBClient {
|
|
pub async fn new(api_key: &str) -> Result<Self, TVDBError>;
|
|
pub async fn authenticate(&mut self) -> Result<(), TVDBError>;
|
|
pub async fn search(&self, query: &str) -> Result<Vec<Show>, TVDBError>;
|
|
pub async fn get_show_details(&self, show_id: i64) -> Result<ShowDetails, TVDBError>;
|
|
pub async fn get_season_episodes(
|
|
&self,
|
|
show_id: i64,
|
|
season_number: i32,
|
|
) -> Result<Vec<Episode>, TVDBError>;
|
|
}
|
|
```
|
|
|
|
### Implementation Checklist
|
|
- [x] Implement authentication with token caching
|
|
- [x] Implement search endpoint
|
|
- [x] Implement show details endpoint
|
|
- [x] Implement episodes endpoint
|
|
- [x] Handle API rate limiting
|
|
- [x] Add tests for all API endpoints
|
|
- [x] Test with real API calls
|
|
|
|
---
|
|
|
|
## Phase 4: File Mapping and Renaming (Week 4)
|
|
|
|
### Tasks
|
|
1. Implement file mapping logic
|
|
2. Implement Jellyfin naming convention
|
|
3. Implement episode range handling
|
|
4. Implement folder renaming with TVDB ID
|
|
5. Handle file conflicts
|
|
6. Write comprehensive mapping tests
|
|
|
|
### Key Functions
|
|
|
|
```rust
|
|
// src/service/file_mapper.rs
|
|
pub struct FileMapper;
|
|
|
|
impl FileMapper {
|
|
pub async fn map_files(
|
|
&self,
|
|
files: &[MediaFile],
|
|
show_name: &str,
|
|
season_number: i32,
|
|
tvdb_id: Option<i64>,
|
|
) -> Result<MappingResult, MappingError>;
|
|
|
|
pub fn generate_jellyfin_filename(
|
|
&self,
|
|
show_name: &str,
|
|
season: i32,
|
|
episode_start: i32,
|
|
episode_end: i32,
|
|
quality: &str,
|
|
extension: &str,
|
|
) -> String;
|
|
}
|
|
```
|
|
|
|
### Implementation Checklist
|
|
- [x] Implement Jellyfin filename generation
|
|
- [x] Handle episode ranges
|
|
- [x] Implement folder renaming
|
|
- [x] Handle file conflicts
|
|
- [x] Add tests for mapping logic
|
|
- [x] Test with various file patterns
|
|
|
|
---
|
|
|
|
## Phase 5: Audit Logging and File Operations (Week 5)
|
|
|
|
### Tasks
|
|
1. Implement audit logging
|
|
2. Implement file movement
|
|
3. Implement folder creation
|
|
4. Handle file operations safely
|
|
5. Write tests for file operations
|
|
|
|
### Key Functions
|
|
|
|
```rust
|
|
// src/service/audit_logger.rs
|
|
pub struct AuditLogger;
|
|
|
|
impl AuditLogger {
|
|
pub fn new(directory: &Path);
|
|
pub fn log_event(&self, action: &str, details: serde_json::Value) -> Result<(), AuditError>;
|
|
}
|
|
|
|
// src/service/file_operations.rs
|
|
pub struct FileOperations;
|
|
|
|
impl FileOperations {
|
|
pub fn move_file(&self, source: &Path, destination: &Path) -> Result<(), FileError>;
|
|
pub fn create_folder(&self, path: &Path) -> Result<(), FileError>;
|
|
pub fn rename_file(&self, old_path: &Path, new_name: &str) -> Result<(), FileError>;
|
|
}
|
|
```
|
|
|
|
### Implementation Checklist
|
|
- [x] Implement audit logging to `.audit` files
|
|
- [x] Implement safe file movement
|
|
- [x] Implement folder creation
|
|
- [x] Implement file renaming
|
|
- [x] Add tests for audit logging
|
|
- [x] Add tests for file operations
|
|
|
|
---
|
|
|
|
## Phase 6: Tag Management (Week 6)
|
|
|
|
### Tasks
|
|
1. Implement tag data structures
|
|
2. Implement tag application/removal
|
|
3. Implement bulk tag operations
|
|
4. Implement tag-based file movement
|
|
5. Write tag management tests
|
|
|
|
### Key Functions
|
|
|
|
```rust
|
|
// src/service/tag_manager.rs
|
|
pub struct TagManager;
|
|
|
|
impl TagManager {
|
|
pub fn add_tag(&mut self, file_path: &Path, tag: &str) -> Result<(), TagError>;
|
|
pub fn remove_tag(&mut self, file_path: &Path, tag: &str) -> Result<(), TagError>;
|
|
pub fn get_tags(&self, file_path: &Path) -> Vec<&str>;
|
|
pub fn get_tagged_files(&self, tag: &str) -> Vec<&Path>;
|
|
pub fn move_tagged_files(&self, tag: &str, target_folder: &Path) -> Result<usize, TagError>;
|
|
}
|
|
```
|
|
|
|
### Implementation Checklist
|
|
- [x] Implement tag data structures
|
|
- [x] Implement tag application logic
|
|
- [x] Implement tag removal logic
|
|
- [x] Implement bulk operations
|
|
- [x] Add tests for tag management
|
|
- [x] Test with multiple tags
|
|
|
|
---
|
|
|
|
## Phase 7: Integration and End-to-End Testing (Week 7)
|
|
|
|
### Tasks
|
|
1. Write integration tests
|
|
2. Write end-to-end tests
|
|
3. Test with real file system
|
|
4. Test with TVDB API
|
|
5. Test error handling
|
|
6. Performance testing
|
|
|
|
### Test Scenarios
|
|
|
|
```rust
|
|
// tests/integration/file_scanner_tests.rs
|
|
#[tokio::test]
|
|
async fn test_scan_directory_with_media_files() {
|
|
// Create test directory structure
|
|
// Scan directory
|
|
// Verify results
|
|
}
|
|
|
|
// tests/integration/tvdb_api_tests.rs
|
|
#[tokio::test]
|
|
async fn test_search_and_fetch_details() {
|
|
// Search for a show
|
|
// Fetch details
|
|
// Verify results
|
|
}
|
|
|
|
// tests/integration/file_mapping_tests.rs
|
|
#[tokio::test]
|
|
async fn test_map_files_to_jellyfin_format() {
|
|
// Create test files
|
|
// Map files
|
|
// Verify renamed files
|
|
}
|
|
```
|
|
|
|
### Implementation Checklist
|
|
- [x] Write integration tests for all modules
|
|
- [x] Write end-to-end tests
|
|
- [x] Test with real file system
|
|
- [x] Test with TVDB API
|
|
- [x] Add error handling tests
|
|
- [x] Performance testing
|
|
|
|
---
|
|
|
|
## Phase 8: Documentation and Examples (Week 8)
|
|
|
|
### Tasks
|
|
1. Write comprehensive documentation
|
|
2. Create example usage
|
|
3. Write migration guide
|
|
4. Create troubleshooting guide
|
|
5. Write benchmark tests
|
|
|
|
### Documentation Checklist
|
|
- [x] API documentation with `cargo doc`
|
|
- [x] User guide
|
|
- [x] Developer guide
|
|
- [x] Migration guide from JavaScript version
|
|
- [x] Troubleshooting guide
|
|
- [x] Performance benchmarks
|
|
|
|
---
|
|
|
|
## Testing Strategy
|
|
|
|
### Unit Tests
|
|
- Test individual functions in isolation
|
|
- Mock external dependencies (FFmpeg, TVDB API)
|
|
- Aim for 90%+ code coverage
|
|
|
|
### Integration Tests
|
|
- Test module interactions
|
|
- Test with real file system
|
|
- Test with TVDB API
|
|
|
|
### End-to-End Tests
|
|
- Test complete workflows
|
|
- Test error scenarios
|
|
- Test edge cases
|
|
|
|
### Test Commands
|
|
```bash
|
|
# Run all tests
|
|
cargo test
|
|
|
|
# Run unit tests only
|
|
cargo test --lib
|
|
|
|
# Run integration tests
|
|
cargo test --test integration
|
|
|
|
# Run with coverage
|
|
cargo tarpaulin
|
|
|
|
# Run benchmarks
|
|
cargo bench
|
|
```
|
|
|
|
---
|
|
|
|
## Known Challenges and Solutions
|
|
|
|
### Challenge 1: FFmpeg Integration
|
|
**Solution**: Use `ffmpeg-next` crate for FFmpeg bindings. Handle errors gracefully and provide fallback values.
|
|
|
|
### Challenge 2: TVDB API Authentication
|
|
**Solution**: Implement token caching with expiration. Handle token refresh automatically.
|
|
|
|
### Challenge 3: File System Operations
|
|
**Solution**: Use `notify` crate for file system events. Implement atomic file operations.
|
|
|
|
### Challenge 4: Progress Reporting
|
|
**Solution**: Use callback functions for progress updates. Implement async/await for non-blocking operations.
|
|
|
|
### Challenge 5: Cross-Platform Path Handling
|
|
**Solution**: Use `PathBuf` and `Path` for all path operations. Handle platform-specific path separators.
|
|
|
|
---
|
|
|
|
## Success Criteria
|
|
|
|
- [x] All features from JavaScript version implemented
|
|
- [x] 90%+ test coverage
|
|
- [x] All tests passing
|
|
- [x] Documentation complete
|
|
- [x] Performance meets or exceeds JavaScript version
|
|
- [x] No memory leaks
|
|
- [x] Clean error handling
|
|
|
|
---
|
|
|
|
## Future Enhancements
|
|
|
|
1. **Caching Layer**: Implement caching for TVDB API responses
|
|
2. **Database Integration**: Store show and file information
|
|
3. **Advanced File Matching**: Better episode identification algorithms
|
|
4. **Export Functionality**: Export organized collections
|
|
5. **Drag and Drop UI**: Native drag and drop support
|
|
6. **Batch Operations**: Support for batch file operations
|