Ampel / ampel (push) Successful in 54s
Commander: "handbrake und makemkv MUESSEN mitgeliefert werden oder waehrend
des Setups separat installiert werden! Ohne das ist das tool NICHT
einsatzfaehig."
Er hat recht, und die Luecke war real: katalog.py konnte die Werkzeuge
finden, beschaffen.py konnte sie holen -- das Setup rief beides nie auf. Wer
Rippy auf einem frischen Rechner installierte, bekam eine Oberflaeche, die
ihm sagte was fehlt, und keinen Weg, es zu aendern.
Die beiden gehen unterschiedliche Wege, und der Grund ist die LIZENZ:
* HandBrakeCLI ist GPL-2 -> mitgeliefert. Weitergabe ausdruecklich erlaubt,
solange Lizenztext und Quellverweis dabei sind (LIZENZ-HandBrake.txt liegt
daneben). Damit komprimiert Rippy auch ohne Internet.
* MakeMKV ist proprietaer -> beim Einrichten vom Hersteller geholt und mit
DESSEN Installer installiert. Weitergabe durch Dritte ist nicht erlaubt.
Das ist dieselbe Black-Box-Trennung wie in KONZEPT.md 6 und deckt sich mit
KONZEPT-V2.md 4.1 ("MakeMKV wird NICHT mitgeliefert").
Drei Regeln, die dazugehoeren:
1. Ein Setup meldet NIE Erfolg, waehrend ein Pflichtwerkzeug fehlt.
sicherstellen() liest den Bestand VOR und NACH dem Versuch und gibt
zurueck, was danach wirklich da ist -- nicht, dass es versucht wurde.
2. Ein nicht erreichbarer Download bricht die Installation nicht ab. Am
28.08.2026 antwortete makemkv.com mit HTTP 525. Rippy ist dann trotzdem
installiert und sagt im Klartext, was fehlt und wie man es beschafft.
3. Ohne HandBrake ist Rippy einsatzbereit (Rip laeuft, nur ohne Kompression),
ohne MakeMKV nicht. Nur Pflichtwerkzeuge entscheiden ueber "bereit".
Nachgemessen am fertigen Setup: HandBrake geloescht, installiert, nach DREI
Sekunden wieder da (74 MB, also aus dem Paket und nicht geladen), Meldung
"Rippy ist einsatzbereit. HandBrakeCLI 1.11.2 / MakeMKV 1.18.4".
RippySetup.exe waechst von 32,0 auf 56,4 MB.
fix(tools): der Fortschritts-Rueckruf bekommt immer einen Text
_datei_laden schickte `None` als Text, wenn sich nur der Fortschritt geaendert
hatte. Der erste echte Aufrufer starb daran:
can only concatenate str (not "NoneType") to str
Ein Rueckruf, den man nur mit einer nirgends dokumentierten Sonderbehandlung
benutzen kann, ist eine Falle. Jetzt kommt immer ein Satz, gedrosselt auf
jedes zehnte Prozent -- 24 MB in 256-KB-Haeppchen waeren sonst hundert Zeilen
im Protokoll. Zwei Tests halten beides fest.
Nicht im Repo: Die 70,9 MB HandBrakeCLI holt der BAU nach
dist/windows/vendor/ (nicht versioniert) -- dasselbe Muster wie der
vendor/-Ordner fuer MakeMKV auf der VM.
Ampel lokal: 607 gruen, ruff sauber.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
721 lines
35 KiB
Markdown
721 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
|
||
- [ ] 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.
|