Praxis-Befund mit echter BD-50: reines UDF, der ISO-PVD-Leser griff nicht. Jetzt ECMA-167-Weg (AVDP Sektor 256 -> Main VDS -> PVD Tag-ID 1 -> Volume Identifier als d-string), mit Tests fuer das d-string-Parsing. ROADMAP Etappe 12 aus der ARM-Vollanalyse: was wir uebernehmen (Fingerprint-DB, bdmt_eng.xml, Suchdegradation, Manual Mode, Apprise, Multi-Drive, Backup-Modus) und wo wir ARM schlagen (Serien-Episoden- Matching, Main-Feature per Laufzeitabgleich). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
12 KiB
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/<uuid> - Job-Erstellung in Celery-Queue mit Disc-Typ und Device-Pfad
Fertig wenn:
- ✅
docker compose upstartet 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:
<Filmname> (<Jahr>)/<Filmname>-<title>.mkv - Serien:
<Serienname>/<Staffel N>/<Serienname> - S{N}E{N} - <Episode>.mkv - Musik:
<Künstler>/<Album> (<Jahr>)/<Track-Nr>. <Titel>.flac
- Filme:
- 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.mkvetc.
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).
- Worker-Dockerfile: makemkv-oss/makemkv-bin 1.18.4 multi-stage gebaut, Beta-Key via MAKEMKV_APP_KEY-Env (entrypoint.sh) — 23.07.
- ripping.py: auf
makemkvcon -r --progress=-same mkv dev:… allumgestellt, 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:
- POST /jobs (API → Celery → Worker) + Job-Persistenz in Postgres
- Disc-Watcher in der API (ioctl-Poll statt udev — Container-tauglich)
- Disc-Erkennung neu über Kernel-ioctls (detection.py, in API+Worker)
- /logs-Endpoint + echte Logs-Seite (Mock-Daten raus)
- /settings-Endpoints (Settings-Seite sprach vorher ins Leere)
- UI: Vite-Build + nginx mit /api-Proxy statt Dev-Server; relative API-Pfade
- compose: devices: statt Bind-Mounts; Ausgabe aufs media-Volume
- Jellyfin-Post-Processing an den Worker anbinden (NFO/Poster nach dem Rip)
- 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.
- Apprise-Benachrichtigungen: eine Lib für Telegram/Discord/…, Hooks auf job_completed/failed/awaiting_selection, Deep-Link ins UI.
- 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).