Files
rippy/KONZEPT.md
Hitonabi 8eb5653848
Ampel / ampel (push) Successful in 55s
Restefeger: Auth komplett raus, Serien-Flow + Episoden-Matching, Jellyfin-Refresh, Duplikat-Warnung, echtes Nur-Hauptfilm
AUTH ENTFERNT (Commander-Entscheid 24.07., KONZEPT §10): /token- und
/api-keys-Endpoints, auth.py, test_auth.py, passlib/bcrypt/PyJWT/
python-multipart, JWT_SECRET_KEY-Pflicht. Heimnetz-only, das UI hatte nie
einen Login — die Auth-Oberflaeche war Placebo und die passlib/bcrypt-
Falle brach die Ampel. Rate-Limit pro IP bleibt. Schnellstart laeuft
jetzt ganz ohne .env-Pflichtwerte.

Serien-Flow (Etappe-12-Kern, ARM-Wunde #395):
- Rip-Dialog: Serienname + Staffel -> Ablage <Serie>/Season NN
  (jellyfin.org/docs Naming-Schema); tvshow.nfo + poster.jpg im
  Serien-Ordner, bei Staffel 2 nicht ueberschrieben.
- Episoden-Matching per Laufzeitabgleich: HandBrakeCLI --scan
  ('+ duration:', handbrake.fr/docs) je MKV gegen TMDB-Staffel-Laufzeiten
  (GET /metadata/tv/{id}/season/{n}; tv-season-details-API).
  Ordnungserhaltend; komplette Staffel auf einer Disc klappt auch bei
  uniformen Anime-Laufzeiten (Sequenz-Stufe). Umbenannt wird NUR bei
  eindeutiger Zuordnung — sonst ehrliches Log. Mit Tests.

Weitere Punkte:
- Jellyfin/Emby-Bibliotheks-Refresh nach jedem fertigen Rip
  (POST /Library/Refresh, X-Emby-Token lt. jellyfin.org/docs) —
  URL/Key + Test-Knopf in Einstellungen -> Ripping.
- Duplikat-Warnung: Disc-Fingerabdruck (jetzt Teil des Prescan-Ergebnisses
  + der Job-Metadaten) gegen die Historie; Karte zeigt 'bereits gerippt',
  Vollautomatik ueberspringt Duplikate.
- 'Nur Hauptfilm' ECHT: makemkvcon info -> TINFO-Attr-9-Laufzeiten
  (usage.txt) -> laengster Titel -> mkv dev:X <nr>. Vorher wirkungsloses
  Setting; pro Rip im Dialog uebersteuerbar. Mit Tests.
- OMDb-Treffer eingedeutscht via TMDB /find (external_source=imdb_id,
  de-DE; find-by-id-API).
- Dashboard: Speicherplatz-Anzeige (amber < 60 GB) + CSV-Export
  (GET /jobs/export, Semikolon+BOM fuer deutsches Excel).
- Metadaten-Seite entfernt (Abnahme durch Commander-Auftrag) inkl.
  Placebo-Endpoints /metadata/lookup (scannte Dummy-Device) und
  /metadata/confirm (schrieb nie gelesenen Cache-Key).
- Doppel-Jahr-Fix: 'X (2009) (2009)' in Log und Ordnernamen.
- Remote-Worker-Blocker: redis (6379) + postgres (5432) waren NIE
  veroeffentlicht — kein Remote-Worker konnte sich je verbinden. Ports
  jetzt offen (Heimnetz-Kompromiss, kommentiert) + API_URL fuer Worker.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 14:22:19 +02:00

189 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# KONZEPT — Rippy
> Automatisches Ripping-System für CD, DVD und Blu-ray, gebaut für Proxmox LXC (Debian 12 Slim). Ziel: Ein modernes, eigenständiges System statt veralteter ARM-Flask-UI.
---
## 1. Ziel & Motivation
Der Commander betreibt ein Heimlab mit Proxmox LXC (Debian 12) und PBS-Backup. Das vorhandene Automatic Ripping Machine (ARM) ist funktional, aber das UI (Flask) ist veraltet, es hat keine Echtzeit-Updates (kein SSE/WebSocket), keine JWT-Auth und eine monolithische Architektur.
Rippy ist ein **komplett neues System** von Grund auf: modulare Multi-Container-Architektur, modernes WebUI, Echtzeit-Jobstatus, sichere Authentifizierung — gebaut als eigenständiges Produkt, nicht als ARM-Fork.
## 2. Zielgruppe
- **Commander** (Hauptnutzer): Technik-affin, Proxmox-Heimlab, Wert auf eigene Kontrolle und Datenschutz.
- **Zukünftig**: Weitere Heimlab-Nutzer mit ähnlicher Infrastruktur.
## 3. Kern-Idee
Ein modular aufgebautes System, das bei Disc-Einwurf automatisch den Typ erkennt, **vorbereitend Metadaten lookup und Preview bereitstellt**, das Medium rippt, Metadaten anreichert und das Ergebnis **Jellyfin-konform strukturiert ablegt**. Alles über eine REST-API, asynchrone Celery-Jobs, ein React-WebUI.
## 4. Features
| Feature | Muss | Kann | Später |
|---------|------|------|--------|
| Disc-Erkennung via udev-Event | ✔ M | | |
| Dynamischer Device-Resolver (UUID/Serial) | ✔ M | | |
| MakeMKV-Ripping (lossless) | ✔ M | | |
| Audio-Rip mit abcde + MusicBrainz | ✔ M | | |
| **Metadaten-Lookup VOR dem Ripping (Preview)** | **✔ M** | | |
| **Jellyfin-Ordnerstruktur & NFO-Generierung** | **✔ M** | | |
| **Jellyfin-Poster/Backdrop/Fanart Download** | **✔ M** | | |
| **Jellyfin-kompatible Dateibenennung** | **✔ M** | | |
| Video-Metadaten via TMDB API | ✔ M | | |
| AcoustID-Fingerprinting (chromaprint) | ✔ M | | |
| Multi-Disc-Set-Handling (Release-Group-Resolver) | ✔ M | | |
| SQLite-Cache für API-Rate-Limits | ✔ M | | |
| ~~JWT-Auth (Access 15min/Refresh 7 Tage)~~ — GESTRICHEN 24.07.2026, siehe §10 | | | |
| Rate-Limiting (100/min pro Client-IP) | ✔ M | | |
| Celery-Queue + Redis mit AOF-Persistence | ✔ M | | |
| React-UI (statisch via Nginx) | ✔ M | | |
| Proxmox LXC Template + Ansible Playbooks | ✔ M | | |
| SELinux/AppArmor Profile pro Container | ✔ M | | |
| MakeMKV als isolierte Black-Box-CLI | ✔ M | | |
| GPL-v3-Compliance-Checkliste | ✔ M | | |
| Source-Release-Endpoint | ✔ M | | |
| HandBrake-Kompression NACH dem Lossless-Rip (Stufe 2) | ✔ M | | |
| Prometheus+Grafana Monitoring | | ✔ K | |
| PBS-Snapshot-Backup-Hooks | | ✔ K | |
| Multi-Disc-Parallelisierung | | | ✔ S |
| Redis-Cluster (Horizontales Scaling) | | | ✔ S |
| PWA Mobile-App | | | ✔ S |
## 5. Mechaniken & Ablauf
**Roter Faden — was passiert, wenn der Commander eine Disc einlegt:**
1. **udev-Event** → System-Dämon (unabhängig vom API-Container) erkennt Einwurf.
2. **Device-Resolver** (udev-basiert) ermittelt UUID/Serial-Nummer des Laufwerks, erzeugt Symlink `/dev/disc/<uuid>`.
3. **Job-Erstellung** → Dämon erstellt Celery-Task, übergibt Device-Pfad und Disc-Typ.
4. **Typ-Erkennung** (CD/DVD/Blu-ray) → Auswahl des Ripping-Pfads.
5. **METADATEN-Lookup im VORFELD**:
- DVD/Blu-ray: `makejungles` liest TOC ohne Ripping.
- Title, Laufzeit, Scene-Labels werden ausgelesen.
- Video-Titel wird gegen TMDB API gegengeprüft → Confidence-Score.
- Audio-Titel wird gegen MusicBrainz gegengeprüft (bei CD).
- **Rippy zeigt eine Preview im WebUI**: Titel, Jahr, Cover, Trackliste.
- Commander bestätigt oder korrigiert manuell.
6. **Ripping** (nach Bestätigung):
- CD: `abcde` → FLAC, Metadaten via AcoustID + MusicBrainz.
- DVD/Blu-ray: `makemkvcon` → verlustfreies MKV als ZWISCHENPRODUKT in /app/temp
(MakeMKV ist der einzige Weg durch AACS — HandBrake kann verschlüsselte
Discs nicht lesen), danach **HandBrake-Kompression auf Arbeitsgröße**
(x265; Commander-Entscheid 23.07.2026: 40-GB-Rohdateien sind kein
brauchbares Endprodukt). Roh-Datei wird nach Erfolg gelöscht
(Setting keepOriginal behält sie).
7. **Post-Processing & Jellyfin-Formatierung**:
- Dateien in Jellyfin-konformer Ordnerstruktur.
- NFO-Dateien im Kodi/NFO-Schema.
- Poster/Backdrop/Fanart von TMDB.
8. **Multi-Disc-Erkennung**: Release-Group-Resolver prüft weitere Discs.
9. **Status-Push**: Worker sendet Fortschritt an UI.
10. **Abschluss**: Job-Ergebnis protokolliert, PBS-Backup-Hook.
## 6. Architektur & Tech-Stack
**Container-Design:**
- **API-Service** (FastAPI): JWT-Auth, REST-Endpoints, OpenAPI-Docs, Job-Management.
- **Worker-Service** (Celery + Redis mit AOF-Persistence): Isolierte Ripping-Jobs.
- **UI-Service** (React + Vite): Build-Step → statisch via Nginx.
- **udev-Daemon**: Separater System-Dienst für Disc-Einwurf-Events.
**Container-Security:**
- `read_only: true` für API/Worker (keine Schreibrechte außer tmpfs)
- `tmpfs` für `/app/tmp`, `/run`, `/tmp` (wichtig für Python `__pycache__`)
- Healthchecks für Postgres/Redis
- Separate Volumes für Medien und Temp-Dateien
**Neue Worker-Komponenten:**
- **NFO-Generator**: `.nfo`-Dateien im Jellyfin-Kodi-Schema.
- **TMDB Image-Downloader**: poster.jpg, fanart.jpg, backdrop.jpg.
- **Pre-Scan-Modul**: TOC-Lesung ohne Ripping + API-Query.
**LXC-Isolation:**
- Read-only Bind-Mounts für System-Bibliotheken.
- Device-Node-Read-Only für `/dev/sr*`.
- SELinux/AppArmor Profile pro Container.
- Netzwerk-Policy: UI→API (HTTPS), API↔Worker (mTLS).
**Persistenz:**
- PostgreSQL für Job-Logs, Metadaten, User-Management.
- SQLite-Cache für API-Antworten (LRU, 10k Einträge).
- NFS/Bind-Mount für Medien-Store.
## 7. UX-Flow
1. **Dashboard** — Echtzeit-Kacheln mit Job-Status, Queue-Übersicht.
2. **Job-Verlauf** — Tabelle aller Jobs mit Status, Fortschrittsbalken.
3. **Metadaten-Preview** — Nach udev-Erkennung: Titel, Jahr, Cover, Trackliste, Confidence-Score.
4. **Job-Detail** — Live-Log-Ausgabe, Fortschritt, "Abort".
5. **Ergebnis-View** — Liste gerippter Dateien, Metadaten, Jellyfin-Ordnerstruktur.
6. **Einstellungen** — API-Keys, Transcoding, Backup-Pfade, Jellyfin-Config.
7. **Geräte-Verwaltung** — Liste Laufwerke, Status, Device-Resolver.
## 8. Risiken & offene Punkte
| Risiko | Status | Behandlung |
|--------|--------|------------|
| MakeMKV-Beta-Key-Management | Gelöst | Key-Erneuerung als Cron-Job; DMCA-Ausnahme in DE |
| LXC-Device-Node-Änderungen | Gelöst | udev-Resolver (UUID/Serial) |
| Pending-Queue / State-Manager | Gelöst | Redis mit AOF-Persistence |
| Hybrid-Discs | Offen | MVP erkennt nur Standard; als "Kann" notiert |
| LXC-Device-Passthrough | Gelöst | Read-only Bind-Mounts; udev-Daemon unabhängig |
| Rate-Limits der Metadaten-APIs | Gelöst | SQLite-Cache (LRU, 10k Einträge), exponential backoff |
| GPL-v3-Compliance | Gelöst | Checkliste, Source-Release-Endpoint, Black-Box-Trennung |
| Redis Single-Instance | Offen | MVP mit Single-Instance; Cluster als "Später" |
| **TMDB-Matching-Fehler bei Nischentiteln** | **Offen** | Pre-Scan Confidence-Score + manueller Korrektur-Mechanismus |
| **NFO-Format-Abhängigkeit von Jellyfin-Version** | **Hinweis** | Kodi/NFO-Schema (stabil, gut dokumentiert) |
| **Pre-Scan-Latenz (515s)** | **Hinweis** | Akzeptabel für Heim-Use-Case; parallelisierbar |
| **TMDB-Bildrechte** | **Gelöst** | TMDB API-ToS erlaubt private Nutzung |
## 9. Härtetest-Dokumentation
**Erster Haertetest (Advocatus Diaboli, GLM-4.7-Flash):**
5 BLOCKER gefunden: MakeMKV-Key-Management, LXC-Device-Resolver, Pending-Queue, Hybrid-Discs, Bind-Mount-Performance.
**Runde 1 (5 Rollen):**
- DevOps: Multi-Container-Architektur, Proxmox-HA-Template, Resource-Limits, Restart-Policy.
- Security: JWT-Refresh-Token, Rate-Limiting, mTLS, SELinux/AppArmor.
- Software Architekt: udev-basierter Device-Resolver, Unix-Socket, State-Manager.
- Media Metadata: AcoustID-Fingerprinting, Multi-Disc-Set-Handling, SQLite-Cache.
- Legal: GPL-v3-Checkliste, MakeMKV-Black-Box-Trennung, Source-Release-Endpoint.
**Zweiter Haertetest (Advocatus Diaboli, GLM-4.7-Flash):**
5 HINWEISE (keine BLOCKER): React als Build-Step+Statisch (korrigiert), Redis-AOF-Persistence (integriert), Read-only vs. Write-Konflikt (nicht relevant), Redis-Cluster (als "Später" notiert), Cold-Boot-Problematik (udev-Daemon gelöst).
**Dritte Iteration — Commander-Feedback:**
- Metadaten-Lookup VOR dem Ripping
- 100% Jellyfin-Kompatibilität
- Metadaten-Preview im UI
- Neue Risiken: TMDB-Matching-Fehler (mit Fallback), NFO-Format-Abhängigkeit (Hinweis), Pre-Scan-Latenz (Hinweis)
**Ergebnis:** Konzept ist wasserdicht für MVP-Phase.
## 10. Konzept-Fortschreibungen (dokumentierte Erweiterungen, keine Abweichungen)
- **24.07.2026 — Media-Server-Neutralität:** Die Jellyfin-Muss-Features
(Ordnerstruktur, NFO, Poster) bleiben vollständig bestehen; sie sind jetzt
über das Setting `mediaServer` auf Emby und Kodi ausgeweitet (identisches
Kodi-NFO-Schema) und für Plex auf die reine Benennung reduziert. Jellyfin
bleibt Referenz- und Empfehlungssystem im Einrichtungs-Assistenten.
- **24.07.2026 — Benachrichtigungen:** Webhook bei Job-Ende (Discord/Slack/
ntfy/generisch) als gebautes Feature — im UX-Flow Punkt 10 („Abschluss")
war das als Protokollierung angelegt, jetzt meldet Rippy aktiv.
- **23./24.07.2026 — udev → ioctl:** Der im Konzept beschriebene udev-Daemon
ist im Container prinzipbedingt nicht lauffähig; die Disc-Wache pollt per
Kernel-ioctl (3 s) — gleiches Verhalten, universell lauffähig.
- **24.07.2026 — AUTH GESTRICHEN (Commander-Entscheid):** Das Muss-Feature
„JWT-Auth" ist komplett entfernt (Endpoints, auth.py, Abhängigkeiten,
Env-Pflicht). Begründung: Rippy läuft ausschließlich im Heimnetz, das UI
hatte nie einen Login-Flow — die Auth-Oberfläche war Placebo und die
passlib/bcrypt-Abhängigkeit hat die CI-Ampel gebrochen. Rate-Limiting
(pro IP) bleibt. Wer Rippy je nach außen öffnet, stellt einen
Reverse-Proxy mit eigener Auth davor (z. B. Authelia/Caddy basicauth).
- **24.07.2026 — Serien-Flow:** Staffel-Ablage <Serie>/Season NN plus
Episoden-Zuordnung per Laufzeitabgleich (TMDB) — erfüllt Etappe-12-Ziel
„Serien-Episoden-Erkennung" in der ersten Ausbaustufe (nur bei
EINDEUTIGER Zuordnung wird umbenannt).