Universal-Sprint: Wizard, UI-Mounts, Encoder-Erkennung, Task-Split, README
Ampel / ampel (push) Successful in 29s

Commander-Ziel: All-in-one, universell, weitergebbar.

- First-Run-Wizard: startet automatisch bei neuer Installation (Keys,
  Verarbeitung, erkannte Hardware); /setup + /setup/complete
- Data-Mounts via UI: Einstellungen -> Speicherziele haengt NFS/SMB direkt
  ein (mounts.py, CAP_SYS_ADMIN + rshared-Propagation, Auto-Remount beim
  Start, CIFS-Creds via Datei statt Kommandozeile); nfs-common/cifs-utils
  im api-Image
- Encoder-Erkennung: jeder Worker meldet beim Start ehrlich seine
  Faehigkeiten (caps.py -> workers-Tabelle), GET /capabilities, Anzeige
  in Wizard + Verarbeitung-Tab
- Task-Split: transcode_files als eigener Task auf Queue "transcode"
  (Basis fuer optionale Remote-GPU-Worker, deploy/remote-transcode-worker.yml
  EXPERIMENTELL) + POST /jobs/{id}/retry-transcode + UI-Knopf
  "Neu komprimieren" bei fehlgeschlagenen Jobs
- API-Keys aus der DB: Settings-UI/Wizard ueberstimmen Env — vorher waren
  die Key-Felder im UI reine Dekoration (Clients lasen nur Env)
- README komplett neu: generischer Schnellstart, Laufwerk-Override via
  docker-compose.override.yml, Architektur, Env-Tabelle

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-23 20:49:08 +02:00
parent e350523f7e
commit b584cc29ad
20 changed files with 984 additions and 154 deletions
+77 -95
View File
@@ -1,119 +1,101 @@
# README — Rippy
# Rippy — die All-in-one Disc-Ripping-Maschine
> **Moderner Ripping-Daemon mit Metadaten-Preview, Jellyfin-Formatierung und JWT-Auth.**
Disc rein → automatisch erkannt (Titel, Poster, Metadaten) → verlustfrei
gerippt (MakeMKV) → auf Arbeitsgröße komprimiert (HandBrake) → fertig
abgelegt, wo DU willst (lokal, NAS, jede Freigabe). Modernes Web-UI,
Echtzeit-Fortschritt, komplett in Docker, komplett lokal.
---
## Schnellstart
## Features
| Feature | Status |
|---------|--------|
| Disc-Erkennung (CD/DVD/Blu-ray) | ✅ |
| Metadaten-Lookup (TMDB/MusicBrainz/TheTVDB) | ✅ |
| Pre-Scan ohne Ripping | ✅ |
| Jellyfin-Formatierung (NFO + Images) | ✅ |
| JWT-Auth + Rate-Limiting | ✅ |
| React-UI mit Dashboard | ✅ |
| SQLite-Cache für API-Rate-Limits | ✅ |
| Multi-Disc-Set-Handling | ✅ |
---
## Architektur
```
┌─────────────────────────────────────────────┐
│ Proxmox LXC (Debian 12) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ API │ │ Worker │ │ UI │ │
│ │ FastAPI │◄─►│ Celery+ │ │ React+ │ │
│ │ │ │ Redis │ │ Nginx │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ PostgreSQL│ │ udev │ │ Media │ │
│ │ │ │ Daemon │ │ Store │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────┘
```
---
## Installation
### Docker Compose
Voraussetzungen: Docker + Docker Compose, ein optisches Laufwerk am Host.
```bash
git clone https://git.tobisniceshomelab.ddnsfree.com/Hitonabi/rippy.git
cd rippy
docker compose up -d
git clone <repo-url> rippy && cd rippy
cp .env.example .env # JWT_SECRET_KEY eintragen (openssl rand -hex 32)
mkdir -p /srv/rippy/media # Ablage-Basis (anpassbar in docker-compose.yml)
docker compose up -d --build
```
### Port-Übersicht
Dann `http://<host>` öffnen — der **Einrichtungs-Assistent** startet beim
ersten Mal automatisch (API-Keys, Verarbeitung, erkannte Hardware).
| Service | Port | URL |
|---------|------|-----|
| UI | 80 | http://localhost:80 |
| API | 8000 | http://localhost:8000 |
| PostgreSQL | 5432 | localhost:5432 |
| Redis | 6379 | localhost:6379 |
### Laufwerk anpassen
---
Standard ist `/dev/sr0` (+ `/dev/sg1` für den Worker — MakeMKV spricht
Laufwerke über die SCSI-Generic-Schicht an). Andere Geräte? Lege eine
`docker-compose.override.yml` an:
## API
```yaml
services:
api:
devices: ["/dev/sr1:/dev/sr0"]
worker:
devices: ["/dev/sr1:/dev/sr0", "/dev/sg2:/dev/sg1"]
```
### Endpoints
Welche sg-Nummer dein Laufwerk hat, verrät `lsscsi -g` oder
`ls -la /sys/class/scsi_generic/`.
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/health` | GET | Health check |
| `/jobs` | GET | Alle Jobs |
| `/devices` | GET | Alle Geräte |
| `/prescan` | POST | Pre-Scan durchführen |
| `/metadata/lookup` | POST | Metadaten lookup |
| `/metadata/confirm` | POST | Metadaten bestätigen |
| `/jellyfin/format` | POST | Für Jellyfin formatieren |
| `/token` | POST | Login (JWT) |
| `/token/refresh` | POST | Refresh Token |
| `/api-keys` | POST/GET/DELETE | API-Key Management |
**Laufwerk in einer VM?** Per USB-Passthrough anhand der Vendor-ID
durchreichen (Proxmox: `qm set <vmid> -usb0 host=xxxx:yyyy,usb3=1`) —
NICHT als emuliertes CD-ROM (`media=cdrom`), das kann keine SCSI-Kommandos.
---
## Wie es funktioniert
## Tech-Stack
1. **Disc-Wache** (ioctl-Polling, kein udev-Gefrickel) erkennt Einlegen,
identifiziert die Disc (Volume-Label → TMDB → OMDb-Fallback) und zeigt
sie mit Poster auf dem Dashboard.
2. **Rip** (MakeMKV, verlustfrei — der einzige Weg durch AACS): Ziel wählst
du beim Start (Filme/Serien/Musik/eigener Pfad, inkl. Netzwerk-Ziele).
Audio-CDs laufen über abcde → FLAC + MusicBrainz.
3. **Kompression** (HandBrake, eigener Job auf eigener Queue): x265/x264,
Preset im UI wählbar; Rohdatei wird erst nach Erfolg gelöscht
(„Original behalten" als Option). Fehlgeschlagene Kompressionen lassen
sich ohne Neu-Rip neu anstoßen.
4. **4K-UHD**: braucht ein LibreDrive-fähiges Laufwerk (MakeMKV-Forum:
„Ultimate UHD Drives Flashing Guide"). Normale BD/DVD gehen mit jedem
Laufwerk.
| Layer | Tech |
|-------|------|
| Backend | Python, FastAPI, Celery |
| Database | PostgreSQL, SQLite, Redis |
| Frontend | React, Vite, TailwindCSS |
| Ripping | MakeMKV, abcde, FFmpeg, HandBrake |
| Auth | JWT, OAuth2 |
## Speicherziele (NAS, Freigaben)
---
Unter **Einstellungen → Speicherziele** hängst du NFS- oder SMB-Freigaben
direkt aus dem UI ein — sie erscheinen sofort in der Ziel-Auswahl beim
Rippen und werden beim Start automatisch wieder verbunden.
Technik: der api-Container läuft mit `CAP_SYS_ADMIN` und einem
rshared-Bind auf `/srv/rippy/media`, Mounts propagieren zu allen
Containern. ⚠️ Zugangsdaten liegen unverschlüsselt in der lokalen
Postgres-DB — bewusster Heimnetz-Kompromiss; lege fürs NAS einen eigenen,
eingeschränkten Benutzer an.
## Roadmap
## Verarbeitung & Hardware
- [x] Etappe 1: Container-Infrastruktur
- [x] Etappe 2: Ripping-Pipeline
- [x] Etappe 3: Metadaten-Lookup + Pre-Scan
- [x] Etappe 4: Jellyfin-Formatierung
- [x] Etappe 5: API + Auth + WebUI
- [x] Etappe 6: Sicherheit + Compliance
- [x] Etappe 7: API UI Modernisiert
- [x] Etappe 8: Dark Mode & Separation of Concerns
- [ ] Etappe 9: Proxmox-Integration
**Einstellungen → Verarbeitung** zeigt ehrlich an, welche Encoder deine
Worker WIRKLICH haben (CPU x264/x265, VAAPI bei AMD/Intel-GPU, NVENC bei
NVIDIA) — jeder Worker meldet seine Fähigkeiten selbst beim Start.
---
### Optional: GPU-Maschine im Netz als Transcode-Worker
## License
Die Kompression läuft als eigener Celery-Task auf der Queue `transcode`
JEDE Maschine im Netz kann sie übernehmen (siehe
`deploy/remote-transcode-worker.yml`). Ohne Zusatz-Worker macht der
eingebaute CPU-Worker alles selbst — Rippy bleibt All-in-one.
GPL-v3
## Umgebungsvariablen (.env)
---
| Variable | Pflicht | Zweck |
|---|---|---|
| `JWT_SECRET_KEY` | ✔ | Signierschlüssel (openssl rand -hex 32) |
| `TMDB_API_KEY` | empfohlen | Metadaten — alternativ im UI/Wizard eintragbar |
| `OMDB_API_KEY` | optional | zweite Metadaten-Quelle (Fallback) |
| `THETVDB_API_KEY` | optional | Serien-Fallback |
| `MAKEMKV_APP_KEY` | optional | MakeMKV-Beta-Key (Forum); DVDs gehen ohne |
| `MAKEMKV_URL_BASE` | optional | alternative Download-Quelle für den Image-Build |
## Credits
UI-Einstellungen (Wizard/Settings) überstimmen die Env-Variablen.
- **Commander**: Projekt-Idee, Anforderungen, Testing
- **AI-Box**: Entwicklung, Architektur, Dokumentation
## Entwicklung
CI („Ampel") läuft bei jedem Push: Ruff, pytest, Vite-Build. Grün auf
`main` wird automatisch auf `stable` befördert — deploye von `stable`.
Regeln für Beiträge: [AGENTS.md](AGENTS.md) · Konzept: [KONZEPT.md](KONZEPT.md) ·
Fahrplan: [ROADMAP.md](ROADMAP.md)