Jarian Cottingham 43114cfe3c feat: release packaging — electron-builder installers + release pipeline
- electron-builder config: AppImage/deb (linux), dmg (mac), nsis (win)
- app icon, desktopName sync, deb maintainer metadata
- move electron to devDependencies; add author/license/repo metadata
- pin @noble/hashes 1.8.0 (electron-builder 26 ESM conflict)
- .github/workflows/release.yml: tag-triggered multi-OS build + release
- scripts/publish-release.sh: upload dist/ assets to a Gitea release
- README: installation + installer build instructions
- add missing .env.example
- verified locally: AppImage + deb build, deb structure checks out,
  118 JS tests still green
2026-08-20 20:46:35 +00:00
2026-08-19 21:23:54 -05:00

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

Description
Rust desktop app for organizing Blu-ray/TV archives — ffprobe metadata, extras/commentary tagging, and Jellyfin-compatible moves with audit trail.
Readme MIT 574 KiB
Languages
JavaScript 53.3%
Rust 41.4%
HTML 2.7%
Shell 1.2%
Python 0.7%
Other 0.7%