92 lines
3.5 KiB
Markdown
92 lines
3.5 KiB
Markdown
# 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`).
|