# 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 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://` ö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 -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 `/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, Preset im UI wählbar; 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 ein LibreDrive-fähiges Laufwerk (MakeMKV-Forum: „Ultimate UHD Drives Flashing Guide"). Normale BD/DVD gehen mit jedem Laufwerk. ⚠️ 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 & 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`. **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` — neue Versionen bringen auch die neueste Disc-Schlüssel-Datenbank mit. 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 | | `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. Dann wie im Schnellstart: klonen, `.env` füllen, `docker compose up -d --build`, `http://` ö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 ` 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)