Files
rippy/README.md
T
Hitonabi e84afc1718
Ampel / ampel (push) Successful in 29s
feat(transcode): ein HandBrake-Preset je Disc-Typ statt eines fuer alles
Rueckfrage des Commanders beim ersten echten UHD-Rip: "merkt Rippy, dass es
eine UHD ist, und nimmt direkt das 4K-Preset?" Antwort war nein. Die
Kompression fragte den Disc-Typ ueberhaupt nicht:

    preset = einstellungen.get("transcodePreset") or DEFAULT_HB_PRESET

Live eingestellt war "HQ 1080p30 Surround". Der gerade laufende Akira-Rip
waere also verlustfrei in 4K gerippt und danach auf 1080p heruntergerechnet
worden - und mit keepOriginal=False waere der 4K-Rohschnitt danach geloescht
worden. Umgekehrt wurde eine DVD auf 1080p hochskaliert, was nichts bringt.

- preset_fuer(disc_type, einstellungen) in ripping.py, pure und getestet.
  Reihenfolge: Preset des Disc-Typs -> allgemeines transcodePreset ->
  DEFAULT_HB_PRESET. Bestandsinstallationen aendern ihr Verhalten NICHT,
  solange die neuen Felder nicht gespeichert sind.
- Drei Einstellungen: transcodePresetDvd / transcodePresetBluray /
  transcodePresetUhd. transcodePreset bleibt als Rueckfall bestehen.
- transcode_files holt den Disc-Typ aus dem Job-Datensatz und schreibt ihn
  mit ins Log ("Disc-Typ 'uhd', Preset '...'").
- UI: drei Auswahlfelder statt einem, mit Klartext dazu, warum eine 4K-UHD
  auf ein 2160p-Preset gehoert.

Preset-Namen stammen aus "HandBrakeCLI --preset-list" im Worker-Image
(HandBrake 1.6.1) - nicht aus dem Kopf (AGENTS Regel D):
H.265 MKV 2160p60 4K, HQ 2160p60 4K HEVC Surround,
Super HQ 2160p60 4K HEVC Surround, H.265 MKV 1080p30, HQ 1080p30 Surround,
Super HQ 1080p30 Surround, H.265 MKV 576p25, H.265 MKV 480p30,
HQ 576p25 Surround.

Sofortmassnahme am laufenden Job (auf Ansage des Commanders): keepOriginal
auf True gesetzt - nur dieses eine Feld, gegengeprueft dass kein anderer
Schluessel veraendert wurde. Damit ueberlebt der 4K-Rohschnitt die
Kompression.

ACHTUNG - Deploy bewusst NICHT ausgefuehrt: docker compose up -d --build
wuerde den Worker-Container neu erstellen und den laufenden Akira-Rip
abbrechen. Erst nach Abschluss des Jobs deployen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 11:38:52 +02:00

293 lines
16 KiB
Markdown

# Rippy — die All-in-one Disc-Ripping-Maschine
Disc rein → automatisch erkannt (Titel, Poster, Metadaten) → verlustfrei
gerippt (MakeMKV) → auf Arbeitsgröße komprimiert (HandBrake) → fertig
abgelegt, wo DU willst (lokal, NAS, jede Freigabe). Modernes Web-UI,
Echtzeit-Fortschritt, komplett in Docker, komplett lokal.
## Schnellstart
Voraussetzungen: Docker + Docker Compose, ein optisches Laufwerk am Host.
```bash
git clone <repo-url> rippy && cd rippy
cp .env.example .env # optional: API-Keys — geht auch später im UI
mkdir -p /srv/rippy/media # Ablage-Basis (anpassbar in docker-compose.yml)
docker compose up -d --build
```
Dann `http://<host>` öffnen — der **Einrichtungs-Assistent** startet beim
ersten Mal automatisch (API-Keys, Verarbeitung, erkannte Hardware).
### Laufwerk anpassen
Der Worker braucht **zwei** Host-Geräteknoten: den CD-ROM-Knoten (meist
`/dev/sr0`) und den passenden **SCSI-Generic-Knoten** (`/dev/sgN`) — MakeMKV
spricht Laufwerke über die sg-Schicht an. Die sg-Nummer ist **je Host anders**
(auf frischen Systemen oft `/dev/sg0`).
Ermitteln, welche Knoten dein Blu-ray/DVD-Laufwerk hat:
```bash
lsscsi -g # zeigt Modell + zugehörigen /dev/sgN
# oder: ls -la /sys/class/scsi_generic/
```
Dann in der `.env` eintragen (Defaults passen für den Ursprungs-Host):
```bash
OPTICAL_SR=/dev/sr0 # CD-ROM-Knoten deines Laufwerks
OPTICAL_SG=/dev/sg0 # sg-Knoten deines Laufwerks
```
`docker compose up -d` nutzt diese Werte. (Für Feineinstellungen geht weiterhin
eine `docker-compose.override.yml` mit eigenen `devices:`-Einträgen.)
**Laufwerk in einer VM?** Per USB-Passthrough anhand der Vendor-ID
durchreichen (Proxmox: `qm set <vmid> -usb0 host=xxxx:yyyy,usb3=1`) —
NICHT als emuliertes CD-ROM (`media=cdrom`), das kann keine SCSI-Kommandos.
## Wie es funktioniert
1. **Disc-Wache** (ioctl-Polling, kein udev-Gefrickel) erkennt Einlegen,
identifiziert die Disc (Volume-Label → TMDB → OMDb-Fallback) und zeigt
sie mit Poster auf dem Dashboard. Klick auf einen Job-Titel öffnet die
Detail-Ansicht (Poster, Jahr, Beschreibung, Ablagepfad).
2. **Rip** (MakeMKV, verlustfrei — der einzige Weg durch AACS): Ziel wählst
du beim Start (Filme/Serien/Musik/eigener Pfad, inkl. Netzwerk-Ziele) —
oder du stellst die **Vollautomatik** an (Einstellungen → Ripping) und
der Rip startet ohne Nachfrage in den passenden Schnellwahl-Ordner.
Optional **nur Hauptfilm** (längster Titel, Extras bleiben weg). Bereits
gerippte Discs erkennt Rippy am Fingerabdruck und warnt. Vor dem Start
prüft Rippy den freien Platz gegen die Disc-Größe. Alle Tonspuren und
Untertitel bleiben erhalten (wichtig für Anime/O-Ton). Audio-CDs laufen
über abcde → FLAC + MusicBrainz.
**Serien**: Im Dialog „Serien" wählen → Serienname + Staffel angeben —
Ablage wird `<Serie>/Season NN`, und die Episoden werden nach dem Rip
per Laufzeitabgleich (TMDB) automatisch zu „Serie S01E02.mkv" benannt
(nur bei eindeutiger Zuordnung — sonst bleiben die Namen, mit Log).
3. **Kompression** (HandBrake, eigener Job auf eigener Queue): x265/x264,
**je Disc-Typ ein eigenes Preset** (Einstellungen → Verarbeitung) —
Rippy kennt den Typ und wählt selbst. Wichtig, weil ein 1080p-Preset
eine 4K-UHD stillschweigend herunterrechnet und ein 1080p-Preset eine
DVD sinnlos hochskaliert. Sind die drei Felder nie gespeichert worden,
gilt weiter das alte allgemeine Preset — Bestandsinstallationen ändern
ihr Verhalten also nicht von selbst.
Rohdatei wird erst nach Erfolg gelöscht
(„Original behalten" als Option). Fehlgeschlagene Kompressionen lassen
sich ohne Neu-Rip neu anstoßen.
4. **Media-Server-Ablage**: Unter Einstellungen → Ripping (oder im
Einrichtungs-Assistenten) wählst du dein System — Jellyfin, Emby, Kodi,
Plex oder keins. Fertige Rips heißen dann „Titel (Jahr)" statt
Job-UUID; für Jellyfin/Emby/Kodi legt Rippy zusätzlich movie.nfo +
poster.jpg dazu (Kodi-NFO-Schema, lesen alle drei nativ). Plex nutzt
nur die Benennung. **Jellyfin/Emby**: Server-URL + API-Key eintragen,
dann stößt Rippy nach jedem fertigen Rip sofort einen Bibliotheks-Scan
an — Disc rein, Film erscheint im Server.
5. **4K-UHD**: braucht **zwei** Dinge — ein LibreDrive-fähiges Laufwerk
(MakeMKV-Forum: „Ultimate UHD Drives Flashing Guide") **und** einen
passenden Disc-Schlüssel. Normale BD/DVD gehen mit jedem Laufwerk und
ohne Schlüssel-Datei.
**Der Schlüssel ist heute die eigentliche Hürde — und zwar aus einem
überraschenden Grund.** Am 25.07.2026 auf beiden Maschinen gemessen
(Akira UHD, MKB v76, Pressung Dezember 2020): Laufwerk und MakeMKV
waren in Ordnung — „Using LibreDrive mode (v06.3)", die Disc wurde
gelesen — und trotzdem kam „The volume key is unknown for this disc".
Die Ursache:
**`makemkvcon` unter Linux holt Disc-Schlüssel nie aus dem Netz. Die
Windows-Version tut es.**
Gemessen: Linux baute in keinem einzigen Lauf eine Verbindung nach
draußen auf — geprüft mit leerem und mit gefülltem Schlüsselspeicher,
mit und ohne `--noscan`, mit `dev:` und `disc:`, und mit erzwungener
frischer Prüfung. Dieselbe Disc am selben Laufwerk unter Windows: „Lade
aktuelle HK …", Verbindung zum Schlüssel-Server, Disc geht auf.
Ein MakeMKV-Update ändert daran nichts, und es ist kein Fehler in
Rippy.
**Der Weg drumherum:** MakeMKV einmal auf einem Windows-PC die Disc
öffnen lassen und die dabei gefüllte Datei `_private_data.tar` bei
Rippy unter **Einstellungen → System** hochladen (siehe unten). Für
Pressungen, die auch MakeMKV nicht kennt, bleibt die **`KEYDB.cfg`**
als Notnagel.
⚠️ **Rippy liefert keine Schlüssel mit, lädt keine herunter und
verteilt keine.** Rippy stellt nur den Platz für eine Datei bereit, die
du selbst mitbringst, und zeigt dir ehrlich an, was dort liegt.
⚠️ UHD-Rohdaten sind bis 100 GB groß — wenn die Platte der
Rippy-Maschine dafür zu klein ist, lege das **Arbeitsverzeichnis**
(Einstellungen → Verarbeitung) auf eine eingehängte Freigabe, z. B.
`/app/media/nas-arbeit`. Rippy bricht sonst VOR dem Rip mit einer
Klartext-Meldung ab statt nach 40 GB mit voller Platte.
## Speicherziele (NAS, Freigaben)
Unter **Einstellungen → Speicherziele** hängst du NFS- oder SMB-Freigaben
direkt aus dem UI ein — sie erscheinen sofort in der Ziel-Auswahl beim
Rippen und werden beim Start automatisch wieder verbunden.
Technik: der api-Container läuft mit `CAP_SYS_ADMIN` und einem
rshared-Bind auf `/srv/rippy/media`, Mounts propagieren zu allen
Containern. ⚠️ Zugangsdaten liegen unverschlüsselt in der lokalen
Postgres-DB — bewusster Heimnetz-Kompromiss; lege fürs NAS einen eigenen,
eingeschränkten Benutzer an.
## Benachrichtigungen
**Einstellungen → Benachrichtigungen**: eine Webhook-URL eintragen, „Test
senden" drücken, speichern — fertig. Rippy meldet Job-Ende (fertig,
fehlgeschlagen, abgebrochen) und erkennt den Dienst an der URL selbst:
| Dienst | URL-Beispiel | Format |
|---|---|---|
| Discord | `https://discord.com/api/webhooks/…` | `{"content": …}` |
| Slack | `https://hooks.slack.com/services/…` | `{"text": …}` |
| ntfy (Handy-Push) | `https://ntfy.sh/mein-geheimes-thema` | Roh-Text + Titel |
| Eigenes (HA, n8n, …) | beliebige HTTPS-URL | `{"title","message","level"}` |
## System, MakeMKV-Beta-Key, Disc-Schlüssel & Updates
**Einstellungen → System** zeigt die Werkzeug-Versionen jedes Workers
(MakeMKV, HandBrake), den Key-Status und den freien Speicherplatz. Der
MakeMKV-Beta-Key (wechselt ~monatlich, Forum-Thread t=1053) wird hier im
UI eingetragen und gilt ab dem **nächsten Rip** — ohne Rebuild, ohne
Neustart; er schlägt den Key aus der `.env`.
**Disc-Schlüssel für 4K-UHD** — im selben Tab, nur für UHD nötig. Der
Hauptweg zuerst:
- **Schlüsselspeicher (`_private_data.tar`)**: Rippy zeigt, **wie viele
Disc-Schlüssel** dieser Worker kennt. Steht dort 0, scheitert jede
unbekannte UHD-Disc.
**So füllst du ihn:** MakeMKV auf einem Windows-PC installieren
(gleicher Beta-Key), Laufwerk anstecken, Disc einmal öffnen — dabei lädt
MakeMKV die Schlüssel nach. Dann in MakeMKV unter *Preferences →
General* das „MakeMKV data directory" nachschlagen und die Datei
`_private_data.tar` daraus hier hochladen. Wirkt ab dem nächsten Rip;
für neue Discs gelegentlich wiederholen.
Rippy prüft die Datei und lehnt sie ab, wenn kein einziger Schlüssel
drinsteckt — sonst ändert sich nichts und niemand versteht, warum.
- **`KEYDB.cfg`** (Notnagel): nur nötig, wenn eine Pressung auch mit
gefülltem Speicher nicht aufgeht, MakeMKV sie also selbst nicht kennt.
Hochladen, Status und Entfernen genau wie oben.
- **AACS-Dumps herunterladen**: MakeMKV legt bei jeder unbekannten Disc
selbst einen Dump ab. Genau den braucht man, wenn man im MakeMKV-Forum
um den Schlüssel für eine neue Pressung bittet — hier holst du ihn dir
aus dem Container, ohne SSH.
Der Beta-Key ist die **Lizenz für die Software**, der Schlüsselspeicher
und die `KEYDB.cfg` sind **Disc-Schlüssel** — zwei völlig verschiedene
Dinge. **Rippy liefert und lädt keine Disc-Schlüssel**, es hält nur ein
persistentes Verzeichnis dafür bereit (`MAKEMKV_DATA_HOST`, siehe Tabelle
unten) — rebuild-fest, damit deine Dateien einen
`docker compose build` überleben. Der Schlüsselspeicher ist der
Zwischenspeicher **deiner eigenen** MakeMKV-Installation.
**Updates:** „Auf Updates prüfen" vergleicht mit makemkv.com und den
offiziellen HandBrake-Releases (12 h gecacht). MakeMKV-Update ohne
Code-Änderung: `MAKEMKV_VERSION=x.y.z` in die `.env`, dann
`docker compose build worker && docker compose up -d worker`.
⚠️ **Richtigstellung (25.07.2026):** Hier stand früher, neue MakeMKV-
Versionen brächten „auch die neueste Disc-Schlüssel-Datenbank mit". Das
ist widerlegt — MakeMKV liefert überhaupt keine Disc-Schlüssel mit, es
holt sie zur Laufzeit. Und die Linux-Version holt sie nie. Ein Update
lohnt für Programmfehler und neue Laufwerke, hilft aber NICHT gegen „The
volume key is unknown". Dafür brauchst du den Schlüsselspeicher (siehe
oben).
HandBrake kommt im Docker-Worker bewusst aus Debian (stabil, hinkt der
offiziellen Version hinterher); der native Windows-Worker nutzt die
aktuelle Version direkt.
## Verarbeitung & Hardware
**Einstellungen → Verarbeitung** zeigt ehrlich an, welche Encoder deine
Worker WIRKLICH haben (CPU x264/x265, VAAPI bei AMD/Intel-GPU, NVENC bei
NVIDIA) — jeder Worker meldet seine Fähigkeiten selbst beim Start.
### Optional: weitere Maschinen als Transcode-Worker
Die Kompression läuft als eigener Celery-Task auf der Queue `transcode`
JEDE Maschine im Netz kann sie übernehmen. **Einstellungen → Worker** zeigt
für beide Varianten einen Copy-Paste-Befehl:
- **Linux (Docker)**: `deploy/remote-transcode-worker.yml`
- **Windows (nativ, ohne Docker)**: braucht nur Python 3.10+ — der
Installer (`install.ps1`) kommt von der Rippy-Instanz selbst
(`/api/worker-setup/windows`), lädt Worker-Code und HandBrakeCLI
automatisch und erzeugt eine `start-worker.bat` (optional `-Autostart`).
Ohne Zusatz-Worker macht der eingebaute CPU-Worker alles selbst — Rippy
bleibt All-in-one.
## Umgebungsvariablen (.env)
| Variable | Pflicht | Zweck |
|---|---|---|
| `TMDB_API_KEY` | empfohlen | Metadaten (deutsche Texte) — alternativ im UI/Wizard; beide Key-Arten gehen (v3-Schlüssel und v4-Token) |
| `WORKER_NAME` | optional | Anzeigename des eingebauten Workers (Standard: rippy-hauptworker) |
| `OMDB_API_KEY` | optional | zweite Metadaten-Quelle (Fallback) |
| `THETVDB_API_KEY` | optional | Serien-Fallback |
| `MAKEMKV_APP_KEY` | optional | MakeMKV-Beta-Key (Forum); DVDs gehen ohne — bequemer: im UI unter Einstellungen → System pflegen |
| `MAKEMKV_URL_BASE` | optional | alternative Download-Quelle für den Image-Build |
| `MAKEMKV_DATA_HOST` | optional | Host-Verzeichnis für MakeMKVs Daten (Default `/srv/rippy/makemkv`) — hier liegen dein Schlüsselspeicher `_private_data.tar`, eine etwaige `KEYDB.cfg` und die AACS-Dumps; persistent, überlebt jeden Rebuild |
| `OPTICAL_SR` | je Host | Host-Pfad des CD-ROM-Knotens (Default `/dev/sr0`) — siehe „Laufwerk anpassen" |
| `OPTICAL_SG` | je Host | Host-Pfad des sg-Knotens des Laufwerks (Default `/dev/sg1`; oft `/dev/sg0`) |
| `POSTGRES_PASSWORD` | optional | DB-Passwort (Default `rippy`) — für exponierte Umgebungen ein starkes Passwort setzen |
UI-Einstellungen (Wizard/Settings) überstimmen die Env-Variablen.
## Rippy woanders bereitstellen
Rippy ist reines Docker Compose — es läuft auf **jedem Linux-Host mit
Docker**, nicht nur auf der Original-VM. Es gibt (noch) keine fertigen
Registry-Images; gebaut wird beim ersten `up` direkt aus dem Repo.
Voraussetzungen auf dem Ziel-Host:
1. Linux (x86_64) mit Docker + Compose-Plugin.
2. Ein optisches Laufwerk, das der Host sieht (`ls /dev/sr* /dev/sg*`).
In einer VM: per **USB-Passthrough** (Vendor-ID) durchreichen, NICHT
als emuliertes CD-ROM — siehe „Laufwerk anpassen" oben.
3. Ablage-Basis anlegen: `mkdir -p /srv/rippy/media` (oder Pfad in
`docker-compose.yml` anpassen). Der Bind nutzt **shared/slave-Propagation**
(fürs In-UI-Einhängen von NAS-Freigaben). Auf den meisten systemd-Linux-Hosts
ist `/` schon `rshared`, dann ist nichts zu tun. Bricht `docker compose up`
mit *„path … is mounted on / but it is not a shared mount"* ab, einmalig:
```bash
sudo mount --bind /srv/rippy/media /srv/rippy/media
sudo mount --make-rshared /srv/rippy/media
```
(reboot-fest als systemd-`.mount`-Unit persistieren.) Braucht einen klassischen
Linux-Docker-Host mit `SYS_ADMIN` — nicht Docker-Desktop/rootless/Podman.
4. MakeMKV-Datenverzeichnis anlegen: `mkdir -p /srv/rippy/makemkv` (oder
eigenen Pfad über `MAKEMKV_DATA_HOST` in der `.env`). Dort liegen
MakeMKVs Programmzustand, die AACS-Dumps und — falls du 4K-UHD rippst —
dein Schlüsselspeicher (`_private_data.tar`) sowie eine etwaige
`KEYDB.cfg`. Das Verzeichnis gehört dem Host, damit ein
`docker compose build` deine Dateien nicht wegwirft.
Dann wie im Schnellstart: klonen, `.env` füllen, `docker compose up -d
--build`, `http://<host>` öffnen — der Einrichtungs-Assistent führt durch
den Rest (API-Keys, Media-Server, Verarbeitung). Updates: `git pull &&
docker compose up -d --build`.
Nicht mitnehmen musst du: Gitea, Arcane, den CI-Runner — das ist die
Entwicklungs-Infrastruktur DIESER Installation, nicht Teil von Rippy.
### Härtung für fremde/exponierte Netze
Rippy ist bewusst **Heimnetz-only**: Es hat **keine Authentifizierung**, und
Redis + PostgreSQL veröffentlichen Ports auf allen Interfaces (für Remote-Worker).
Im vertrauten LAN ist das ein akzeptierter Kompromiss — **exponiere Rippy niemals
ungeschützt an ein unsicheres oder öffentliches Netz.** Wer es weiter absichern will:
- **Zugriff kapseln:** API (`:8000`) und UI hinter einen Reverse-Proxy mit Auth
(Basic-/Forward-Auth) legen oder nur über VPN erreichbar machen; Port `8000`
nicht auf `0.0.0.0` binden.
- **DB/Broker abschotten:** `POSTGRES_PASSWORD` in der `.env` auf ein starkes
Passwort setzen; die Ports `5432`/`6379` nur an ein internes/VPN-Interface binden
(z. B. `"10.0.0.5:5432:5432"`) statt an `0.0.0.0`; Redis mit `--requirepass
<geheim>` starten und das Passwort in `REDIS_URL` ergänzen.
- **CORS:** `main.py` erlaubt aktuell `*` (nötig, weil UI und API getrennte Ports
sind) — hinter einem Proxy auf die echte UI-Herkunft einschränken.
- **NAS-Zugangsdaten** liegen bewusst im Klartext in der DB — ein weiterer Grund,
den DB-Port nie offen ins unsichere Netz zu hängen.
## Entwicklung
CI („Ampel") läuft bei jedem Push: Ruff, pytest, Vite-Build. Es gibt genau
einen Branch, `main` (Single Source of Truth) — die Ampel prüft nur,
deployt wird direkt aus `main`. Rot heißt: nicht deployen.
Regeln für Beiträge: [AGENTS.md](AGENTS.md) · Konzept: [KONZEPT.md](KONZEPT.md) ·
Fahrplan: [ROADMAP.md](ROADMAP.md)