# ROADMAP — Rippy > Meilenstein-Plan für den Bau von Rippy. Jede Etappe ist lauffähig für sich. --- ## Etappe 1: Fundament — Container-Infrastruktur + udev-Erkennung **Ziel:** Das System bootet, erkennt eine eingelegte Disc und erstellt einen Job. **Was gebaut wird:** - Docker Compose mit `api`, `worker`, `ui`, `postgres`, `redis` - Basis-Dockerfiles für jeden Service (Python/FastAPI, Python/Celery, Node/React, PostgreSQL, Redis) - udev-Regel + separater Daemon (Python), der Disc-Einwurf erkennt und Jobs an den Worker sendet - Device-Resolver: ermittelt UUID/Serial des Laufwerks, erzeugt Symlink `/dev/disc/` - Job-Erstellung in Celery-Queue mit Disc-Typ und Device-Pfad **Fertig wenn:** - ✅ `docker compose up` startet alle 5 Container - ✅ udev-Regel erkennt Disc-Einwurf - ✅ udev-Daemon erstellt Celery-Job - ✅ Celery-Worker nimmt den Job entgegen und gibt "Disc erkannt: DVD, Device: /dev/disc/xxx" aus **Status:** Abgeschlossen --- ## Etappe 2: Ripping-Pipeline — Verlustfreies Extrahieren **Ziel:** Disc wird rippt und als rohe Dateien abgelegt. **Was gebaut wird:** - CD-Ripping via `abcde` → FLAC, AcoustID-Fingerprinting (chromaprint) + MusicBrainz-Lookup - DVD/Blu-ray-Ripping via `makejungles` (makeMKV-Äquivalent, OpenSource) → MKV, mit `--all --progress` - Ripping im Worker-Container, Read-Only Device-Passthrough - Fortschritts-Reporting über Celery-Signale an SSE-Stream **Fertig wenn:** - CD → FLAC-Dateien + MusicBrainz-Metadaten - DVD → MKV mit allen Titeln - Blu-ray → MKV mit allen Titeln - Fortschritt wird in Echtzeit im UI angezeigt --- ## Etappe 3: Metadaten-Lookup + Pre-Scan **Ziel:** Vor dem Ripping wird die Disc identifiziert und der Commander bestätigt. **Was gebaut wird:** - Pre-Scan-Modul: liest TOC (kein Ripping), extrahiert Titel/Laufzeit/Scene-Labels - TMDB-Integration für Film-/Serien-Matching (Confidence-Score) - MusicBrainz-Integration für CD-Matching - TheTVDB-Fallback für Serien - SQLite-Cache für API-Antworten (LRU, 10k Einträge, TTL) - Pre-Scan-Latenz: 5–15s, dokumentiert **Fertig wenn:** - Nach Disc-Einwurf: Pre-Scan läuft automatisch - UI zeigt: Titel, Jahr, Cover, Confidence-Score, Trackliste - Commander kann bestätigen oder manuell korrigieren - Bestätigte Metadaten werden im Cache persistiert **Status:** Abgeschlossen --- ## Etappe 4: Jellyfin-Formatierung + NFO-Generierung **Ziel:** Gerippte Dateien liegen in Jellyfin-konformer Ordnerstruktur mit Metadaten. **Was gebaut wird:** - Ordnerstruktur: - Filme: ` ()/-.mkv` - Serien: `<Serienname>/<Staffel N>/<Serienname> - S{N}E{N} - <Episode>.mkv` - Musik: `<Künstler>/<Album> (<Jahr>)/<Track-Nr>. <Titel>.flac` - NFO-Generator im Kodi/NFO-Schema: - `movie.nfo`, `series.nfo`, `episode.nfo`, `album.nfo` - Alle Metadaten aus Pre-Scan + NFO-Attribution (Source: TMDB) - Image-Downloader: poster.jpg (500x750), fanart.jpg, backdrop.jpg (1920x1080+) von TMDB - Jellyfin-kompatible Dateibenennung - Multi-Disc-Handling: `Disc 1.mkv`, `Disc 2.mkv` etc. **Fertig wenn:** - Gerippte Dateien + NFO + Poster in Jellyfin-Ordnerstruktur - Jellyfin scannt und erkennt alles korrekt - Multi-Disc-Sets werden als eine Entität angezeigt **Status:** Abgeschlossen --- ## Etappe 5: API + Auth + WebUI **Ziel:** Vollständiger Web-Dienst mit Echtzeit-Status und Job-Steuerung. **Was gebaut wird:** - FastAPI mit JWT-Auth (Access 15min, Refresh 7 Tage), Rate-Limiting (100/min/API-Key) - REST-Endpoints: Jobs erstellen/listen/abbrechen, Geräte verwalten, Einstellungen - SSE-Stream für Echtzeit-Jobstatus - React-UI (Vite-Build → statisch via Nginx): - Dashboard mit Echtzeit-Kacheln (Job-Status, Queue, Disc-Einwurf) - Job-Verlauf mit Fortschrittsbalken - Metadaten-Preview mit Bestätigungs-Dialog - Job-Detail mit Live-Log - Ergebnis-View mit Ordnerstruktur-Preview - Einstellungen (API-Keys, Transcoding, Backup-Pfade, Jellyfin-Config) - Geräte-Verwaltung **Fertig wenn:** - Commander kann UI im Browser öffnen und alles bedienen - Jobs starten, stoppen, Verlauf einsehen - Echtzeit-Updates via SSE funktionieren - Alle Einstellungen werden gespeichert **Status:** Abgeschlossen --- ## Etappe 6: Sicherheit + Compliance + Hardening **Ziel:** Produktionsreif — sicher, compliant, robust. **Was gebaut wird:** - SELinux/AppArmor Profile pro Container - Read-only Bind-Mounts für System-Bibliotheken - mTLS zwischen API ↔ Worker - Netzwerk-Policy: UI→API (HTTPS), API↔Worker (mTLS), Worker↔Internet (nur API) - PostgreSQL mit verschlüsselten Connections - Source-Release-Endpoint (GPL-v3-Compliance) - Lizenz-Dokumentation (MakeMKV, OpenSource-Komponenten) - Backup-Hooks (PBS-Snapshot-Integration) - Error-Handling: exponential backoff Retry (max 5), Circuit-Breaker für APIs **Fertig wenn:** - Alle Container haben Security-Profile - Netzwerkverkehr zwischen Containern ist verschlüsselt - GPL-v3-Compliance-Checkliste abgehakt - Backup-Hooks funktionieren **Status:** Abgeschlossen --- ## Etappe 7: API UI Modernisiert **Ziel:** Modernes React-UI mit Dark Mode Support. **Was gebaut wird:** - React UI mit TailwindCSS - Sidebar Navigation - Einstellungen mit Tab-Struktur - Dark Mode mit Theme-Toggle und localStorage persistence - Status-Badges und StatCards mit Dark Mode Support **Fertig wenn:** - UI mit Dark Mode läuft - Navigation und Einstellungen funktionieren - Commit `43dfce5` — Dark Mode Implementation **Status:** Abgeschlossen --- ## Etappe 8: Separation of Concerns (Dark Mode) **Ziel:** Code-Qualität durch saubere Trennung. **Was gebaut wird:** - Theme-Context aus App.tsx auslagern - Dark Mode Utility für CSS-Klassen - Theme props in Komponenten verstecken - Tailwind-Config zentralisieren **Fertig wenn:** - Theme-Logik in eigenem Context - Wiederverwendbare Dark Mode Helper - Saubere Komponenten-Struktur **Status:** Abgeschlossen (Teil von Etappe 9) --- ## Etappe 9: SoC Refactoring & Config Validation **Ziel:** Code-Qualität durch saubere Trennung + Konfigurations-Validierung. **Was gebaut wird:** - Theme-Context aus App.tsx in eigenes Context auslagern - Config Validation mit TMDB-API-Key Pflicht - Cache Key Centralization (cache/keys.py) - Worker Refactoring für bessere Trennung - Docker Compose mit Healthchecks **Fertig wenn:** - Theme-Logik in eigenem Context (ThemeContext.tsx) - Wiederverwendbare Dark Mode Helper (useDarkMode.ts) - TMDB-API-Key ist Pflicht (Fehler bei Fallback-UI) - Cache-Keys zentral definiert - Docker Healthchecks für API **Status:** In Arbeit ## Etappe 9: Proxmox-Integration **Ziel:** Ein-Click-Deploy auf Proxmox LXC. --- ## Offene Punkte (aus KONZEPT.md) | Punkt | Etappe | Behandlung | |-------|--------|------------| | TMDB-Matching-Fehler bei Nischentiteln | Etappe 3 | Pre-Scan Confidence-Score + manueller Korrektur-Mechanismus | | NFO-Format-Abhängigkeit von Jellyfin-Version | Etappe 4 | Kodi/NFO-Schema (stabil, gut dokumentiert) | | Pre-Scan-Latenz (5–15s) | Etappe 3 | Akzeptabel, Parallelisierung möglich | | TMDB-Bildrechte | Etappe 4 | Gelöst: TMDB API-ToS erlaubt private Nutzung | | Hybrid-Discs | Etappe 1 | MVP erkennt nur Standard; als "Kann" notiert | | Redis Single-Instance | Etappe 1 | MVP reicht; Cluster als "Später" | ## Etappe 10: MakeMKV-Umstellung — das Muss-Feature „lossless" einlösen **Ziel:** DVD/Blu-ray-Ripping auf `makemkvcon` umstellen (verlustfrei), wie im KONZEPT als Muss definiert. HandBrake fliegt aus dem Ripp-Pfad (bleibt ggf. als optionaler Transcode-Schritt NACH dem verlustfreien Rip). - [x] Worker-Dockerfile: makemkv-oss/makemkv-bin 1.18.4 multi-stage gebaut, Beta-Key via MAKEMKV_APP_KEY-Env (entrypoint.sh) — 23.07. - [x] ripping.py: auf `makemkvcon -r --progress=-same mkv dev:… all` umgestellt, PRGV-Fortschritts-Parsing laut makemkv.com/developers/usage.txt, Tests dabei — 23.07. - [ ] E2E mit echter Disc verifizieren (Commander, Laufwerk nötig) **Fertig wenn:** eine echte DVD landet verlustfrei als MKV im Output, Ampel grün. **Entstanden aus:** Review 22.07. — HandBrake-lossy war eine stille Abweichung vom Konzept; Entscheid 22.07. abends: Konzept gilt, Umbau als eigene Etappe. --- ## Etappe 11 (23.07.2026): Kernumbau — der Zweck funktioniert erstmals wirklich **Befund des Komplett-Audits (Claude):** Der Kern „Disc rein → gerippt raus" hatte NIE einen Code-Pfad: kein POST /jobs, kein udev-Daemon (das referenzierte udev_daemon.py existierte nirgends), kein Ripping-Tool im Worker-Image, Disc-Erkennung strukturell tot (`file -L` auf Block-Device), Geräte als Bind-Mounts statt devices: (EPERM), UI rief hartkodiert localhost:8000 auf. **Gebaut:** - [x] POST /jobs (API → Celery → Worker) + Job-Persistenz in Postgres - [x] Disc-Watcher in der API (ioctl-Poll statt udev — Container-tauglich) - [x] Disc-Erkennung neu über Kernel-ioctls (detection.py, in API+Worker) - [x] /logs-Endpoint + echte Logs-Seite (Mock-Daten raus) - [x] /settings-Endpoints (Settings-Seite sprach vorher ins Leere) - [x] UI: Vite-Build + nginx mit /api-Proxy statt Dev-Server; relative API-Pfade - [x] compose: devices: statt Bind-Mounts; Ausgabe aufs media-Volume - [x] Jellyfin-Post-Processing an den Worker anbinden (NFO/Poster nach dem Rip) — 24.07., medien.py: Ordner „Titel (Jahr)" + movie.nfo + poster.jpg, gesteuert übers mediaServer-Setting (Jellyfin/Emby/Kodi/Plex/keins) - [ ] Auth vor die schreibenden Endpoints (JWT existiert, schützt aber nichts) --- ## Etappe 12: Besser als ARM (aus ARM-Analyse 23.07.2026) **Quelle:** Vollanalyse von Automatic Ripping Machine v2.24 (Code, arm.yaml, Wiki, Issues). Was Rippy strukturell schon besser macht: Lossless-first statt Transcode-first (ARMs BD-Default ist ein 1080p30-Downscale!), Celery+Postgres statt Prozess-pro-udev-Event+SQLite (ARM-UI friert beim Rippen ein, #1046), ioctl-Watcher statt fragiler udev-Ketten (ARMs größte Support-Quelle), NFO + Jellyfin-Konvention nativ (ARM kann nur Emby-Refresh, keine NFOs). **Übernehmen (priorisiert):** - [ ] **Disc-Fingerprint-DB (selbstlernend)** — ARMs beste Idee, besser gemacht: Tabelle disc_fingerprints (DVD-CRC64/MusicBrainz-DiscID/BD-Label-Hash → bestätigte Metadaten). Jede UI-Bestätigung schreibt zurück; zweite Disc derselben Serie wird sofort erkannt. Lokal statt ARMs Crowd-Server (Single Point of Failure auf Free-Hosting). - [ ] **BD-Titel aus BDMV/META/DL/bdmt_eng.xml** als Identifikations-Stufe vor den APIs (echter Disc-Titel statt Label-Raterei). - [ ] **Progressive Suchdegradation** bei TMDB/OMDb: mit Jahr → ohne Jahr → tokenweises Titel-Stripping; jede Stufe senkt die Confidence. - [ ] **Duplikat-Schutz**: Fingerprint-Treffer → „schon gerippt am X — trotzdem?" - [ ] **Track-Auswahl (Manual Mode), besser als ARM**: Job-Status awaiting_selection nach makemkvcon-info; Track-Tabelle im UI mit Heuristik-Vorauswahl; Timeout → Weiter mit Default (ARM bricht hart ab, erlaubt nur EINE Auswahl). - [ ] **Min/Max-Titellänge + Extras**: Bonusmaterial nach extras/ (versteht Jellyfin nativ) statt alles flach. - [x] **Benachrichtigungen bei Job-Ende** — 24.07., eigenes notify-Modul (Discord/Slack/ntfy/generisches JSON, Dienst-Erkennung an der URL) statt Apprise-Dependency; Test-Knopf im UI. Telegram/Deep-Links offen. - [ ] **Multi-Drive-Verwaltung**: drives-Tabelle (Seriennummer, Custom-Name, UHD-fähig-Flag), parallele Rips, Job↔Drive-Zuordnung. - [ ] **Backup-Modus** (makemkvcon backup --decrypt) als Plan B für Problem-Discs. - [ ] **Jellyfin-Refresh** nach Ablage (POST /Library/Refresh). **ARM schlagen (Alleinstellung):** - [ ] **Serien-Episoden-Erkennung** — ARMs offene Wunde seit 2019 (#395): TVDB-Episodenlaufzeiten gegen Track-Laufzeiten matchen (±5 %, Reihenfolge-Constraint, Disc-Nr aus Label), Vorschlag „Show/Season 02/Show S02E05.mkv" im Preview bestätigen. - [ ] **Main-Feature per Laufzeitabgleich** mit TMDB-Runtime (±3 min) statt ARMs „größte Datei gewinnt" (#1297-Fehlklasse). --- ## Etappe 13 (24.07.2026): Universal-Komfort-Runde — Lücken aus dem Alltag schließen **Quelle:** Commander-Sammelauftrag 24.07. — alles, was beim echten Benutzen auffiel, in einem Rutsch. Alles gebaut, Tests dabei, Ampel-Blocker behoben. **Gebaut:** - [x] **Ampel entrostet**: bcrypt auf 4.0.1 gepinnt (passlib-1.7.4-Bruch) und cache_keys-Test an das Fingerprint-Format vom 23.07. angepasst — DIE beiden Rot-Ursachen, wegen derer `stable` 10 Commits zurückhing. - [x] **Media-Server-Integration**: mediaServer-Setting (Wizard + Einstellungen), Zielordner „Titel (Jahr)", movie.nfo/tvshow.nfo + poster.jpg für Jellyfin/Emby/Kodi (medien.py im Worker, mit Tests). - [x] **Benachrichtigungen echt gemacht**: notify.py (API+Worker), Meldung bei fertig/fehlgeschlagen/abgebrochen, Anleitung + Test-Knopf im UI — das Webhook-Feld war vorher ein Placebo, nichts hat je gesendet. - [x] **SMB-Freigaben-Scan repariert**: NT_STATUS-Fehler → Klartext (Gast- Abfrage verweigert ⇒ Benutzer/Passwort nötig), Credential-Felder im UI VOR den „Freigaben auflisten"-Knopf gezogen. - [x] **4K-UHD-Platzproblem**: Arbeitsverzeichnis konfigurierbar (workDir, z. B. NAS-Freigabe), Platz-Check per Disc-Größe (ioctl) VOR dem Rip. - [x] **MakeMKV-Key über UI** (Einstellungen → System): gilt ab dem nächsten Rip, ohne Rebuild; Worker melden Werkzeug-Versionen + Key-Quelle. - [x] **Job-Detail-Popup**: Klick auf Titel in „Neueste Jobs" → Poster, Jahr, Beschreibung, Ablagepfad, Fehler (Job speichert Metadaten jetzt mit). - [x] **UI-Feedback überall**: Toast-System (reinploppende Meldungen), drehende Refresh-Knöpfe, Logs-Filter um Warnung/Fehler-Pills ergänzt. - [x] **Datei-Browser zeigt Dateien**: Ordner wirkten „leer", weil nur Unterordner gelistet wurden — Dateien erscheinen jetzt grau mit Größe. - [x] Favicon (Disc im Logo-Verlauf) + Footer „Created with ❤️ by LucyAI, Claude and KrBrZ". - [x] README: Media-Server, Benachrichtigungen, UHD-Arbeitsverzeichnis, „Rippy woanders bereitstellen" (beliebiger Docker-Host). - [x] **Download-Knopf für fertige Rips** (Wunsch aus der Übernahme-Session): GET /jobs/{id}/files (+ Datei-Stream, Pfad-Validierung strikt unter /app/media inkl. realpath-Check), Download-Knopf in der Aktion-Spalte, Dateiliste mit Größen im Job-Detail-Popup — vorher kam man an fertige MKVs nur per scp. nginx hatte proxy_buffering off schon (SSE). **Offen aus dieser Runde:** nichts — Rest siehe Etappe 12 und Ideen unten. --- ## Etappe 14 (24.07.2026): Praxis-Feedback-Runde — erste echte Nutzung **Quelle:** Commander-Feedback nach dem ersten richtigen Arbeiten mit v3.2. - [x] SMB-Mount-Blocker: CAP_DAC_READ_SEARCH für mount.cifs (auf der VM reproduziert + bewiesen), Compose-Fix. - [x] TMDB-Key-Falle: v3-Schlüssel wurden still 401 (Client konnte nur v4-Bearer) — beide Arten unterstützt, „Verbindung prüfen" im UI. - [x] 4K UHD als eigener Disc-Typ (≥ 55 GiB) mit eigener Farbe + Klartext- Fehler bei Nicht-LibreDrive-Laufwerken. - [x] Vollautomatik-Setting (Disc rein → Rip startet ohne Popup). - [x] Job-Verwaltung: can_retry (Knopf nur bei vorhandenen Rohdaten), Einzel-Löschen, „Erledigte aufräumen", „Alle herunterladen". - [x] Worker: WORKER_NAME-Anzeigename + IP/ID, verwaiste Einträge löschbar. - [x] Ripping-Tab nach Medium (Video/Audio/Allgemein), Untertitel-Klartext, CD → Musik-Vorauswahl im Ziel-Dialog, Ordner-Verwaltung eingeklappt. --- ## Etappe 15 (24.07.2026): Restefeger — der Ideen-Katalog wird abgearbeitet **Commander-Auftrag:** „Arbeite alles ab, abgesehen von Auth — das ist irrelevant und kann komplett raus." - [x] **AUTH KOMPLETT ENTFERNT** (Commander-Entscheid): /token- und /api-keys-Endpoints, auth.py, test_auth.py, passlib/bcrypt/PyJWT, JWT_SECRET_KEY-Pflicht — alles raus (KONZEPT §10). Der Schnellstart braucht keine .env-Pflichtwerte mehr. Rate-Limit pro IP bleibt. - [x] **Serien-Staffel-Flow**: Im Rip-Dialog Serienname + Staffel → Ablage `<Serie>/Season NN`; tvshow.nfo + poster.jpg landen im Serien-Ordner (werden bei Staffel 2 nicht überschrieben). - [x] **Episoden-Erkennung per Laufzeitabgleich** (ARM-Wunde #395): Datei-Laufzeiten (HandBrake-Scan) gegen TMDB-Episoden-Laufzeiten, ordnungserhaltend; komplette Staffel auf einer Disc geht auch bei uniformen Laufzeiten. Umbenannt wird NUR bei eindeutiger Zuordnung („Serie S01E02.mkv"), sonst bleiben die Namen + ehrliches Log. - [x] **Jellyfin/Emby-Bibliotheks-Refresh** nach jedem fertigen Rip (POST /Library/Refresh, X-Emby-Token) — URL/Key + Test-Knopf in den Einstellungen. Die Null-Klick-Kette Disc→Bildschirm steht. - [x] **Duplikat-Warnung**: Disc-Fingerabdruck gegen die Job-Historie — Hinweis auf der Disc-Karte, Vollautomatik überspringt Duplikate. - [x] **„Nur Hauptfilm" ECHT**: das Setting war wirkungslos — jetzt Info-Lauf → längster Titel → nur der wird gerippt; pro Rip im Dialog übersteuerbar. (Volle Track-Tabelle bleibt Ausbaustufe.) - [x] **Deutsche Texte für OMDb-Treffer** via TMDB /find (IMDb-ID → de-DE). - [x] **Speicherplatz in der Dashboard-Leiste** (amber unter 60 GB frei). - [x] **CSV-Export** der Job-Historie (Semikolon+BOM, Excel-tauglich). - [x] **Metadaten-Seite entfernt** (+ Placebo-Endpoints /metadata/lookup und /metadata/confirm — lookup scannte ein Dummy-Device). - [x] **Doppel-Jahr-Fix** („X (2009) (2009)" in Log/Ordnernamen). - [x] **Remote-Worker-Blocker**: redis/postgres waren nie veröffentlicht — kein Remote-Worker konnte sich je verbinden. Ports 6379/5432 jetzt offen (Heimnetz-Kompromiss, dokumentiert) + API_URL für Worker. --- ## Etappe 16 (24.07.2026): Track-Tabelle + nativer Windows-Worker + Anleitung - [x] **Volle Titel-Auswahl vor dem Rip**: scan_tracks-Worker-Task, Polling-Endpoints, Tabelle (Dauer/Größe/Kapitel, Vorauswahl ≥ 5 min) im Rip-Dialog, Multi-Titel-Rip (ein makemkvcon-Aufruf je Titel, Fortschritt anteilig). Parser mit Tests. - [x] **Nativer Windows-Worker ohne Docker**: install.ps1 + Worker-Code werden von der Rippy-Instanz selbst serviert (/worker-setup/*); HandBrakeCLI 1.9.2 vom offiziellen GitHub-Release; celery --pool=solo -Q transcode; optional Autostart. UI bietet Linux- und Windows-Variante. E2E auf echtem Windows-PC bewiesen. - [x] **Anleitungs-Tab**: Rippy erklärt sich selbst (Disc-Weg, Serien, NAS, Media-Server, Benachrichtigungen, Key, Worker, FAQ). --- ## Etappe 17 (25.07.2026): 4K-UHD-Schlüssel (KEYDB.cfg) **Quelle:** Messung am 25.07. live auf der Rippy-VM im Worker-Container. Eine 4K-UHD (Akira, MKB v76, Pressung Dezember 2020) scheitert an „The volume key is unknown for this disc" — obwohl makemkvcon „Using LibreDrive mode (v06.3)" und „Using direct disc access mode" meldet, die Disc liest und den AACS-Dump ablegt (Meldung 3332). Das Debug-Log geht ohne einen einzigen Netz-Versuch von „Loaded content hash table" direkt auf den Fehler; `_private_data.tar` enthielt nur die Index-Datei und keine einzige `hkd_*.bin`; auch mit gelöschter `update.conf` (Meldung 5074 belegt den Web-Kontakt) und `app_UpdateEnable = "1"` kam kein Schlüssel; die Forum-Schlüssel-Server `hkdata.fairuse.org` und `hkdata.crabdance.com` lösen weltweit nicht mehr auf. **Fazit: Ein MakeMKV-Update löst das nicht** (das behauptete v3.3 — dort richtiggestellt). Der einzige heute funktionierende Weg ist eine `KEYDB.cfg` im MakeMKV-Datenverzeichnis. **Gebaut:** - [x] **Persistentes Datenverzeichnis**: `${MAKEMKV_DATA_HOST:-/srv/rippy/makemkv}` vom Host gemountet — Worker `/root/.MakeMKV`, API `/app/makemkv-data`, beide mit `MAKEMKV_DATA_DIR`. `KEYDB.cfg` und AACS-Dumps überleben jeden Rebuild. `.env.example` erklärt die Variable. - [x] **entrypoint.sh entschärft**: `settings.conf` wird ergänzt statt überschrieben (der Beta-Key hatte sonst alles andere gelöscht), `app_UpdateEnable = "1"` gesetzt. - [x] **Zwillings-Modul `makemkv_daten.py`** (identisch in `docker/api/` und `docker/worker/`) als einzige Wahrheit über das Verzeichnis: Status lesen, Inhalt prüfen, atomar schreiben, löschen, Dumps auflisten — alles reine Funktionen, damit die Ampel sie ohne Postgres/Redis testen kann. - [x] **API**: `GET/POST/DELETE /system/keydb`, `GET /system/aacs-dumps` und `GET /system/aacs-dumps/{dateiname}`. Der Inhalt kommt bewusst als JSON-Body — es gibt kein `python-multipart`, ein Endpunkt mit `UploadFile`/`File()` würde die API beim Import töten. - [x] **UI (Einstellungen → System)**: Status der `KEYDB.cfg` (Pfad, Größe, Anzahl Disc-Einträge, Datum), Inhalt einfügen, entfernen, AACS-Dumps herunterladen — ohne SSH auf die VM. - [x] **MakeMKV redet endlich**: `parse_msg()` in `ripping.py` + Log-Callback in `tasks.py` schreiben MakeMKV-Meldungen ins Rippy-Log (gedrosselt: Code 1003 raus, keine Wiederholungen, max. 40 je Rip). UHD-Fehlertext ehrlich neu geschrieben; `caps.py` meldet `keydb: ja | nein | unbekannt`. - [x] **Doku nachgezogen**: README (UHD-Voraussetzungen, System-Panel, `MAKEMKV_DATA_HOST`, Bereitstellung), SAVEPOINT v3.10 inkl. Richtigstellung von v3.3, KONZEPT §8 + §10. **Offen aus dieser Runde:** - [ ] **Der Nachweis mit einer echten `KEYDB.cfg` steht aus.** Zum Zeitpunkt der Änderung lag keine Datei vor, die den Akira-Schlüssel enthält — belegt sind der Befund und die Mechanik, NICHT ein erfolgreicher UHD-Rip. - [ ] Damit bleibt auch der volle Transcode-E2E an einer UHD weiter offen (siehe SAVEPOINT v3.7) — an normalen BD/DVD ist die Kette bewiesen. **Ausdrücklich nicht gebaut (und wird es auch nicht):** Rippy liefert keine Disc-Schlüssel mit, lädt keine herunter und verteilt keine. Es stellt nur den Platz für eine Datei bereit, die der Nutzer selbst mitbringt, und zeigt ehrlich an, was dort liegt. --- ## Ideen-Katalog (Rest) — bewusst offen 1. **Design 2.0** — an Gemini übergeben (24.07.2026). Vollständiges Briefing: `docs/DESIGN-2.0-BRIEFING.md`. Arbeitsbranch: `design-2.0` (deployt bewusst NICHT, nur `main` wird befördert). Kern: 428 `theme === 'dark'`-Ternaries → Tailwind-`dark:` + UI-Primitives, Optik-Modernisierung, ohne Funktions-/Text-Änderungen. Der neue Anleitungs-Tab gehört mit in den Feinschliff. 2. **AI-Box als VAAPI-Transcode-Worker**: Ports sind offen, Compose steht (deploy/remote-transcode-worker.yml) — es fehlt nur der NFS/SMB-Export der Rippy-Ablage an die AI-Box (Infra-Entscheid auf der VM). 3. **Kodi-Bibliotheks-Refresh** (JSON-RPC VideoLibrary.Scan) analog zu Jellyfin/Emby. 4. **Windows-Worker als echter Dienst** (statt start-worker.bat/onlogon): z. B. via NSSM oder PyInstaller-Paket — Komfort-Ausbau der jetzt funktionierenden nativen Variante.