diff --git a/.env.example b/.env.example index 6712eb3..d01ca4a 100644 --- a/.env.example +++ b/.env.example @@ -7,11 +7,17 @@ POSTGRES_PASSWORD=rippy # Optisches Laufwerk (Host-Geräteknoten) — je Rechner UNTERSCHIEDLICH! # Der Worker braucht den SCSI-CD-ROM-Knoten (meist /dev/sr0) UND den passenden -# generischen sg-Knoten des Laufwerks. Die sg-Nummer variiert je Host — auf DIESER -# Maschine ermitteln: lsscsi -g (oder: ls -l /dev/sg*). Hier den HOST-Pfad des -# Blu-ray/DVD-Laufwerks eintragen; der Default passt für den Ursprungs-Host. -OPTICAL_SR=/dev/sr0 -OPTICAL_SG=/dev/sg1 +# generischen sg-Knoten des Laufwerks. +# +# BEWUSST AUSKOMMENTIERT: Die sg-Nummer ist JE HOST ANDERS. Ein vorbelegter Wert +# wäre auf den meisten Rechnern falsch — und zwar unbemerkt, weil er dann „schon +# gesetzt" aussieht. `install.sh` findet beide Knoten selbst (Abgleich über die +# SCSI-Adresse in /sys) und trägt sie hier ein. +# +# Von Hand ermitteln, falls gewünscht: lsscsi -g +# Ohne Eintrag gelten die Compose-Vorgaben /dev/sr0 und /dev/sg1. +#OPTICAL_SR=/dev/sr0 +#OPTICAL_SG=/dev/sg1 # (JWT/Auth wurde am 24.07.2026 komplett entfernt — Rippy ist Heimnetz-only, # Commander-Entscheid, siehe KONZEPT.md Abschnitt 10. Härtung für exponierte diff --git a/README.md b/README.md index a8d1c00..c827557 100644 --- a/README.md +++ b/README.md @@ -2,291 +2,374 @@ 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. +abgelegt, wo du willst (lokal, NAS, jede Freigabe). Modernes Web-UI, komplett +in Docker, komplett lokal — keine Cloud, keine Telemetrie. -## Schnellstart +--- -Voraussetzungen: Docker + Docker Compose, ein optisches Laufwerk am Host. +## Installation + +Du brauchst: einen **Linux-Rechner mit Docker** und ein **optisches Laufwerk**. ```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) +sudo ./install.sh +``` + +Das war es. Am Ende steht die Adresse im Terminal — im Browser öffnen, der +**Einrichtungs-Assistent** übernimmt den Rest. + +Zuerst nur nachsehen, ob alles passt, ohne etwas zu ändern: + +```bash +./install.sh --nur-pruefen +``` + +
+Was install.sh für dich macht (aufklappen) + +Es nimmt genau die Schritte ab, an denen man vorher scheitern konnte: + +1. **Prüft die Voraussetzungen** — Linux, Docker, Compose. Fehlt etwas, steht + der Installationsbefehl dabei. +2. **Findet dein Laufwerk selbst.** MakeMKV braucht **zwei** Geräteknoten: + `/dev/srN` und den passenden `/dev/sgM`. Welche sg-Nummer dazugehört, ist + **je Rechner anders** — das Skript gleicht sie über die SCSI-Adresse ab + statt zu raten. (Genau daran ging vorher die Handarbeit schief.) +3. **Legt die Verzeichnisse an** (`/srv/rippy/media` für die Filme, + `/srv/rippy/makemkv` für MakeMKVs Daten). +4. **Richtet die Mount-Propagation ein** und macht sie neustart-fest — sonst + funktioniert das Einhängen von NAS-Freigaben aus dem UI nach jedem Reboot + nicht mehr. +5. **Schreibt die `.env`** mit den gefundenen Werten. Bestehende Werte werden + **nie** überschrieben. +6. **Baut und startet** alles. + +Das Skript ist **wiederholbar**: mehrmals ausführen ändert nichts kaputt. Es +ist auch der Update-Weg — siehe unten. + +
+ +### Aktualisieren + +```bash +git pull && sudo ./install.sh +``` + +--- + +## Wenn etwas nicht geht + +Die vier Fälle, die praktisch alles abdecken: + +| Symptom | Ursache & Lösung | +|---|---| +| **„Kein optisches Laufwerk gefunden"** | In einer **VM**? Das Laufwerk muss per **USB-Passthrough** durchgereicht werden, nicht als emuliertes CD-ROM (`media=cdrom`) — das kann keine SCSI-Kommandos, MakeMKV sieht es nie. Proxmox: `qm set -usb0 host=:,usb3=1`. Auf echter Hardware: `ls /dev/sr*` prüfen. | +| **Build bricht beim MakeMKV-Download ab** | Cloudflare drosselt manchmal. Tarballs von makemkv.com/download händisch nach `docker/worker/vendor/` legen, dann `sudo ./install.sh` erneut — der Build nimmt sie dann von dort. | +| **Kompression läuft ewig** | Deine CPU kann kein AVX2. Rippy zeigt das jetzt selbst an (Einstellungen → System, „Vektorbefehle"). Siehe **[Rippy schneller machen](#rippy-schneller-machen)**. | +| **4K-UHD: „The volume key is unknown"** | Erwartbar und **kein Fehler in Rippy**. Siehe **[4K-UHD](#4k-uhd)**. | + +Logs ansehen: `docker compose logs -f` · Status: `docker compose ps` + +--- + +## Rippy schneller machen + +**Läuft Rippy in einer virtuellen Maschine, ist das hier der wirksamste +Handgriff überhaupt** — und er kostet fünf Minuten. + +Virtualisierer geben der VM standardmäßig eine **generische CPU** (bei +Proxmox/KVM heißt sie `kvm64` bzw. `qemu64`). Die kann absichtlich nur alte +Befehlssätze, damit sich eine VM zwischen verschiedenen Wirten verschieben +lässt. Der Preis: **kein AVX2** — und genau davon lebt der Video-Encoder x265. + +Was das ausmacht, ist auf der Rippy-Maschine gemessen worden: ein 4K-Film in +H.265 brauchte **28 bis 55 Stunden**, bei voll ausgelasteten Kernen. Mit AVX2 +sind typisch **2- bis 4-mal schneller** drin. + +**So stellst du es um (Proxmox):** + +1. VM **herunterfahren.** Ein Neustart von innen genügt nicht — Proxmox + übernimmt Hardware-Änderungen nur bei einem echten Stopp. +2. Im Web-UI: VM auswählen → **Hardware** → **Processors** → Doppelklick → + **Type** auf **`host`** stellen → OK. + Oder auf der Proxmox-Konsole: + ```bash + qm set --cpu host + ``` +3. VM **starten.** + +**Nachprüfen — Rippy sagt es dir selbst:** Einstellungen → System, Zeile +„Vektorbefehle" beim Worker. Steht dort jetzt `avx2` oder `avx512f` statt +`sse4_2`, hat es geklappt und die amberfarbene Warnung verschwindet. +Auf der Kommandozeile: `grep -o avx2 /proc/cpuinfo | head -1`. + +
+Nachteile von host — der Vollständigkeit halber + +Die VM sieht dann die echte CPU. Dadurch lässt sie sich nicht mehr auf einen +Wirt mit anderem Prozessor **live** verschieben. In einem Heim-Cluster mit +einem einzigen Wirt ist das ohne Bedeutung. Wer mehrere Wirte hat und +Live-Migration nutzt, wählt statt `host` das neueste Modell, das **alle** +Wirte beherrschen (z. B. `x86-64-v3` — das enthält AVX2). + +
+ +**Kein AVX2 möglich?** Dann zwei Auswege, beide im UI: +- **4K nicht komprimieren** (Einstellungen → Verarbeitung → Preset für 4K-UHD → + „Nicht komprimieren"). Die verlustfreie Datei bleibt stehen: beste Qualität, + 20–100 GB je Film. Der Einrichtungs-Assistent wählt das bei schwacher CPU + von selbst. +- **Andere Maschine komprimieren lassen** — siehe + [Weitere Maschinen als Worker](#weitere-maschinen-als-worker). + +--- + +## Der Alltag + +### Rippen + +Disc einlegen. Rippy erkennt sie, zeigt Titel und Poster, du wählst das Ziel — +oder du stellst die **Vollautomatik** an (Einstellungen → Ripping) und es +läuft ohne Nachfrage los. + +- **Alle Tonspuren und Untertitel bleiben erhalten** (wichtig für Anime/O-Ton). +- **Nur Hauptfilm** auf Wunsch — der längste Titel, Extras bleiben weg. +- **Serien:** Serienname + Staffel angeben → Ablage `/Season NN`, und + die Episoden werden per Laufzeitabgleich (TMDB) zu „Serie S01E02.mkv" + benannt. Nur bei eindeutiger Zuordnung, sonst bleiben die Namen — mit Log. +- **Audio-CDs** laufen über abcde zu FLAC mit MusicBrainz-Tags. +- Schon gerippte Discs erkennt Rippy am Fingerabdruck und warnt. +- Vor dem Start wird der freie Platz gegen die Disc-Größe geprüft. + +### Kompression + +Ein **eigenes Preset je Disc-Typ** (Einstellungen → Verarbeitung) — Rippy +erkennt den Typ selbst. Das ist wichtig, weil ein 1080p-Preset eine 4K-UHD +stillschweigend herunterrechnet und eine DVD sinnlos hochskaliert. + +Jeder Typ kann auch auf **„Nicht komprimieren"** stehen: dann bleibt der +verlustfreie Rip liegen. Sinnvoll für 4K, wenn die Ablage groß genug ist. + +Die Rohdatei wird erst nach erfolgreicher Kompression gelöscht („Original +behalten" als Option). Fehlgeschlagene Kompressionen lassen sich ohne +Neu-Rip erneut anstoßen. + +### Ablage & Media-Server + +Einstellungen → Ripping: dein System wählen (Jellyfin, Emby, Kodi, Plex oder +keins). Fertige Rips heißen dann „Titel (Jahr)"; für Jellyfin/Emby/Kodi legt +Rippy zusätzlich `movie.nfo` + `poster.jpg` dazu. Bei **Jellyfin/Emby** mit +Server-URL + API-Key stößt Rippy nach jedem Rip sofort einen +Bibliotheks-Scan an — Disc rein, Film erscheint im Server. + +**NAS-Freigaben** hängst du unter Einstellungen → Speicherziele direkt aus dem +UI ein (NFS/SMB). Sie erscheinen sofort in der Ziel-Auswahl und werden beim +Start automatisch wieder verbunden. +⚠️ Zugangsdaten liegen unverschlüsselt in der lokalen Datenbank — 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. Rippy erkennt den Dienst an der URL selbst: + +| Dienst | URL-Beispiel | +|---|---| +| Discord | `https://discord.com/api/webhooks/…` | +| Slack | `https://hooks.slack.com/services/…` | +| ntfy (Handy-Push) | `https://ntfy.sh/mein-geheimes-thema` | +| Eigenes (Home Assistant, n8n, …) | beliebige HTTPS-URL | + +--- + +## 4K-UHD + +4K braucht **zwei** Dinge, die normale BD/DVD nicht brauchen: ein +**LibreDrive-fähiges Laufwerk** (MakeMKV-Forum: „Ultimate UHD Drives Flashing +Guide") **und** den **Schlüssel dieser Pressung**. + +**Der Schlüssel ist die eigentliche Hürde — 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". + +> **`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 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** (Einstellungen → System): + +1. MakeMKV auf einem **Windows-PC** installieren (gleicher Beta-Key). +2. Laufwerk anstecken, Disc **einmal öffnen** — dabei lädt MakeMKV die + Schlüssel nach. +3. In MakeMKV unter *Preferences → General* das „MakeMKV data directory" + nachschlagen und die Datei **`_private_data.tar`** daraus bei Rippy + hochladen. + +Rippy zeigt an, **wie viele Disc-Schlüssel** dieser Worker kennt. Steht dort 0, +scheitert jede unbekannte UHD. Für neue Discs den Schritt 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. + +**Kennt MakeMKV die Pressung selbst nicht**, bleibt die **`KEYDB.cfg`** als +Notnagel (gleicher Tab). Und: **AACS-Dumps herunterladen** — den Dump legt +MakeMKV bei jeder unbekannten Disc selbst ab, und genau den braucht man, wenn +man im MakeMKV-Forum um den Schlüssel für eine neue Pressung bittet. + +> ⚠️ **Rippy liefert keine Disc-Schlüssel mit, lädt keine herunter und +> verteilt keine.** Rippy hält nur den Platz für eine Datei bereit, die du +> selbst mitbringst, und zeigt ehrlich an, was dort liegt. Der +> MakeMKV-**Beta-Key** ist die Lizenz für die *Software* — zwei völlig +> verschiedene Dinge. + +⚠️ UHD-Rohdaten sind bis 100 GB groß. Ist die Platte zu klein, lege das +**Arbeitsverzeichnis** (Einstellungen → Verarbeitung) auf eine eingehängte +Freigabe. Rippy bricht sonst **vor** dem Rip mit Klartext ab statt nach 40 GB +mit voller Platte. + +--- + +## Weitere Maschinen als Worker + +Die Kompression läuft als eigener Task auf der Queue `transcode` — **jede** +Maschine im Netz kann sie übernehmen. Einstellungen → Worker zeigt für beide +Varianten einen Copy-Paste-Befehl: + +- **Windows (nativ, ohne Docker)** — braucht nur Python. Der Installer kommt + als fertige `.exe` von Rippy selbst; Worker-Code und HandBrake holt er zur + Laufzeit. +- **Linux (Docker)** — `deploy/remote-transcode-worker.yml`. + +Rippy zeigt für jeden Worker an, **was er wirklich kann**: Encoder, Kernzahl, +Vektorbefehle. Für einen **GPU-Worker** wichtig: das Bild braucht ein +HandBrake mit `nvenc_*` bzw. `qsv_*` — die Anzeige nennt HandBrakes +ungefilterte Auskunft, damit du das nachprüfen kannst. Das mitgelieferte +Linux-Worker-Bild hat **keinen** Hardware-Encoder. + +Ohne Zusatz-Worker macht der eingebaute CPU-Worker alles selbst — Rippy bleibt +All-in-one. + +--- + +## Für Fortgeschrittene + +
+Umgebungsvariablen (.env) + +`install.sh` füllt die hostabhängigen Werte selbst. Alles hier ist optional — +UI-Einstellungen überstimmen die Env-Variablen. + +| Variable | Zweck | +|---|---| +| `TMDB_API_KEY` | Metadaten (deutsche Texte). Bequemer im Assistenten — beide Key-Arten gehen (v3-Schlüssel und v4-Token) | +| `OMDB_API_KEY` | zweite Metadaten-Quelle (Fallback) | +| `THETVDB_API_KEY` | Serien-Fallback | +| `WORKER_NAME` | Anzeigename des eingebauten Workers (Standard `rippy-hauptworker`) | +| `MAKEMKV_APP_KEY` | MakeMKV-Beta-Key. Bequemer im UI unter Einstellungen → System — gilt ab dem nächsten Rip, ohne Rebuild | +| `MAKEMKV_VERSION` | MakeMKV-Version für den Image-Build | +| `MAKEMKV_URL_BASE` | alternative Download-Quelle für den Build | +| `MAKEMKV_DATA_HOST` | Host-Verzeichnis für MakeMKVs Daten (Standard `/srv/rippy/makemkv`) — Schlüsselspeicher, `KEYDB.cfg`, AACS-Dumps. Persistent, überlebt jeden Rebuild | +| `OPTICAL_SR` / `OPTICAL_SG` | Geräteknoten des Laufwerks. **Findet `install.sh` selbst** | +| `POSTGRES_PASSWORD` | DB-Passwort (Standard `rippy`) | + +
+ +
+Installation ohne install.sh (von Hand) + +Falls du jeden Schritt selbst machen willst: + +```bash +cp .env.example .env +mkdir -p /srv/rippy/media /srv/rippy/makemkv + +# Laufwerksknoten ermitteln — die sg-Nummer ist je Host anders! +lsscsi -g # zeigt Modell + zugehoerigen /dev/sgN +# in die .env: OPTICAL_SR=/dev/sr0 und OPTICAL_SG=/dev/sgN + +# Nur falls 'docker compose up' meldet: +# "path ... is mounted on / but it is not a shared mount" +mount --bind /srv/rippy/media /srv/rippy/media +mount --make-rshared /srv/rippy/media # neustart-fest als systemd-.mount-Unit + docker compose up -d --build ``` -Dann `http://` öffnen — der **Einrichtungs-Assistent** startet beim -ersten Mal automatisch (API-Keys, Verarbeitung, erkannte Hardware). +Braucht klassisches Linux-Docker mit `SYS_ADMIN` — nicht Docker Desktop, +rootless oder Podman. Die Mount-Propagation ist nur für das Einhängen von +NAS-Freigaben **aus dem UI** nötig; Freigaben auf dem Host einhängen geht immer. -### 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`). +
+Wie es intern funktioniert -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.) +1. **Disc-Wache** — ioctl-Polling, kein udev. Im Container läuft kein udevd, + die udev-Datenbank ist leer; `udevadm info` liefert dort prinzipbedingt + nichts. +2. **Rip** — MakeMKV, verlustfrei. Der einzige Weg durch AACS: HandBrake kann + verschlüsselte Discs nicht lesen, deshalb sind es zwingend zwei Stufen. +3. **Kompression** — HandBrake als eigener Celery-Task auf eigener Queue, + deshalb an andere Maschinen routbar. +4. **Metadaten** — Volume-Label → TMDB → OMDb → MyAnimeList, mit + Ähnlichkeits-Bewertung und Korrektur-Popup an der Disc-Karte. -**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 +
+Härtung für exponierte Netze -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, - **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. +Rippy ist bewusst **Heimnetz-only**: keine Authentifizierung, und Redis + +PostgreSQL veröffentlichen Ports für Remote-Worker. Im vertrauten LAN ein +akzeptierter Kompromiss — **exponiere Rippy niemals ungeschützt an ein +öffentliches Netz.** -## 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://` ö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 +- **Zugriff kapseln:** UI und API (`:8000`) hinter einen Reverse-Proxy mit Auth + oder nur über VPN erreichbar machen. +- **DB/Broker abschotten:** starkes `POSTGRES_PASSWORD`; die Ports + `5432`/`6379` nur an ein internes/VPN-Interface binden statt an `0.0.0.0`; + Redis mit `--requirepass` starten und das Passwort in `REDIS_URL` ergänzen. +- **CORS:** `main.py` erlaubt `*` (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. +- **NAS-Zugangsdaten** liegen im Klartext in der DB — ein weiterer Grund, den + DB-Port nie offen ins unsichere Netz zu hängen. + +
+ +
+Updates der Werkzeuge + +„Auf Updates prüfen" (Einstellungen → System) vergleicht mit makemkv.com und +den offiziellen HandBrake-Releases, 12 h gecacht. + +**MakeMKV** aktualisieren: `MAKEMKV_VERSION=x.y.z` in die `.env`, dann +`sudo ./install.sh`. Der Beta-Key wechselt etwa monatlich (Forum-Thread +t=1053) und wird im UI gepflegt — ohne Rebuild. + +**HandBrake** kommt im Docker-Worker bewusst aus Debian (stabil, hinkt der +offiziellen Version hinterher); der native Windows-Worker nutzt die aktuelle. + +⚠️ Ein MakeMKV-Update hilft **nicht** gegen „The volume key is unknown" — +MakeMKV liefert überhaupt keine Disc-Schlüssel mit, es holt sie zur Laufzeit, +und die Linux-Version holt sie nie. Siehe [4K-UHD](#4k-uhd). + +
+ +--- ## 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. +einen Branch, `main` — 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) +Fahrplan: [ROADMAP.md](ROADMAP.md) · Stand: [SAVEPOINT.md](SAVEPOINT.md) diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..a713f6f --- /dev/null +++ b/install.sh @@ -0,0 +1,303 @@ +#!/usr/bin/env bash +# +# Rippy einrichten — ein Befehl, keine Handarbeit. +# +# Das Skript nimmt genau die Schritte ab, an denen man vorher scheitern konnte: +# * Laufwerk finden (BEIDE Geraeteknoten — der sg-Knoten ist je Host anders, +# und ein fest eingetragener Standard ist damit auf fremden Hosts falsch) +# * Ablage- und MakeMKV-Verzeichnis anlegen +# * shared-Mount-Propagation herstellen, falls Docker sie verlangt +# * .env anlegen bzw. fehlende Werte ergaenzen, ohne Bestehendes zu ueberschreiben +# * bauen und starten +# +# Es ist absichtlich WIEDERHOLBAR: mehrfach ausfuehren aendert nichts kaputt. +# Es aendert NIE einen Wert, der schon in der .env steht. +# +# Aufruf: sudo ./install.sh +# sudo ./install.sh --nur-pruefen (nichts anfassen, nur berichten) + +set -u + +NUR_PRUEFEN=0 +[ "${1:-}" = "--nur-pruefen" ] && NUR_PRUEFEN=1 + +MEDIA_DIR="${RIPPY_MEDIA_DIR:-/srv/rippy/media}" +MAKEMKV_DIR="${RIPPY_MAKEMKV_DIR:-/srv/rippy/makemkv}" +FEHLER=0 + +rot() { printf '\033[31m%s\033[0m\n' "$*"; } +gruen() { printf '\033[32m%s\033[0m\n' "$*"; } +gelb() { printf '\033[33m%s\033[0m\n' "$*"; } +titel() { printf '\n\033[1m%s\033[0m\n' "$*"; } + +echo "======================================================================" +echo " Rippy — Einrichtung" +echo "======================================================================" +[ "$NUR_PRUEFEN" = 1 ] && gelb "Nur-Pruefen-Modus: es wird nichts geaendert." + +# --------------------------------------------------------------------------- +# 1. Voraussetzungen +# --------------------------------------------------------------------------- +titel "1/6 Voraussetzungen" + +if [ "$(uname -s)" != "Linux" ]; then + rot " X Das hier ist kein Linux. Rippy braucht einen Linux-Host mit Docker." + rot " (Docker Desktop unter Windows/macOS kann keine optischen Laufwerke" + rot " durchreichen — deshalb geht es dort grundsaetzlich nicht.)" + exit 1 +fi +gruen " OK Linux erkannt ($(uname -r))" + +if ! command -v docker >/dev/null 2>&1; then + rot " X Docker ist nicht installiert." + rot " Installation: curl -fsSL https://get.docker.com | sudo sh" + FEHLER=1 +else + gruen " OK Docker gefunden ($(docker --version 2>/dev/null | head -1))" +fi + +if docker compose version >/dev/null 2>&1; then + COMPOSE="docker compose" + gruen " OK Compose-Plugin gefunden" +elif command -v docker-compose >/dev/null 2>&1; then + COMPOSE="docker-compose" + gelb " ! Nur das alte docker-compose gefunden — funktioniert, ist aber veraltet." +else + rot " X Docker Compose fehlt." + rot " Installation (Debian/Ubuntu): sudo apt install docker-compose-plugin" + FEHLER=1 +fi + +if [ "$(id -u)" = "0" ]; then + gruen " OK Als root gestartet" +elif [ "$NUR_PRUEFEN" = 1 ]; then + # Der Pruef-Modus aendert nichts und darf deshalb NICHT an root scheitern — + # sonst kann man vor der Installation nicht nachsehen, ob alles passt. + gelb " ! Ohne root — fuer die Pruefung in Ordnung. Die echte Installation" + gelb " braucht sudo (Verzeichnisse unter /srv, Mount-Propagation)." +else + rot " X Bitte mit sudo starten: sudo ./install.sh" + rot " (Verzeichnisse unter /srv und die Mount-Propagation brauchen root.)" + rot " Nur nachsehen, ohne etwas zu aendern: ./install.sh --nur-pruefen" + FEHLER=1 +fi + +[ "$FEHLER" = 1 ] && { rot ""; rot "Abgebrochen — bitte das Fehlende nachholen."; exit 1; } + +# --------------------------------------------------------------------------- +# 2. Laufwerk suchen +# --------------------------------------------------------------------------- +titel "2/6 Optisches Laufwerk" + +# MakeMKV spricht Laufwerke ueber die SCSI-Generic-Schicht an und braucht +# deshalb ZWEI Knoten: /dev/srN und den passenden /dev/sgM. Welche sg-Nummer +# dazugehoert, ist je Host anders — deshalb wird sie hier ueber die +# SCSI-Adresse ermittelt statt geraten. Beide Knoten zeigen in /sys auf +# dasselbe Geraeteverzeichnis (z. B. 3:0:0:0), das ist der Abgleich. +SR="" +SG="" +LAUFWERK="" +for srpfad in /sys/block/sr*; do + [ -e "$srpfad" ] || continue + srname=$(basename "$srpfad") + adresse=$(basename "$(readlink -f "$srpfad/device" 2>/dev/null)" 2>/dev/null) + [ -n "$adresse" ] || continue + for sgpfad in /sys/class/scsi_generic/sg*; do + [ -e "$sgpfad" ] || continue + if [ "$(basename "$(readlink -f "$sgpfad/device" 2>/dev/null)" 2>/dev/null)" = "$adresse" ]; then + SR="/dev/$srname" + SG="/dev/$(basename "$sgpfad")" + LAUFWERK="$(cat "$srpfad/device/vendor" 2>/dev/null) $(cat "$srpfad/device/model" 2>/dev/null)" + break 2 + fi + done +done + +if [ -n "$SR" ]; then + gruen " OK Laufwerk gefunden: $(echo "$LAUFWERK" | tr -s ' ')" + gruen " $SR + $SG (SCSI-Adresse abgeglichen, nicht geraten)" +else + gelb " ! Kein optisches Laufwerk gefunden." + gelb " Rippy laesst sich trotzdem installieren und kann dann als reine" + gelb " KOMPRIMIER-Maschine fuer andere Rippy-Instanzen dienen." + gelb " Zum Rippen fehlt das Laufwerk. Haeufigste Ursachen:" + gelb " - In einer VM: Laufwerk per USB-Passthrough durchreichen" + gelb " (Proxmox: qm set -usb0 host=:,usb3=1)" + gelb " NICHT als emuliertes CD-ROM (media=cdrom) — das kann keine" + gelb " SCSI-Kommandos und MakeMKV sieht es nie." + gelb " - Auf echter Hardware: 'ls /dev/sr*' pruefen, Kabel/Strom." +fi + +# --------------------------------------------------------------------------- +# 3. Verzeichnisse +# --------------------------------------------------------------------------- +titel "3/6 Verzeichnisse" +for d in "$MEDIA_DIR" "$MAKEMKV_DIR"; do + if [ -d "$d" ]; then + gruen " OK $d liegt schon da" + elif [ "$NUR_PRUEFEN" = 1 ]; then + gelb " ! $d fehlt (wuerde angelegt)" + else + mkdir -p "$d" && gruen " OK $d angelegt" + fi +done +echo " Ablage: $MEDIA_DIR (hier landen die fertigen Filme)" +echo " MakeMKV-Daten: $MAKEMKV_DIR (Schluesselspeicher, rebuild-fest)" + +# --------------------------------------------------------------------------- +# 4. Mount-Propagation +# --------------------------------------------------------------------------- +titel "4/6 Mount-Propagation (fuer NAS-Freigaben aus dem UI)" + +# Rippy haengt NAS-Freigaben aus dem UI ein. Damit die auch in den anderen +# Containern sichtbar werden, muss der Ablage-Pfad ein 'shared' Mount sein. +# Auf den meisten systemd-Hosts ist / schon rshared und es ist nichts zu tun. +propagation_ok() { + findmnt -no PROPAGATION --target "$MEDIA_DIR" 2>/dev/null | grep -q shared +} + +if propagation_ok; then + gruen " OK $MEDIA_DIR ist bereits 'shared' — nichts zu tun" +elif [ "$NUR_PRUEFEN" = 1 ]; then + gelb " ! Propagation fehlt (wuerde eingerichtet)" +else + mount --bind "$MEDIA_DIR" "$MEDIA_DIR" 2>/dev/null + mount --make-rshared "$MEDIA_DIR" 2>/dev/null + if propagation_ok; then + gruen " OK Propagation eingerichtet" + # Neustart-fest machen, sonst ist es nach dem naechsten Reboot wieder weg + # und das Einhaengen aus dem UI scheitert stillschweigend. + UNIT="/etc/systemd/system/$(systemd-escape -p --suffix=mount "$MEDIA_DIR" 2>/dev/null)" + if [ -n "${UNIT:-}" ] && [ ! -e "$UNIT" ] && command -v systemctl >/dev/null 2>&1; then + cat > "$UNIT" </dev/null + systemctl enable "$(basename "$UNIT")" >/dev/null 2>&1 \ + && gruen " OK Neustart-fest gemacht ($(basename "$UNIT"))" \ + || gelb " ! Konnte nicht neustart-fest gemacht werden — nach einem Reboot" + gelb " ggf. dieses Skript erneut ausfuehren." + fi + else + gelb " ! Propagation liess sich nicht einrichten." + gelb " Rippy laeuft trotzdem — nur das Einhaengen von NAS-Freigaben AUS DEM UI" + gelb " funktioniert dann nicht. Freigaben stattdessen auf dem Host einhaengen," + gelb " z. B. unter $MEDIA_DIR/nas. Betrifft nur klassisches Docker mit" + gelb " SYS_ADMIN — nicht rootless/Podman." + fi +fi + +# --------------------------------------------------------------------------- +# 5. .env +# --------------------------------------------------------------------------- +titel "5/6 Konfiguration (.env)" + +cd "$(dirname "$0")" || exit 1 + +if [ ! -f .env ]; then + if [ "$NUR_PRUEFEN" = 1 ]; then + gelb " ! .env fehlt (wuerde aus .env.example erzeugt)" + else + cp .env.example .env && gruen " OK .env aus .env.example erzeugt" + fi +else + gruen " OK .env liegt schon da — bestehende Werte bleiben unangetastet" +fi + +# Setzt einen Wert NUR, wenn er noch nicht (unkommentiert) gesetzt ist. +setze_wenn_leer() { + schluessel="$1"; wert="$2" + [ "$NUR_PRUEFEN" = 1 ] && { echo " wuerde setzen: $schluessel=$wert"; return; } + [ -f .env ] || return + if grep -qE "^${schluessel}=.+" .env; then + echo " $schluessel steht schon in der .env — unveraendert gelassen" + else + sed -i "/^#*${schluessel}=/d" .env + printf '%s=%s\n' "$schluessel" "$wert" >> .env + gruen " OK $schluessel=$wert eingetragen" + fi +} + +if [ -n "$SR" ]; then + setze_wenn_leer OPTICAL_SR "$SR" + setze_wenn_leer OPTICAL_SG "$SG" +fi +setze_wenn_leer MAKEMKV_DATA_HOST "$MAKEMKV_DIR" + +echo " API-Keys (TMDB/OMDb) brauchst du hier NICHT einzutragen —" +echo " der Einrichtungs-Assistent im Browser fragt sie ab und prueft sie." + +# Gegenprobe: Zeigen die WIRKSAMEN Werte auf Geraete, die es hier gibt? Faengt +# den Fall "'.env' von einem anderen Rechner kopiert" und Tippfehler ab — sonst +# startet Docker mit einem Pfad, den es nicht gibt, und die Meldung ist kryptisch. +if [ -f .env ]; then + for paar in "OPTICAL_SR:/dev/sr0" "OPTICAL_SG:/dev/sg1"; do + schluessel="${paar%%:*}"; standard="${paar##*:}" + wirksam=$(grep -E "^${schluessel}=" .env 2>/dev/null | tail -1 | cut -d= -f2-) + [ -n "${wirksam:-}" ] || wirksam="$standard" + if [ ! -e "$wirksam" ]; then + gelb " ! $schluessel zeigt auf $wirksam — dieses Geraet gibt es hier NICHT." + if [ -n "$SR" ]; then + gelb " Gefunden wurde stattdessen: $SR + $SG" + gelb " Trage das in der .env ein (oder loesche die Zeile $schluessel=)." + else + gelb " Es wurde auch kein anderes Laufwerk gefunden — siehe Schritt 2." + fi + fi + done +fi + +# --------------------------------------------------------------------------- +# 6. Bauen und starten +# --------------------------------------------------------------------------- +titel "6/6 Bauen und starten" + +if [ "$NUR_PRUEFEN" = 1 ]; then + gelb " ! Uebersprungen (Nur-Pruefen-Modus)." + echo "" + gruen "Pruefung fertig. Ohne --nur-pruefen wuerde jetzt gebaut und gestartet." + exit 0 +fi + +echo " Der erste Bau dauert je nach Internet 3-10 Minuten. Nur beim ersten Mal." +echo "" +if ! $COMPOSE up -d --build; then + rot "" + rot "Der Start ist gescheitert. Die haeufigsten Ursachen:" + rot " - Kein Platz auf der Platte: df -h /" + rot " - Port 80 schon belegt: ss -tlnp | grep ':80 '" + rot " - Download von makemkv.com gedrosselt (Cloudflare): Tarballs von" + rot " makemkv.com/download nach docker/worker/vendor/ legen, dann erneut." + rot "Die volle Meldung steht oben. Logs: $COMPOSE logs --tail=50" + exit 1 +fi + +IP=$(ip -4 route get 1.1.1.1 2>/dev/null | grep -oE 'src [0-9.]+' | awk '{print $2}') +[ -n "${IP:-}" ] || IP="" + +echo "" +echo "======================================================================" +gruen " Fertig. Rippy laeuft." +echo "======================================================================" +echo "" +echo " Jetzt im Browser oeffnen: http://$IP" +echo "" +echo " Dort startet der Einrichtungs-Assistent. Er zeigt dir, ob Laufwerk," +echo " Worker und Platz in Ordnung sind, und stellt die Kompression passend" +echo " zu deiner CPU ein. Mehr ist nicht zu tun." +echo "" +echo " Status ansehen: $COMPOSE ps" +echo " Logs ansehen: $COMPOSE logs -f" +echo " Aktualisieren: git pull && sudo ./install.sh" +echo ""