docs: rewrite README, add GitHub Actions CI

This commit is contained in:
Jarian Cottingham 2026-08-20 20:18:56 +00:00
parent 7ee8f14f3d
commit 0447acd6c5
2 changed files with 165 additions and 19 deletions

38
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,38 @@
name: Test
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
js:
name: JavaScript (vitest)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm test
rust:
name: Rust (workspace)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy rustfmt
- uses: Swatinem/rust-cache@v2
with:
workspaces: Rust->target backend->target ui->target
- name: Check
run: cargo check --workspace
- name: Clippy
run: cargo clippy --workspace --all-targets
- name: Test
run: cargo test --workspace

146
README.md
View File

@ -1,30 +1,138 @@
# MovieMapper # MovieMapper
A desktop application for organizing and managing movie and TV show collections. 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](https://github.com/actions/workflows/test.yml/badge.svg)](https://github.com/actions/workflows/test.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
## Features ## Features
- Browse and scan directories for media files - **Directory scanning** — non-recursive folder browsing with real-time progress
- Search TV shows using TheTVDB API - **Metadata extraction** — duration, video quality, and FPS via `ffprobe`
- View show details, seasons, and episodes - **File tagging** — mark files as `extra` or `commentary` with visual state
- Rename files by clicking on the file name - **Jellyfin-compatible moves** — tagged files move into spec-compliant folders
- Display video durations in mm:ss format (`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
## Installation ## Architecture
1. Clone the repository Three implementations share the same core concepts (scanner → metadata →
2. Install dependencies: `npm install` tagging → mapping → audit):
3. Run the application: `npm start` or `electron .`
## Dependencies ```
┌─────────────────────────────────────────────────────────────┐
│ 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 │ │
└──────────────┴──────────────────────────┴───────────────────┘
```
- Electron | Component | Stack | Role |
- fluent-ffmpeg (for video duration detection) |-----------|-------|------|
- TheTVDB API integration | `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 |
## Usage ### Data flow
1. Click "Select Directory" to choose a folder containing media files ```
2. The application will scan the directory and display media files with their durations directory scan ──▶ ffprobe metadata ──▶ tag (extra/commentary)
3. Click on any file name to rename it
4. Use the search functionality to find TV shows and their details
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
```
## Getting started
### Desktop app (Electron)
Prerequisites: Node.js 20+, npm, `ffmpeg`/`ffprobe` on PATH.
```bash
npm install
cp .env.example .env # add your TVDB_API_KEY
npm start
```
### Rust core
```bash
cargo build --workspace
cargo test --workspace
```
### Tests
```bash
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](https://docs.jellyfin.org/):
`behind the scenes`, `deleted scenes`, `interviews`, `scenes`, `samples`,
`shorts`, `featurettes`, `clips`, `other`, `extras`, `trailers`,
`theme-music`, `backdrops`.
## Documentation
- [Project overview](docs/PROJECT_OVERVIEW.md)
- [Feature matrix](docs/FEATURES.md)
- [Rust implementation notes](docs/RUST_IMPLEMENTATION.md)
- [Folder navigation design](docs/FOLDER_NAVIGATION_PLAN.md)
- [iOS plan](docs/iOS_PLAN.md)
## License
[MIT](LICENSE)