# Curator Curator is a desktop app for managing a **Jellyfin-first movie and series library**. You import video files into a managed **pool**; Curator identifies them through **TMDb**, names and lays them out the way Jellyfin expects, and can generate a genre-split **miniDLNA** tree of hardlinks for simple DLNA players — without ever duplicating the video data on disk. Metadata (posters, plots, `.nfo` files) is Jellyfin's job; Curator owns the files, their names and the library structure. Written in Rust with an egui GUI. ## Concepts - **Pool** — the managed folder and the **single source of truth**. Curator imports, renames and removes files itself, so nothing moves behind its back. Each top-level folder is a **library** with a kind: | Kind | Holds | Layout | |------|-------|--------| | `movie` | movies | `Title (rok) [tmdbid-N].ext`, or a folder once a film has several versions | | `series` | series | `Series (rok) [tmdbid-N]/Season NN/SxxEyy - Series.ext` | | `mixed` | movies and series together | as above, side by side | | `homevideo` | files without a TMDb id | mirrored as-is | - **Pool index** — Curator's own metadata (TMDb id, ČSFD link, versions, tags, library settings) lives in one `.Curator.!index` JSON file at the pool root. - **miniDLNA output** — a generated tree of **hardlinks** into the pool, built from genres / years / countries / ratings. It is disposable: delete it and regenerate it at any time. ## Features - Import movies and episodes with a **TMDb id**; Czech titles come from TMDb, with **ČSFD** as a fallback and as a bridge for finding the right TMDb id. - **Multiple versions** of one film (2D/3D, 4K, director's cut) and **multi-part** films and episodes, named so Jellyfin groups them. - Subtitle sidecars follow their video through renames. - Duplicate check, video integrity check (FFmpeg), library statistics, index/disk consistency check. - Jellyfin integration: trigger a library scan, verify the pool against it. - miniDLNA tree scoped per library, with "Tipy dne" and "Nově přidané" folders. ## Requirements - Rust 1.85+ (`rustup`), for building - `ffmpeg` / `ffprobe` on `PATH` — optional, for the integrity check ## Configuration Secrets and settings are read from a `.env` file in the working directory (never committed): | Variable | Purpose | |----------|---------| | `TMDB_API_KEY` | TMDb API key — needed to identify movies and series | | `TMDB_LANGUAGE` | TMDb language, default `cs-CZ` | | `JELLYFIN_URL` | Jellyfin server URL — optional, for the Jellyfin menu | | `JELLYFIN_API_KEY` | Jellyfin API key — optional | | `ENV_DEBUG` | `true` enables debug logging and the `-DEV` title | The pool and output folders are chosen in the app (*Pool* menu) and stored in the global config (`~/.config/curator/.Curator.!gtag` on Linux, overridable with `CURATOR_CONFIG`). ## Running ```bash cargo run --release ``` ## Development ```bash cargo fmt # format cargo clippy -- -D warnings # lint cargo test # unit tests + headless UI tests cargo doc --open # API reference ``` `cargo run --example screenshot -- out.png [--action edit]` renders the window offscreen to a PNG. Architecture and module overview: [`docs/`](docs/README.md). ## Building ```bash cargo build --release ``` The result is `target/release/curator`, plus `target/release/tipy-dne` — a standalone "Tipy dne" refresher meant for a systemd timer (see `scripts/tipy-dne.service` / `.timer`).