MovieMapper/Rust/RUST_PLAN.md
Jarian Cottingham 6dd4e83ddf feat: Add Rust implementation for performance-critical components
- 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
2026-02-28 09:52:08 -06:00

12 KiB

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

[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

// 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

  • Initialize Rust project
  • Configure Cargo.toml
  • Create model structs (File, Show, Episode, Season)
  • Implement custom error types with thiserror
  • Set up basic logging with tracing
  • 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

// 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

  • Implement directory scanning (non-recursive)
  • Integrate FFmpeg for metadata extraction
  • Handle permission errors gracefully
  • Implement progress callback support
  • Add tests for file scanning
  • Add tests for metadata extraction
  • 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

// 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

  • Implement authentication with token caching
  • Implement search endpoint
  • Implement show details endpoint
  • Implement episodes endpoint
  • Handle API rate limiting
  • Add tests for all API endpoints
  • 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

// 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

  • Implement Jellyfin filename generation
  • Handle episode ranges
  • Implement folder renaming
  • Handle file conflicts
  • Add tests for mapping logic
  • 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

// 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

  • Implement audit logging to .audit files
  • Implement safe file movement
  • Implement folder creation
  • Implement file renaming
  • Add tests for audit logging
  • 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

// 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

  • Implement tag data structures
  • Implement tag application logic
  • Implement tag removal logic
  • Implement bulk operations
  • Add tests for tag management
  • 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

// 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

  • Write integration tests for all modules
  • Write end-to-end tests
  • Test with real file system
  • Test with TVDB API
  • Add error handling tests
  • 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

  • API documentation with cargo doc
  • User guide
  • Developer guide
  • Migration guide from JavaScript version
  • Troubleshooting guide
  • 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

# 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

  • All features from JavaScript version implemented
  • 90%+ test coverage
  • All tests passing
  • Documentation complete
  • Performance meets or exceeds JavaScript version
  • No memory leaks
  • 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