MovieMapper/README.md
Jarian Cottingham d0c673398d
Some checks are pending
CI / lint (push) Waiting to run
CI / test (push) Waiting to run
CI / docker-build (push) Waiting to run
CI / security (push) Waiting to run
CI / build-result (push) Blocked by required conditions
docs: point CI badge at Gitea Actions (was bogus GitHub URL)
2026-08-21 15:50:35 +00:00

7.7 KiB

MovieMapper

Desktop application for organizing and managing movie and TV show collections. Scan media directories, extract metadata with FFmpeg, tag files as extras or commentary, and move them into Jellyfin-compatible folder structures — with a full audit trail.

CI License: MIT

Features

  • Directory scanning — non-recursive folder browsing with real-time progress
  • Metadata extraction — duration, video quality, and FPS via ffprobe
  • File tagging — mark files as extra or commentary with visual state
  • Jellyfin-compatible moves — tagged files move into spec-compliant folders (extras/, commentary/, behind the scenes/, ...)
  • TheTVDB integration — search shows, browse seasons/episodes, map episodes to SxxExx naming convention
  • Audit logging — every move/rename writes a .audit entry in the target directory; nothing happens silently
  • Progress reporting — IPC-driven progress updates during scans

Architecture

Three implementations share the same core concepts (scanner → metadata → tagging → mapping → audit):

┌─────────────────────────────────────────────────────────────┐
│                     MovieMapper                             │
├──────────────┬──────────────────────────┬───────────────────┤
│  Electron    │  Rust core (crate)       │  iOS (Swift)      │
│  desktop app │  movie_mapper            │  companion client │
│              ├──────────────────────────┤                   │
│  main.js     │  model/   Show, Season,  │  SharedModels/    │
│  renderer.js │             Episode      │  Swift mirrors    │
│  index.html  │  service/               │                   │
│  utils/      │    FileScanner          │  build.sh         │
│              │    MetadataExtractor    │  archive.sh       │
│  Electron    │    TVDBClient           │  Xcode project    │
│  IPC bridge  │    FileMapper           │                   │
│              │    TagManager           │                   │
│              │    AuditLogger          │                   │
└──────────────┴──────────────────────────┴───────────────────┘
Component Stack Role
main.js, renderer.js Electron (Node 20) Desktop UI, IPC handlers, filesystem ops
utils/fileUtils.js Node + fluent-ffmpeg Directory scanning, ffprobe metadata
Rust/ (crate movie_mapper) Rust, tokio, reqwest Reusable core: scanner, TVDB client, mapper, tags, audit
backend/ (crate) Rust Async backend integration layer
ui/ (crate) Rust, Iced Native Rust UI prototype
SharedModels/ Swift Data models for the iOS companion

Data flow

directory scan ──▶ ffprobe metadata ──▶ tag (extra/commentary)
                                              │
                                              ▼
                              Jellyfin folder mapping
                                              │
                                              ▼
                              .audit log entry per operation

Project structure

├── main.js               # Electron main process (IPC, file ops, TVDB)
├── renderer.js           # Renderer process (UI state, events)
├── index.html            # UI (dark theme)
├── preload.js            # Context bridge
├── utils/fileUtils.js    # Directory scan + ffprobe metadata
├── tests/                # vitest suite (118 tests)
│   └── legacy/           # Earlier node:test integration tests
├── Rust/                 # Rust core crate (movie_mapper)
│   ├── src/service/      # Scanner, TVDB client, mapper, tags, audit
│   ├── src/model/        # Show, Season, Episode, MediaFile
│   └── tests/            # Unit, integration, e2e, benchmarks
├── backend/              # Rust backend integration crate
├── ui/                   # Rust Iced UI prototype
├── SharedModels/         # Swift models (iOS companion)
└── docs/                 # Design docs, phase summaries, plans

Installation

Installers are published on the releases page (AppImage + .deb for Linux, .dmg for macOS, .exe for Windows).

Linux — AppImage

chmod +x MovieMapper-*.AppImage
./MovieMapper-*.AppImage

Linux — Debian/Ubuntu

sudo dpkg -i MovieMapper_*_amd64.deb

Rust CLI

cargo install --path Rust

Requires Rust and ffmpeg/ffprobe on PATH (used for metadata extraction).

Getting started

Desktop app (Electron) — from source

Prerequisites: Node.js 20+, npm, ffmpeg/ffprobe on PATH.

npm install
cp .env.example .env        # add your TVDB_API_KEY
npm start

Building installers

npm run dist         # current platform
npm run dist:linux   # AppImage + deb
npm run dist:mac     # dmg (macOS only)
npm run dist:win     # nsis exe

Rust core

cargo build --workspace
cargo test --workspace

Rust CLI

The movie_mapper binary exposes the core as a command-line tool for scripting and headless use:

# List media files with metadata
movie-mapper scan /path/to/season [--json]

# Rename files to Jellyfin naming (Show S01E01 - Quality.ext)
movie-mapper map /path/to/season --show "The Show" --season 1 [--episode-start 1] [--dry-run]

# Tag / untag files (persisted to .moviemapper.json)
movie-mapper tag /path/to/media "behind the scenes"
movie-mapper untag /path/to/media "behind the scenes"

# Move tagged files into the Jellyfin folder for that tag
movie-mapper move /path/to/media "behind the scenes" [--dry-run]

# TheTVDB (requires TVDB_API_KEY)
movie-mapper tvdb search "Breaking Bad"
movie-mapper tvdb show 81189

# Show the audit log for a directory
movie-mapper audit /path/to/season

All destructive commands support --dry-run for a filesystem-safe preview. Every rename and move writes an entry to the directory's .audit log.

Configuration is read from ~/.config/movemapper/config.toml:

tvdb_api_key = "your-api-key"
media_dir = "/path/to/media"

Precedence for the API key: --tvdb-key flag > TVDB_API_KEY env var > config file.

Tests

npm test                    # vitest suite (JS)
cargo test --workspace      # Rust unit + integration

Configuration

Variable Required Description
TVDB_API_KEY for TVDB search TheTVDB v4 API token

Jellyfin folder compatibility

Moves target the Jellyfin extras folder specification: behind the scenes, deleted scenes, interviews, scenes, samples, shorts, featurettes, clips, other, extras, trailers, theme-music, backdrops.

Documentation

License

MIT