Ampel / ampel (push) Failing after 54s
Beide Befunde des Commanders vom 28.08.2026 festgehalten, mitsamt der Begruendung, warum ein 'if (windows)' an dreissig Stellen die falsche Reparatur gewesen waere: Die Oberflaeche haette weiterhin nichts ueber ihren Betrieb gewusst, nur eine zweite Sorte Vermutung gehabt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
729 lines
35 KiB
Markdown
729 lines
35 KiB
Markdown
# 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 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: `<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`
|
||
- 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.
|
||
|
||
> ⚠️ **Nachtrag am selben Tag (siehe Etappe 18): Die letzte Folgerung war
|
||
> falsch.** Die beiden toten Hostnamen stammen aus alten Forumsbeiträgen und
|
||
> werden von MakeMKV längst nicht mehr benutzt — der Dienst lebt. Richtig
|
||
> ist: `makemkvcon` unter **Linux** fragt nie nach Schlüsseln, die
|
||
> **Windows**-Version schon. Alles hier Gebaute bleibt richtig und nötig,
|
||
> nur die `KEYDB.cfg` ist nicht der Haupt-, sondern der Ersatzweg.
|
||
|
||
**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.
|
||
|
||
**Nachtrag zu „Offen":** Beide Punkte sind mit Etappe 18 erledigt — Akira
|
||
ging auf der VM auf, allerdings über den Schlüsselspeicher statt über eine
|
||
`KEYDB.cfg`.
|
||
|
||
**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.
|
||
|
||
---
|
||
|
||
## Etappe 18 (25.07.2026): 4K-UHD gelöst — Schlüsselspeicher statt KEYDB.cfg
|
||
|
||
**Quelle:** Einwand des Commanders („wenn ich MakeMKV lokal auf meinem
|
||
Windows-PC installiere, würde es SOFORT gehen — wir übersehen etwas
|
||
Gewaltiges"). Er hatte recht. Gegenprobe mit demselben Laufwerk und
|
||
derselben Disc an einem Windows-PC:
|
||
|
||
| | Linux (Worker) | Windows |
|
||
|---|---|---|
|
||
| Verbindungen beim Disc-Öffnen | **keine einzige** | 185.84.108.20:443 |
|
||
| Meldung 3338 „Downloading latest HK" | nie | ja |
|
||
| `_private_data.tar` | 2048 B, 0 Schlüssel | 6,4 MB, 604 Schlüssel |
|
||
| Disc | „volume key is unknown" | **TCOUNT:5, geht auf** |
|
||
|
||
Gegengeprüft mit leerem UND gefülltem Speicher, mit und ohne `--noscan`,
|
||
mit `dev:/dev/sr0` und `disc:0`, mit gelöschter `update.conf`: Linux
|
||
fragt nie. Die Meldungsvorlage „Downloading latest %1 to %2 ..." steckt
|
||
sehr wohl im Linux-Binary — sie löst nur nicht aus. Gleiches Symptom im
|
||
MakeMKV-Forum, seit Jahren offen (t=25782, t=34022).
|
||
**Damit ist die Diagnose aus Etappe 17 („der Schlüssel-Kanal ist tot")
|
||
widerlegt.** Sie stützte sich auf zwei Hostnamen aus alten Forumsbeiträgen,
|
||
die MakeMKV längst nicht mehr benutzt.
|
||
|
||
**Gebaut:**
|
||
- [x] **Schlüsselspeicher im Modul**: `zaehle_schluessel`,
|
||
`private_data_pruefen`, `schluesselspeicher_status`,
|
||
`private_data_schreiben` in `makemkv_daten.py` (beide Zwillinge).
|
||
Die Prüfung lehnt einen Speicher OHNE `hkd_*.bin` ab — sonst lädt
|
||
jemand den leeren Vorrat einer frischen Installation hoch, es ändert
|
||
sich nichts, und niemand versteht warum.
|
||
- [x] **API**: `GET /system/keystore` und `POST /system/keystore`. Der
|
||
Rohkörper der Anfrage IST die Datei — binär, deshalb kein JSON und
|
||
kein Base64; Multipart kann die API ohnehin nicht.
|
||
- [x] **UI**: neuer Block „Disc-Schlüssel für 4K-UHD" ÜBER dem
|
||
KEYDB-Block, mit Schlüssel-Anzahl, Upload und Schritt-für-Schritt-
|
||
Anleitung für den Windows-Umweg. KEYDB.cfg ist jetzt als Notnagel
|
||
beschriftet. Worker-Plakette zeigt die Schlüssel-Anzahl.
|
||
- [x] **Fehlertext** in `tasks.py` sagt den Windows-Weg an und nennt die
|
||
Anzahl bekannter Schlüssel dieses Workers.
|
||
- [x] **`caps.py`** meldet `schluessel` je Worker.
|
||
- [x] **Alle Falschaussagen korrigiert**: UI (3 Stellen), Anleitung (2),
|
||
README (3), KONZEPT §8 + §10, `makemkv_daten.py`-Modulkopf,
|
||
Worker-Dockerfile, `makemkv_key.py`.
|
||
|
||
**Bewiesen:** Nach Übernahme des Windows-Schlüsselspeichers öffnet
|
||
`makemkvcon` auf der VM die Akira-UHD — „Operation successfully
|
||
completed", `TCOUNT:5`, fünf Titel, identisch zum Windows-Ergebnis.
|
||
**Das ist der erste belegte UHD-Disc-Zugriff auf der Rippy-Maschine.**
|
||
|
||
**Offen aus dieser Runde:**
|
||
- [ ] Voller UHD-Rip inklusive Transcode-E2E (nur der Disc-Zugriff ist
|
||
belegt, nicht die komplette Kette bis zur fertigen Datei).
|
||
- [ ] Ob sich der Abruf unter Linux doch anstoßen lässt, ist ungeklärt —
|
||
der Code ist im Binary vorhanden. Bis dahin bleibt der Windows-Umweg.
|
||
|
||
---
|
||
|
||
## Etappe 19 (25.07.2026): Preset je Disc-Typ
|
||
|
||
**Quelle:** Rückfrage des Commanders beim ersten echten UHD-Rip („merkt
|
||
Rippy eigentlich, wenn es eine UHD-Disc ist, und wendet direkt das
|
||
4K-Preset an?"). Antwort war: nein. Die Kompression fragte den Disc-Typ
|
||
gar nicht — ein globales `transcodePreset` galt für alles, live eingestellt
|
||
`HQ 1080p30 Surround`. Der laufende 4K-Rip wäre danach auf 1080p
|
||
heruntergerechnet und der Rohschnitt gelöscht worden (`keepOriginal: False`).
|
||
|
||
**Gebaut:**
|
||
- [x] **`preset_fuer(disc_type, einstellungen)`** in `ripping.py` — pure
|
||
Funktion, drei Tests. Reihenfolge: Preset des Disc-Typs → allgemeines
|
||
`transcodePreset` → `DEFAULT_HB_PRESET`. Bestandsinstallationen
|
||
ändern ihr Verhalten NICHT, solange die neuen Felder ungespeichert sind.
|
||
- [x] **`transcode_files`** holt den Disc-Typ aus dem Job-Datensatz und
|
||
schreibt ihn mit ins Log („Disc-Typ 'uhd', Preset '…'").
|
||
- [x] **UI**: drei Auswahlfelder (DVD / Blu-ray / 4K-UHD) statt einem, mit
|
||
Erklärung, warum 4K auf ein 2160p-Preset gehört. Preset-Namen aus
|
||
`HandBrakeCLI --preset-list` im Worker-Image belegt, nicht geraten.
|
||
- [x] **Sofortmaßnahme am laufenden Job**: `keepOriginal` auf `True`, damit
|
||
der 4K-Rohschnitt die Kompression überlebt.
|
||
|
||
**Offen aus dieser Runde:**
|
||
- [ ] **Deploy steht aus** — er würde den laufenden Akira-Rip abbrechen.
|
||
Erst nach Abschluss des Jobs deployen, dann bei Bedarf „Neu
|
||
komprimieren" mit dem 4K-Preset.
|
||
|
||
---
|
||
|
||
## Rippy v2 — Etappen V2-0 bis V2-7 (Plan vom 28.08.2026)
|
||
|
||
**Vollständige Spezifikation: `KONZEPT-V2.md`.** Hier stehen nur die Etappen
|
||
und ihre Abnahmekriterien.
|
||
|
||
**Ziel:** drei Betriebsmodi statt eines — Docker (wie heute, aufgeräumt), eine
|
||
native Windows-App ohne Docker, eine Headless-Linux-Anwendung. Alle drei mit
|
||
demselben Webinterface, alle drei aus EINEM Kern.
|
||
|
||
**Grundregel für den ganzen Weg:** Jede Etappe endet mit grüner Ampel und einem
|
||
lauffähigen System. v1 läuft bis V2-5 produktiv weiter — auf der VM liegen echte
|
||
Medien.
|
||
|
||
### V2-0: Monorepo — ein Paket statt Zwillingen
|
||
- [ ] `src/rippy/` als gemeinsames Paket anlegen (api UND worker importieren daraus)
|
||
- [ ] Die byte-identischen Zwillinge zusammenführen: `detection.py`,
|
||
`makemkv_daten.py`, `notify.py` — je zweimal im Repo
|
||
- [ ] Tests wandern mit; `test_zwillinge_sind_byteweise_identisch` wird
|
||
gegenstandslos und weicht einem Test, der die EINE Quelle prüft
|
||
- [ ] Beide Dockerfiles kopieren `src/rippy`, `PYTHONPATH` gesetzt
|
||
- **Verhalten unverändert.** Kein Funktionsgewinn, reine Struktur.
|
||
- **Fertig, wenn:** Ampel grün, `docker compose up` verhält sich wie vorher,
|
||
kein Modul mehr doppelt im Repo.
|
||
|
||
### V2-1: Ports einziehen
|
||
- [ ] `Store`, `Queue`, `Bus`, `Drives` als Python-`Protocol`
|
||
- [ ] v1-Verhalten läuft über die Treiber Postgres / Celery / Redis / Linux
|
||
- [ ] Kein Funktionsgewinn — reine Verdrahtung
|
||
- **Fertig, wenn:** Ampel grün und ein Rip auf der VM durchläuft.
|
||
|
||
### V2-2: Standalone (SQLite + lokale Queue)
|
||
- [ ] SQLite-Treiber mit WAL, `busy_timeout`, ein Schreiber-Kontext
|
||
- [ ] Alembic statt handgeschriebener `ALTER TABLE … IF NOT EXISTS`
|
||
(das ist Postgres-only und bricht auf SQLite)
|
||
- [ ] LocalQueue: Auftrags-Tabelle + Lease + Prozesspool, kein Broker
|
||
- [ ] Lease ersetzt `zombies.py` — abgelaufene Lease = Auftrag ist frei
|
||
- [ ] `rippyd --profil standalone`
|
||
- **Fertig, wenn:** ein DVD-Rip komplett ohne Postgres, Redis und Docker läuft.
|
||
|
||
### V2-3: Echtzeit — Polling raus
|
||
- [ ] Bus-Treiber (asyncio in-process / Redis Pub/Sub)
|
||
- [ ] `GET /api/v2/events` als SSE-Strom, `snapshot` beim Verbinden,
|
||
lückenlose `seq` für Wiederaufnahme
|
||
- [ ] UI auf einen `useEventStream`-Haken; die neun `setInterval` fliegen raus
|
||
- [ ] `test_grenze_deckt_die_eigene_last_ab` auf die neuen Zahlen ziehen
|
||
- **Fertig, wenn:** Grundlast ≈ 0/min gemessen (heute ≈ 133/min bei einem Tab
|
||
plus Worker) UND ein Verbindungsabriss keine Liste leert.
|
||
|
||
### V2-4: Windows nativ
|
||
- [x] `drives/windows.py` — Win32 statt ioctl (`IOCTL_STORAGE_CHECK_VERIFY2`,
|
||
`IOCTL_STORAGE_MEDIA_REMOVAL`, `IOCTL_STORAGE_EJECT_MEDIA`,
|
||
MMC `GET CONFIGURATION` für den Disc-Typ)
|
||
- [ ] Disc-Einwurf per `WM_DEVICECHANGE` statt Polling — **offen**, läuft
|
||
vorerst über den Poll aus `drives/detection.py`
|
||
- [x] Dienst + Fenster als GETRENNTE Prozesse; **WebView2-Fenster**
|
||
(`fenster.py`, Entscheid 4 in `KONZEPT-V2.md` § 10)
|
||
- [x] Eintrag in „Programme und Features" und im Taskmanager als `Rippy.exe`
|
||
(ausdrücklicher Wunsch des Commanders)
|
||
- [x] Desktop-Symbol und Startmenü-Eintrag, im Setup abschaltbar
|
||
- [x] Werkzeug-Erkennung und -Beschaffung (`tools/katalog.py`,
|
||
`tools/beschaffen.py`) — Rippy findet, holt und aktualisiert
|
||
HandBrake/MakeMKV selbst
|
||
- [x] **Das Setup richtet die Werkzeuge wirklich ein** (`tools/einrichten.py`,
|
||
Entscheid 5) — HandBrakeCLI liegt im Paket (GPL-2), MakeMKV wird beim
|
||
Einrichten vom Hersteller geholt. Ein Setup, dem ein Pflichtwerkzeug
|
||
fehlt, meldet das im Klartext statt Erfolg.
|
||
- [x] Symbol mit allen Größen, die Windows holt (16/32/48/256) — vorher steckte
|
||
nur 256×256 in der `.ico`, und Desktop, Startmenü und Taskleiste zeigten
|
||
ein leeres Blatt
|
||
- [x] **Ein echtes Setup** (`einrichtung.py`, `setup_fenster.py`): acht
|
||
Voraussetzungs-Prüfungen, Zielordner UND Ablage zur Wahl, Port,
|
||
Autostart/Verknüpfungen/Werkzeuge als Schalter. Vorher installierte der
|
||
Doppelklick stillschweigend und öffnete das Fenster.
|
||
- [x] **Die Oberfläche kennt ihren Betrieb** (`betrieb.py`, `GET /betrieb`,
|
||
`useBetrieb.tsx`): keine Worker-Zähler, keine Container-Platte, kein
|
||
`docker compose ps` mehr im Windows-Client — und der Docker-Betrieb
|
||
behält alles.
|
||
- [ ] Standby blocken via `SetThreadExecutionState`, ohne `ES_DISPLAY_REQUIRED`
|
||
— **offen**
|
||
- **Fertig, wenn:** auf einem frischen Win-11-Rechner gilt: Installer →
|
||
Disc rein → MKV raus. Und der UHD-Schlüssel kommt automatisch.
|
||
**Noch offen:** ein echter Rip auf Windows ist ungeprüft — das Laufwerk
|
||
hängt an der VM.
|
||
|
||
> **Abweichung vom Plan, bewusst und mit Folgen.** Statt Nuitka `--standalone`
|
||
> (one-dir) + Inno Setup wurde **PyInstaller onefile** genommen: ein Programm,
|
||
> drei Betriebsarten (`RippySetup.exe`, `--dienst`, `--deinstallieren`), kein
|
||
> zweites Werkzeug in der Kette.
|
||
>
|
||
> Der Preis stand oben schon im Plan — *„ein Onefile-Paket entpackt sich bei
|
||
> jedem Start neu nach `%TEMP%`"* — und er ist am 28.08.2026 fällig geworden:
|
||
> Ein Dienst lief eine Stunde, `/api/health` gab 200, `/` gab **404**. Vom
|
||
> Entpack-Verzeichnis des laufenden Prozesses waren 31 statt 44 Einträge übrig,
|
||
> `ui` und `api` fehlten. Die API meldete sich gesund, während die Oberfläche
|
||
> weg war.
|
||
>
|
||
> **Gegenmaßnahme:** Der Installer legt die Oberfläche als Kopie NEBEN das
|
||
> Programm (`windows_app.ui_auspacken`), und `daemon._ui_pfad()` nimmt diese
|
||
> Kopie vor dem Entpack-Verzeichnis. Zwei Tests halten das fest. Sollte sich
|
||
> derselbe Ausfall an den API-Modulen zeigen, ist one-dir die richtige Antwort
|
||
> — dann ist diese Abweichung zurückzunehmen.
|
||
|
||
### V2-5: Docker neu
|
||
- [ ] EIN Image, drei Profile (`standalone`, `api`, `node`)
|
||
- [ ] GPU-Durchreichung: `/dev/dri` für QSV/VAAPI, `runtime: nvidia` für NVENC
|
||
- [ ] **Host-Mounts statt Container-Mounts** (Entscheid 28.08.2026)
|
||
- [ ] Multi-Arch; ARM64 ist Encode-/API-Knoten (MakeMKV hat kein ARM64-Binary)
|
||
- **Fertig, wenn:** All-in-One und verteilt laufen und `SYS_ADMIN`,
|
||
`DAC_READ_SEARCH`, `apparmor:unconfined` weg sind.
|
||
|
||
### V2-6: CLI & Pakete
|
||
- [ ] `rippy status / drives / scan / rip / queue / logs --follow / doctor`
|
||
- [ ] `rippy doctor` = die Prüfphase aus `install.sh` als Befehl (erst alles
|
||
prüfen, dann berichten, nichts ändern)
|
||
- [ ] systemd-Unit mit `SupplementaryGroups=cdrom` und `DeviceAllow` für
|
||
block-sr UND char-sg (ohne sg findet MakeMKV kein Laufwerk)
|
||
- [ ] udev-Regel für echte Disc-Ereignisse; ioctl-Poll bleibt Rückfallebene
|
||
- [ ] `.deb` / AppImage
|
||
- **Fertig, wenn:** ein Headless-Server ohne Browser bedienbar ist.
|
||
|
||
### V2-7: Neue Features
|
||
- [ ] Multi-Drive Parallel-Ripping (Rip parallel, **Schlüssel-Phase
|
||
serialisiert** — vorher an zwei Laufwerken MESSEN, nicht annehmen)
|
||
- [ ] Zero-Click gegen Interaktiv, je Laufwerk und Disc-Typ
|
||
- [ ] Auto-Presets nach gemessener Hardware (Vorschlag, kein Zwang)
|
||
- [ ] Ton-/Untertitel-Regelwerk (Originalton, Wunschsprachen, erzwungene
|
||
Untertitel behalten, Kommentarspuren verwerfen, HD-Ton durchreichen)
|
||
- [ ] **Schlüsselkette in drei Stufen** (Entscheid 28.08.2026, `KONZEPT.md` § 10)
|
||
- [ ] Anime über AniList zusätzlich zu Jikan
|
||
- [ ] Medienserver-Refresh als Auftrag MIT Wiederholung (heute still scheiternd)
|
||
- [ ] FFmpeg-Direktpfad für reines Remuxen
|
||
- **Fertig, wenn:** je Feature ein Nachweis vorliegt.
|
||
|
||
---
|
||
|
||
## Ideen-Katalog (Rest) — bewusst offen
|
||
|
||
> **Stand 28.08.2026:** Punkt 3 (Kodi-Refresh) und Punkt 4 (Windows-Worker als
|
||
> Dienst) sind in den v2-Plan aufgegangen — Punkt 4 ist V2-4, Punkt 3 steckt in
|
||
> V2-7 („Medienserver-Refresh"). Punkt 2 (AI-Box als Transcode-Worker) wird von
|
||
> V2-5 abgedeckt, sobald der Host-Mount-Weg steht.
|
||
|
||
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.
|