4c78914529
Ampel / ampel (push) Successful in 27s
Diese Sitzung endete wegen vollem Kontext. Der Savepoint ist so geschrieben, dass die naechste ohne Nachfragen weitermachen kann. ZUSTAND, den man kennen MUSS: Repofd1feaamit gruener Ampel, aber die VM laeuft noch61c38a0- die letzten zwei Commits sind NICHT deployt, und der Windows-Worker des Commanders laeuft mit altem Code. Der 80-GB-Rohschnitt liegt intakt auf der NAS, "Neu komprimieren" genuegt also, sobald der Blocker faellt. DER KERNBEFUND aus dem fehlgeschlagenen Test-Rip, mit Messung statt Vermutung: Das gezielte Routing funktionierte einwandfrei - sein PC nahm die Aufgabe an und lehnte sie 182 ms spaeter ab. Drei Ursachen griffen ineinander, zwei sind behoben, eine bleibt der Blocker (RIPPY_PATH_MAP wird von niemandem gesetzt). Die offenen Punkte stehen nach Prioritaet, jeweils MIT dem Kontext, der zum Weiterarbeiten fehlt: Format von pfad_lokal fuer Punkt 1, warum Punkt 2 nicht ohne die Preset-Liste vom Worker geht (AGENTS Regel D - Namen erfinden hat das Projekt zweimal teuer bezahlt), welcher Messpunkt sich fuer die ETA bewaehrt hat (/proc/<pid>/fdinfo statt Fortschrittsanzeige), und welche Datei jeweils dran ist. Dazu ein eigener Abschnitt "Fallen, die diese Sitzung gekostet haben" - deutsche Anfuehrungszeichen in doppelt gequoteten Python-Strings (dreimal), Code in f-String-Einsetzungen, docker exec ohne sh -c verschluckt Globs, /proc-Suche trifft die eigene Shell, und pydantic-core springt lokal wiederholt zurueck. Alles auch in den Memory-Notizen, damit es nicht wieder entdeckt werden muss. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1272 lines
71 KiB
Markdown
1272 lines
71 KiB
Markdown
# SAVEPOINT — Rippy
|
||
|
||
## Aktueller Stand: v3.16 — ÜBERGABE: externes Encoden konnte nie funktionieren (26.07.2026)
|
||
|
||
> **Zuerst lesen.** Diese Sitzung endete wegen vollem Kontext. Der Auftrag war
|
||
> Commander-Feedback aus der ersten Selbst-Einrichtung plus die Diagnose eines
|
||
> fehlgeschlagenen Test-Rips. Die Diagnose ist abgeschlossen, zwei Commits sind
|
||
> gebaut — **aber NICHT deployt**, und der Kern-Blocker steht noch offen.
|
||
|
||
### ZUSTAND, gemessen
|
||
|
||
| | |
|
||
|---|---|
|
||
| Repo | `fd1feaa`, Ampel **grün** |
|
||
| **VM** | **`61c38a0` — die letzten 2 Commits sind NICHT aktiv** |
|
||
| Windows-Worker des Commanders | läuft mit **altem** Code (vor der Windows-Erkennung) |
|
||
| Job `95afdc89` | `failed` beim Encoden |
|
||
| **Rohschnitt** | **79,6 GB intakt** auf `/app/media/rippy/95afdc89-…/title_t00.mkv` (NAS) → „Neu komprimieren" genügt, **kein Neu-Rip** |
|
||
| Commander-PC | AMD Ryzen 7 9700X · **avx512f** · 16 Kerne · RX 9070 XT |
|
||
| Rippy-VM-CPU | QEMU-Generikum · nur `sse4_2` · 4 Kerne |
|
||
|
||
### DER KERNBEFUND: drei Ursachen, die ineinandergriffen
|
||
|
||
Der Commander vermutete „das System sieht den externen Encoder nicht". **Falsch —
|
||
das Routing funktionierte einwandfrei.** Gemessen:
|
||
|
||
```
|
||
meta.transcode_node = tobisnicerpc@TobisNicerPC
|
||
VM-Worker-Log = nur rip_disc, KEIN transcode_files
|
||
22:19:41.271 Kompression eingereiht
|
||
22:19:41.453 "Keine Roh-MKVs gefunden" ← 182 ms später
|
||
```
|
||
|
||
Sein PC nahm die Aufgabe an und lehnte sie sofort ab. Warum:
|
||
|
||
1. **`RIPPY_PATH_MAP` wird von NIEMANDEM gesetzt** — nicht vom Installer, nicht
|
||
vom UI, nicht von Compose. `pfad_lokal()` in `tasks.py` hat sogar Tests, aber
|
||
keinen Anschluss. `/app/media/...` sind Container-Pfade; ein externer Worker
|
||
sieht sie nur übersetzt. **Ein Windows-Worker konnte also nie transcodieren.**
|
||
⚠️ **DAS IST DER OFFENE BLOCKER.**
|
||
2. **Die Ablage war im UI überhaupt nicht einstellbar.** `outputDir` wurde von
|
||
Vollautomatik und Schnellwahl gelesen, hatte aber **kein Eingabefeld**. Das
|
||
Arbeitsverzeichnis hatte eine Auswahl eingehängter Ziele, das Ziel nicht.
|
||
Folge: Rohdaten auf der NAS (erreichbar), Ziel auf der VM-Platte (nicht
|
||
erreichbar — dort läuft **kein Samba**). Die richtige Einstellung war mit den
|
||
vorhandenen Bedienelementen **nicht erreichbar.** → behoben, siehe unten.
|
||
3. **Die Fehlermeldung log.** „Keine Roh-MKVs gefunden" klang nach kaputtem Rip,
|
||
obwohl der Rip vollständig war. → behoben.
|
||
|
||
### GEBAUT in dieser Sitzung (2 Commits, gepusht, Ampel grün)
|
||
|
||
**`fe12401`** — Hardware-Encoder + CPU-Merkmale auf Windows, ehrliche Fehler:
|
||
- **Hardware-Erkennung war MEIN Bug:** `leite_backends_ab()` verlangte
|
||
`/dev/dri` bzw. `nvidia-smi` — beides gibt es unter Windows nicht. Der PC des
|
||
Commanders meldete deshalb nur CPU, obwohl HandBrakes Windows-Build `vce_*`
|
||
kennt. Die Prüfung war zudem überflüssig: **HandBrake probiert Hardware selbst
|
||
an und listet nur Nutzbares** (auf der VM belegt: „qsv: not available", und
|
||
`qsv_*` fehlt dann in `--help`). Jetzt ist HandBrakes Liste die einzige
|
||
Auskunft, unterschieden nach Familie (`nvenc`/`qsv`/`vce`/`vaapi`) plus eigener
|
||
Kennung für Hardware-AV1.
|
||
- **Vektorbefehle unter Windows** über `IsProcessorFeaturePresent` (kernel32,
|
||
winnt.h) + CPU-Name aus der Registry. Auf dem Commander-PC gegengeprüft:
|
||
vorher „AMD64 Family 26 Model 68 / unbekannt", jetzt „AMD Ryzen 7 9700X /
|
||
avx512f". Damit verschwindet die AVX2-Warnung für diesen Worker von selbst.
|
||
- **`_erreichbarkeit_pruefen()`** unterscheidet jetzt „Pfad nicht erreichbar +
|
||
kein Mapping" (nennt `RIPPY_PATH_MAP` mit Beispiel), „Mapping greift nicht"
|
||
und „Ordner leer" — und prüft **beide** Pfade, nicht nur die Quelle. Jede
|
||
Meldung sagt ausdrücklich, dass die Rohdaten nicht verloren sind.
|
||
- Vier Platzhalter mit der Umgebung des Commanders (`192.168.178.20`,
|
||
`TOBIS-PC`, seine Jellyfin- und Rippy-IP) verallgemeinert.
|
||
|
||
**`fd1feaa`** — Ablage einstellbar + Kohärenz-Prüfung:
|
||
- Auswahlliste **„Ablage"** in Einstellungen → Ripping, gleiche Liste wie beim
|
||
Arbeitsverzeichnis. Wirkt automatisch in Vollautomatik und Schnellwahl, weil
|
||
beide `outputDir` lesen — genau wie vom Commander gefordert.
|
||
- **Warnung, sobald ein EXTERNER Worker gemeldet ist** und Ablage +
|
||
Arbeitsverzeichnis nicht beide auf einer erreichbaren Freigabe liegen. Drei
|
||
Fälle mit Konsequenz im Klartext (kann nicht lesen / kann nicht schreiben /
|
||
läuft, kostet aber eine Vollkopie).
|
||
- „Extern" ist keine Heuristik: `caps.py` meldet `extern` selbst (`/app` gibt es
|
||
im Rippy-Image immer, außerhalb nie) und zusätzlich `pfad_map`.
|
||
|
||
### OFFENE PUNKTE — nach Priorität, mit Kontext
|
||
|
||
**1. `RIPPY_PATH_MAP` setzen (DER BLOCKER).** Der Installer muss fragen „wie
|
||
erreicht dieser PC die Freigabe?" und den Wert in `start-tray.bat` /
|
||
`start-worker.bat` schreiben. Format laut `pfad_lokal()`:
|
||
`/app/media=\\NAS\rippy;/app/temp=…` (Paare per `;`, Präfix-Ersetzung, wandelt
|
||
`/` zu `\`, wenn das Ziel Backslashes enthält). Commander-Vorgabe dazu: *„Wenn
|
||
ein externes Ziel für den Speicher eingehängt ist, soll Rippy das ausgewählte als
|
||
Arbeitsziel verwenden … das muss auch für den Automatik-Modus so sein."* Punkt 2
|
||
oben erfüllt die Einstellungs-Seite davon; es fehlt die Worker-Seite.
|
||
Danach: Commander kann seinen 80-GB-Rohschnitt per „Neu komprimieren" auf dem
|
||
Ryzen laufen lassen.
|
||
|
||
**2. Preset-Liste vom Worker holen** — Voraussetzung für „immer das Beste".
|
||
Commander: *„Bei den Presets soll IMMER das Beste ausgewählt werden"* und *„wenn
|
||
der Worker AV1 oder noch besseres kann, immer diesem empfehlen, die Warnung
|
||
verschwindet oder wird von orange zu grün"*. Blocker: Die Namen der
|
||
HandBrake-**Hardware**-Presets sind auf der Rippy-VM **nicht ermittelbar** (deren
|
||
HandBrake hat keinen Hardware-Encoder), und Erfinden verstößt gegen AGENTS
|
||
Regel D — das Projekt hat das zweimal teuer bezahlt. Richtige Lösung: `caps.py`
|
||
meldet `HandBrakeCLI --preset-list` des jeweiligen Workers, das UI bietet genau
|
||
diese an. Beendet das Raten dauerhaft.
|
||
|
||
**3. Dashboard + ETA.** Commander: *„Der Server Status muss dringend überarbeitet
|
||
werden, das Dashboard soll ja quasi alles auf einen Blick zeigen"* — „Auslastung:
|
||
0 % (Aktiv)" ist nichtssagend. Dazu eine **ETA** im Dashboard und beim externen
|
||
Worker. Restzeit ist aus dem Fortschrittsverlauf schätzbar; ehrlich bleiben,
|
||
solange die Datenlage dünn ist. Verlässlichster Messpunkt (in dieser Sitzung
|
||
bewährt): Leseposition im Quellstrom über `/proc/<pid>/fdinfo/`.
|
||
|
||
**4. Datei-Browser aus dem Rip-Dialog.** Commander: *„Warum wird hier der Datei
|
||
Browser noch angezeigt — das ist doch quatsch"*. Prüfen, ob wirklich redundant
|
||
(darüber gibt es Schnellwahl + Arbeitsverzeichnis-Auswahl), dann raus oder
|
||
einklappen. Datei: `docker/ui/src/components/RipTargetModal.tsx`.
|
||
|
||
**5. Nicht-Debian-Hosts.** `install.sh` nennt bei fehlendem Compose nur
|
||
`sudo apt install docker-compose-plugin`; auf Arch/Fedora/openSUSE falsch.
|
||
Paketmanager erkennen. Klarstellen: der Worker-**Container** ist unabhängig vom
|
||
Host-System.
|
||
|
||
**6. Warnung im Rip-Dialog** (nicht nur in den Einstellungen), wenn der gewählte
|
||
externe Encoder die Pfade nicht erreicht — vor dem Start, nicht nach einer Stunde.
|
||
Bausteine liegen: `caps.py` meldet `extern` und `pfad_map`.
|
||
|
||
**7. Jikan-Reihenfolge prüfen** (Nebenbefund). Kette ist TMDB → **Jikan** → OMDb
|
||
mit Gate `MINDEST_AEHNLICHKEIT = 0.55`. Jikan wird also wirklich benutzt (Antwort
|
||
auf die Commander-Frage), läuft aber **vor** OMDb: bei einem Nicht-Anime, den
|
||
TMDB verpasst, antwortet zuerst eine Anime-Datenbank. 0,55 ist großzügig.
|
||
|
||
**8. Aus dem ARM-Vergleich, nicht gebaut:** ISO-Sicherung für Datenträger, die
|
||
weder Film noch Audio-CD sind (daran scheitert Rippy heute), und **mehrere
|
||
Laufwerke gleichzeitig** — Rippy sieht sie (`/dev/sr[0-9]*`), ob parallel gerippt
|
||
wird, ist **unbewiesen**.
|
||
|
||
**9. Ältere offene Punkte, unverändert gültig:**
|
||
- „Job aus der Liste entfernen" sagt nicht, wie viel daneben liegen bleibt — der
|
||
Rohschnitt verwaist unsichtbar (v3.14).
|
||
- Discord-Webhook und MakeMKV-Key liegen im Klartext in der settings-Tabelle.
|
||
- **VM-CPU-Typ steht auf `qemu64`** → `host` würde AVX2 freischalten, 2–4×
|
||
schneller. Anleitung steht in der README („Rippy schneller machen").
|
||
- **`install.sh` ist nie als root durchgelaufen** — Verzeichnisse anlegen,
|
||
`mount --make-rshared` und die systemd-Unit sind ungetestet.
|
||
- Zwei API-Tests laufen nur in der Ampel (`test_api_smoke.py` überspringt sich
|
||
unter Windows selbst).
|
||
|
||
### FALLEN, die diese Sitzung gekostet haben
|
||
|
||
- **Deutsche Anführungszeichen in DOPPELT gequoteten Python-Strings** beenden den
|
||
String vorzeitig. Dreimal hineingetappt. Der Bestand nutzt dafür **einfach**
|
||
gequotete f-Strings (`f'…„{x}"…'`). In dreifach gequoteten Docstrings ist es
|
||
unproblematisch.
|
||
- **In f-Strings steht in `{...}` CODE, kein Text.** Ein Umlaut-Konverter machte
|
||
aus `f"{groesse}"` ein `f"{größe}"`, während die Variable `groesse` hieß —
|
||
Ruff fand es als F821.
|
||
- **`docker exec` ohne `sh -c` expandiert kein `*`** — ein `du -sh /pfad/*`
|
||
liefert dann still nichts und sieht wie „leer" aus.
|
||
- **Eine `/proc`-Suche nach „HandBrake" trifft die eigene Shell mit**, weil deren
|
||
Kommandozeile das Wort enthält. Zwei Fehlalarme.
|
||
- **`pydantic-core` springt lokal wiederholt auf 2.47.0** und bricht damit das
|
||
Einsammeln ALLER API-Tests (`SystemError`). Fix:
|
||
`python -m pip install "pydantic-core==2.46.4"`. Zweimal nötig gewesen.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.15 — Aufräum-Runde: Tempo, tote Routen, 4K-Entscheidung (25.07.2026, 20:00)
|
||
|
||
> **Deployt und live gegengeprüft.** Auftrag war „bau alles so um, dass es
|
||
> sauber ist" mit fünf Vorgaben: saubere Codebase, selbsterklärendes UI,
|
||
> externe Worker, kein Laggen, idiotensicher. Was noch offen ist, steht unten.
|
||
|
||
### Das „Laggen" hatte genau eine Ursache — gemessen und behoben
|
||
|
||
Über alle 15 Endpunkte gemessen, die das UI beim Laden braucht:
|
||
|
||
| Endpunkt | vorher | nachher |
|
||
|---|---|---|
|
||
| `/capabilities` | **1,010 s** | **0,003 s** |
|
||
| `/system/updates` | 0,491 s | unverändert (hängt am Knopf) |
|
||
| `/metadata/status` | 0,412 s | unverändert (hängt am Knopf) |
|
||
| die anderen 12 | < 0,025 s | < 0,010 s |
|
||
|
||
Nur `/capabilities` schlug beim **Seitenaufbau** zu — und fünf Stellen holen
|
||
ihn (Dashboard, Einstellungen, Worker-Tab, Wizard, Rip-Dialog). Jede Seite
|
||
zahlte eine Sekunde. Ursache ist kein Fehler, sondern das Wesen des
|
||
Celery-Pings: er sammelt Antworten bis zum Timeout und kann nicht früher
|
||
aufhören. Den Timeout zu kürzen würde Antworten langsamer Remote-Worker
|
||
verschlucken — also genau die Maschinen, um die es beim externen Encoding geht.
|
||
Jetzt pingt eine Hintergrund-Schleife im 5-s-Takt, der Endpunkt liest ab. Ist
|
||
der Vorrat älter als 30 s, wird einmal synchron gepingt: lieber langsam als
|
||
falsch („alles offline", obwohl alles läuft). Kompletter Dashboard-Aufbau:
|
||
**1,03 s → 0,028 s.**
|
||
|
||
### 4K ist entschieden — Kompression je Disc-Typ abwählbar
|
||
|
||
Die offene Frage aus v3.14 ist gebaut. Bisher gab es nur `transcodeEnabled`:
|
||
alles oder nichts. Jetzt kann das Preset eines Disc-Typs auf den Reservewert
|
||
`keine` stehen → die verlustfreie Datei bleibt stehen. Damit ist die sinnvolle
|
||
Einstellung für diese Maschine erstmals möglich: **4K verlustfrei behalten,
|
||
DVD und Blu-ray weiter schrumpfen.**
|
||
|
||
`komprimieren_fuer()` ist die neue reine Funktion; `preset_fuer()` überspringt
|
||
den Reservewert bewusst und gibt ihn NIE als Preset-Namen zurück — sonst bekäme
|
||
HandBrake `--preset keine`. Gegengeprüft: keiner der 90 echten Presets aus
|
||
`--preset-list` heißt so, und die fünf im UI angebotenen Namen existieren alle.
|
||
|
||
### Der Wizard läuft nicht mehr in die 4K-Falle
|
||
|
||
Er hatte die Zahlen längst vorliegen (`/capabilities` meldet `cpu_simd` und
|
||
`cpu_kerne`) — benutzt hat er sie nicht und H.265 als Standard vorgeschlagen.
|
||
Auf einer CPU ohne AVX2 sind das ein bis zwei Tage pro 4K-Film.
|
||
|
||
Jetzt entscheidet die **gemessene** Leistung: schwache CPU → 4K nicht
|
||
komprimieren, Blu-ray/DVD auf H.264. Stark oder Hardware-Encoder → H.265
|
||
durchgehend. Und er schreibt **alle vier** Preset-Felder statt nur des
|
||
allgemeinen; vorher fiel 4K auf ein 1080p-Preset zurück.
|
||
|
||
Dazu gehärtet: Kasten „Was Rippy gerade sieht" (Laufwerk, Worker mit
|
||
Kernen/SIMD, freier Platz) — jede Zeile mit **Handlungsanweisung** statt nur
|
||
einem Kreuz. Lädt parallel und wiederholt im 5-s-Takt, weil der Worker beim
|
||
ersten Start noch hochläuft. API-Keys sind sichtbar statt Punkte (kopierte
|
||
Keys, keine Passwörter — Tippfehler sieht man in Punkten nicht) und werden
|
||
direkt nach dem Speichern geprüft, mit der Wahl „Key korrigieren" oder
|
||
„Trotzdem fertigstellen".
|
||
|
||
**Gewarnt wird nur, wenn es belegt ist:** `schwacheEncoderCpu()` verlangt
|
||
mindestens einen Worker mit BEKANNTER SIMD-Stufe und keinen mit
|
||
Hardware-Encoder. Ein Windows-Worker meldet `unbekannt` (kein `/proc/cpuinfo`)
|
||
→ dann wird geschwiegen statt falsch gewarnt.
|
||
|
||
### Vier tote Routen raus
|
||
|
||
`POST /prescan`, `POST /jellyfin/format` (+ `nfo_generator.py` und
|
||
`image_downloader.py`, die sonst nichts nutzte), `GET /stream/jobs`,
|
||
`GET /worker-setup/windows-gui`. Jede ein Überrest eines ersetzten Entwurfs,
|
||
keine mit Aufrufer. `main.py`: 1726 → 1682 Zeilen, dazu 279 Zeilen in zwei
|
||
gelöschten Modulen. Tests halten beide Seiten fest: die vier müssen WEG
|
||
bleiben, die drei für die Worker-Installation (`/worker-setup/paket`,
|
||
`/windows`, `/windows-exe`) müssen DA sein.
|
||
|
||
### Externe Worker — vorbereitet, vom Commander zu testen
|
||
|
||
Auf **Windows gegengeprüft** (dieser PC): `cpu_kerne` 16 und CPU-Modell kommen
|
||
korrekt durch, `encoders` ist ohne installiertes HandBrake korrekt **leer**,
|
||
`cpu_simd` ehrlich `unbekannt` → keine falsche Warnung. Ein GPU-Worker braucht
|
||
ein HandBrake-Build mit `nvenc_*`/`qsv_*`; die neue Anzeige nennt die
|
||
ungefilterte HandBrake-Auskunft, damit das nachprüfbar ist.
|
||
|
||
### ARM-Vergleich (Vorbild-Projekt)
|
||
|
||
Fast alles, was ARM automatisch macht, macht Rippy schon — und meist
|
||
gründlicher: Metadaten aus drei Quellen statt nur OMDb, Episoden-Erkennung per
|
||
Laufzeitabgleich, Kompression auf eine eigene Queue routbar. Bezeichnend:
|
||
ARMs Auto-Auswurf war bei Rippy nur **behauptet** und ist erst in v3.14 echt
|
||
geworden. Zwei Lücken bleiben, beide **nicht gebaut, als Vorschlag**:
|
||
- **ISO-Sicherung** für Datenträger, die weder Film noch Audio-CD sind — daran
|
||
scheitert Rippy heute.
|
||
- **Mehrere Laufwerke gleichzeitig.** Rippy sieht sie (`/dev/sr[0-9]*`), ob
|
||
parallel gerippt wird, ist **unbewiesen** — mit einem Laufwerk nicht testbar.
|
||
|
||
### Installation: ein Befehl statt Checkliste (`install.sh`)
|
||
|
||
Commander-Rückmeldung: „Das Docker Deployment ist mir zu kompliziert." Zu
|
||
Recht — es war eine Sechs-Schritte-Checkliste, von der zwei Punkte Fachwissen
|
||
verlangten. Jetzt:
|
||
|
||
```bash
|
||
git clone <repo-url> rippy && cd rippy
|
||
sudo ./install.sh
|
||
```
|
||
|
||
Der schlimmste Punkt war das **Laufwerk**: MakeMKV braucht ZWEI Geräteknoten,
|
||
und die sg-Nummer ist je Host anders. Das Skript gleicht sie über die
|
||
SCSI-Adresse in `/sys` ab statt zu raten — auf der VM gegengeprüft
|
||
(`sr0 → 3:0:0:0`, `sg1 → 3:0:0:0` = dasselbe Gerät, korrekt erkannt). Dazu:
|
||
Verzeichnisse, Mount-Propagation **inklusive neustart-fester systemd-Unit**
|
||
(vorher stand in der README nur „reboot-fest persistieren", ohne zu sagen wie —
|
||
nach einem Reboot scheiterte das NAS-Einhängen aus dem UI stillschweigend),
|
||
`.env` schreiben ohne Bestehendes zu überschreiben, bauen, starten.
|
||
`./install.sh --nur-pruefen` sieht nur nach. Wiederholbar, damit auch der
|
||
Update-Weg: `git pull && sudo ./install.sh`.
|
||
|
||
**Zwei Fallgruben fielen beim Testen auf, beide meine eigenen:**
|
||
- `--nur-pruefen` verlangte root und brach ab — ein Prüf-Modus, der nichts
|
||
ändert, darf daran nicht scheitern.
|
||
- `.env.example` hatte `OPTICAL_SG=/dev/sg1` **unkommentiert** vorbelegt. Der
|
||
Installer hätte den erkannten Wert deshalb nicht eingetragen („steht schon
|
||
drin") und auf jedem fremden Host still eine kaputte Konfiguration
|
||
hinterlassen — genau das, was er verhindern soll. Beide Gerätezeilen sind
|
||
jetzt auskommentiert (Compose hat ohnehin Vorgaben), plus eine Gegenprobe:
|
||
zeigt ein wirksamer Wert auf ein Gerät, das es hier nicht gibt („`.env` von
|
||
einem anderen Rechner"), wird das benannt statt kryptisch von Docker gemeldet.
|
||
|
||
Die `.env`-Logik ist in drei Fällen auf der VM geprüft: frische Datei bekommt
|
||
den erkannten Wert, ein selbst gesetzter Wert bleibt unangetastet, zweimal
|
||
ausführen erzeugt genau eine Zeile.
|
||
|
||
### README neu aufgebaut
|
||
|
||
Vorher 293 Zeilen, in denen der Schnellstart zwischen `lsscsi`, sg-Knoten,
|
||
USB-Passthrough und `mount --make-rshared` begraben war. Jetzt: Installation in
|
||
zwei Zeilen oben, dann die Tabelle „Wenn etwas nicht geht" mit den vier Fällen,
|
||
die praktisch alles abdecken. Alles Technische darunter in aufklappbaren
|
||
Abschnitten, inklusive der Handarbeits-Variante.
|
||
|
||
**Neu und ausdrücklich gewünscht: „Rippy schneller machen"** — der VM-CPU-Typ.
|
||
Warum Virtualisierer eine generische CPU ohne AVX2 geben, was das kostet
|
||
(gemessene 28–55 h je 4K-Film), die genauen Proxmox-Schritte (herunterfahren →
|
||
Hardware → Processors → Type auf `host` → starten, bzw. `qm set <vmid> --cpu
|
||
host`), **warum ein Neustart von innen nicht genügt**, und wie man nachprüft:
|
||
Rippy zeigt die Vektorbefehle selbst an. Dazu der Nachteil (keine
|
||
Live-Migration auf andere CPUs) und die Alternative `x86-64-v3` für Cluster.
|
||
|
||
### Der MakeMKV-„Fallback" auf der VM war seit Monaten tot
|
||
|
||
Beim Aufräumen der VM-`.env` aufgefallen und nachgemessen (25.07.2026):
|
||
|
||
| Quelle | Antwort |
|
||
|---|---|
|
||
| `https://www.makemkv.com/download` (Repo-Standard) | **HTTP 200** |
|
||
| `https://www.makemkv.com/download/old` | HTTP 525 (Cloudflare) |
|
||
| web.archive.org-Schnappschuss **aus der VM-`.env`** | **HTTP 404** |
|
||
|
||
Die VM zeigte also auf eine **kaputte** Adresse. Aufgefallen ist es nie, weil
|
||
dort die `vendor/`-Tarballs liegen und der Download-Zweig gar nicht erreicht
|
||
wird. Nimm die Tarballs weg, und jeder Bau scheitert mit 404 — während die
|
||
Konfiguration gesund aussieht. Genau diese Sorte Fehler ist bei einer Übergabe
|
||
teuer.
|
||
|
||
**Bereinigt** (Sicherung liegt als `.env.sicherung-vor-aufraeumen-20260725`):
|
||
`MAKEMKV_URL_BASE` raus → es gilt der Standard, der liefert. `JWT_SECRET_KEY`
|
||
raus → Überrest der in v3.4 ausgebauten Anmeldung, wirkungslos.
|
||
|
||
**Gebaut — Rückfall dreistufig und ehrlich:** `vendor/`-Tarballs →
|
||
`MAKEMKV_URL_BASE` → `MAKEMKV_URL_FALLBACK` (neu, wird automatisch versucht).
|
||
Der Fallback ist **absichtlich leer vorbelegt**: Es gibt derzeit keine belegbare
|
||
zweite Quelle, und eine einzutragen, die nicht liefert, wäre schlimmer als
|
||
keine — siehe oben. Scheitert alles, nennt die Fehlermeldung jetzt die beiden
|
||
Wege, die funktionieren (Tarballs nach `vendor/`, oder eigene Quelle als
|
||
`MAKEMKV_URL_FALLBACK`), statt nur einen curl-Rückgabewert zu hinterlassen.
|
||
|
||
### NOCH OFFEN
|
||
|
||
1. **Externe Worker im Praxistest** (Commander).
|
||
2. **ISO-Sicherung und Mehr-Laufwerk-Betrieb** — siehe ARM-Vergleich.
|
||
3. **„Job aus der Liste entfernen" sagt nicht, wie viel daneben liegen bleibt**
|
||
(v3.14). Der Rohschnitt verwaist dabei unsichtbar.
|
||
4. **Discord-Webhook und MakeMKV-Key liegen im Klartext** in der
|
||
settings-Tabelle. Für Heimnetz erwartbar, aber der Webhook ist eine echte
|
||
Zugangsberechtigung.
|
||
5. **Der VM-CPU-Typ steht auf `qemu64`.** `host` würde AVX2 freischalten und
|
||
jeden Software-Encode 2–4× beschleunigen. Ein VM-Neustart, nicht gemacht —
|
||
**die Anleitung steht jetzt in der README** („Rippy schneller machen").
|
||
6. **`install.sh` ist nie als root durchgelaufen.** Auf dieser VM sind alle
|
||
root-Schritte No-Ops (Verzeichnisse da, Propagation schon `shared`), und
|
||
`sudo` verlangt hier ein Passwort. Bewiesen sind Laufwerkserkennung,
|
||
`.env`-Logik (drei Fälle) und Syntax; **ungetestet bleiben das Anlegen der
|
||
Verzeichnisse, `mount --make-rshared` und die systemd-Unit** — die laufen
|
||
erst bei einer echten Neuinstallation.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.14 — Durchsicht: vier Placebos und ein unwirksamer Schutz (25.07.2026, 18:40)
|
||
|
||
> **Stand 19:30: alles committet, Ampel grün (`a1aabd5`), DEPLOYT und live
|
||
> gegengeprüft.** Der Akira-Encode wurde um 18:31 abgebrochen (Nachtrag im
|
||
> Block darunter), danach der Job aus der Liste gelöscht und die Rohdaten
|
||
> entsorgt. Es läuft nichts, die Platte hat **111 GB frei**.
|
||
> Was noch zu entscheiden ist, steht unten unter „NOCH OFFEN".
|
||
|
||
### DER WICHTIGSTE FUND: der Platten-Schutz aus `c065967` greift nicht
|
||
|
||
`_original_aufheben()` entschied per `os.stat().st_dev`, ob umgehängt oder
|
||
kopiert werden muss. Auf der VM gemessen — **beides gleichzeitig wahr**:
|
||
|
||
```
|
||
st_dev /app/temp = 2050
|
||
st_dev /app/media = 2050 → identisch
|
||
os.rename(...) → EXDEV, "Invalid cross-device link"
|
||
```
|
||
|
||
Der Kernel vergleicht bei `rename()` den **Mount**, nicht das Gerät.
|
||
`/app/temp` (Docker-Volume) und `/app/media` (Bind-Mount) sind zwei Mounts
|
||
DERSELBEN ext4-Partition. Die Prüfung sah deshalb „gleiches Dateisystem",
|
||
**übersprang die Platzprüfung**, und `shutil.move` kopierte doch — 75 GB bei
|
||
37 GB frei. Der Schutz hätte genau den Schaden zugelassen, gegen den er
|
||
gebaut wurde.
|
||
|
||
**Behoben:** `os.rename` wird jetzt VERSUCHT statt vorhergesagt. Klappt es,
|
||
ist es umgehängt. Kommt EXDEV, steht die Kopie fest — und erst dann wird der
|
||
Platz geprüft. Vier Tests dazu (`test_original_aufheben.py`), inklusive des
|
||
Falls, der die Platte füllte.
|
||
|
||
### GEMESSEN, Stand 18:30 (alles per Befehl auf der VM geprüft)
|
||
|
||
- **Container:** alle 5 `Up`, api/postgres/redis `healthy`. api/ui/worker seit
|
||
18:00:39 (Deploy von `8bb075c`), postgres/redis älter.
|
||
- **Platte:** 148 G, 105 G belegt, 37 G frei = 75 G Rohschnitt + 4,9 G Medien
|
||
(Evangelion) + ~25 G System. **Keine Kopier-Reste**, kein `original`-Ordner.
|
||
- **Akira-Job:** `failed`, „Abgebrochen durch Nutzer" (Abbruch 18:30:17
|
||
angefordert, Worker bestätigt 18:33:38 → **3,4 Minuten Verzug**, siehe unten).
|
||
Es läuft **kein** HandBrake mehr (per `/proc` geprüft, Stand 19:06).
|
||
- **Der Encode war bei 1,44 %**, gemessen an der Leseposition im Quellstrom
|
||
(`/proc/<pid>/fdinfo/3`: 1.145.940.149 von 79.604.951.639 Bytes) — exakter
|
||
als jede Fortschrittsanzeige. Zwei Tempo-Fenster ergaben 395 und 784 KB/s
|
||
→ **28–55 h** für den Film, bei 3,84 von 4 gesättigten Kernen.
|
||
- **Achtung bei Prozess-Suchen per `/proc`:** Ein `case "$c" in *HandBrake*)`
|
||
trifft die eigene Shell mit, weil deren Kommandozeile das Wort enthält. Zwei
|
||
Fehlalarme in dieser Sitzung. Immer die PID gegenprüfen.
|
||
- **Die Ursache dafür ist neu und behebbar:** Die VM läuft auf dem generischen
|
||
QEMU-CPU-Modell (`QEMU Virtual CPU version 2.5+`), `grep -c avx2
|
||
/proc/cpuinfo` = **0**, nur bis `sse4_2`. x265 lebt von AVX2. Abhilfe:
|
||
CPU-Typ von VM 106 in Proxmox auf `host` stellen (braucht VM-Neustart).
|
||
- **HandBrake im Worker-Image kann:** `svt_av1`, `x264`, `x265` (je 10/12-bit),
|
||
`mpeg4/2`, `VP8/9`, `theora` — und **keinen einzigen Hardware-Encoder**.
|
||
- **Ampel grün** für `b526a0a` und `8bb075c` (Gitea-API abgefragt).
|
||
|
||
### GEBAUT — vier Placebos entfernt bzw. echt gemacht
|
||
|
||
1. **Fortschritt log statt Wahrheit.** `get_progress_from_line` matchte jede
|
||
Zahl vor einem `%` — also auch HandBrakes **Scan-Durchlauf**, der VOR dem
|
||
Encodieren bis 100 % hochläuft. Dazu warf `if progress > 0` alle echten
|
||
Werte unter 1,00 % weg. Ergebnis: Anzeige klebte stundenlang auf 99 %.
|
||
Jetzt wird nur die `Encoding:`-Zeile gelesen, `task N of M` mitgerechnet,
|
||
und **-1 heißt „keine Angabe"** (Muster von `get_progress_from_prgv`).
|
||
Formatstrings aus dem Binary gelesen, nicht geraten.
|
||
**⚠️ Richtigstellung zu v3.13:** Dort steht, `progress=99` sei ein „Altwert
|
||
aus dem Absturz". Falsch — beide Startpfade setzen auf 0, der Wert war
|
||
frisch vom Scan-Durchlauf geschrieben. Es war ein Bug, kein Überrest.
|
||
2. **„Automatischer Auswurf" tat nichts.** Die Einstellung (Standard: ein)
|
||
wurde von niemandem gelesen: DVD/Blu-ray warfen **nie** aus, Audio-CDs
|
||
**immer**, weil abcde `-x` fest verdrahtet bekam. Jetzt entscheidet die
|
||
Einstellung beides (`wirf_disc_aus()` per CDROMEJECT-ioctl, Linux-guarded).
|
||
3. **„Alle Tracks rippen" konnte nichts bewirken** — abcde bekommt keine
|
||
Track-Auswahl und es gibt keine Oberfläche dafür. Schalter entfernt, an
|
||
seiner Stelle steht jetzt die Wahrheit („wird immer vollständig gerippt").
|
||
4. **Encoder-Auslese behauptete statt zu messen.** `cpu-x264`/`cpu-x265`
|
||
standen fest verdrahtet drin („immer dabei") — ein Rip-Worker **ohne**
|
||
HandBrake behauptete damit, komprimieren zu können. Und `vaapi` wurde
|
||
allein wegen `/dev/dri` gemeldet, ohne zu prüfen, ob HandBrake das kann
|
||
(dieses Image kann es nicht). Jetzt aus `HandBrakeCLI --help` geparst, plus
|
||
**CPU-Modell, Kernzahl und Vektorbefehlsstufe** je Worker — mit sichtbarer
|
||
Warnung im UI, wenn AVX2 fehlt. Genau die Angabe, deren Fehlen den
|
||
55-Stunden-Encode unsichtbar machte.
|
||
|
||
### GEBAUT — Zombie-Erkennung (v3.13 Punkt 2 abgearbeitet)
|
||
|
||
`zombies.py`: Beim Worker-Start werden Jobs, die auf `ripping`/`transcoding`/
|
||
`canceling` stehen, gegen Celerys `active`/`reserved`/`scheduled` gehalten und
|
||
ehrlich auf `failed` gesetzt, wenn niemand daran arbeitet. Drei Sicherungen,
|
||
weil ein falsch getöteter Job teurer ist als eine stehende Leiche:
|
||
|
||
- **nur beim Start** (da ist „es lief nichts" eindeutig),
|
||
- **120 s Gnadenfrist** (Celery stellt unbestätigte Aufgaben erneut zu),
|
||
- **Vollzähligkeit**: antworten weniger Knoten als laut Herzschlag online
|
||
sind, wird NICHTS gewertet — sonst wäre der laufende Job eines
|
||
beschäftigten Remote-Workers eine falsche Leiche.
|
||
|
||
13 Tests, unter anderem: „laufender Job wird nicht angetastet" und
|
||
„schweigender Worker verhindert jedes Urteil".
|
||
|
||
### GEBAUT — Pfad-Prüfung gehärtet
|
||
|
||
Elf Stellen prüften mit nacktem `startswith(MEDIA_ROOT)`. `/app/media-boese/x`
|
||
beginnt mit `/app/media`, liegt aber außerhalb — betroffen waren auch `/browse`
|
||
und `/browse/mkdir`, wo der Pfad vom Nutzer kommt. Neuer Zwillings-Helfer
|
||
`unter_wurzel()` in `api/main.py` und `worker/tasks.py`, alle elf Stellen
|
||
umgestellt, Tests in beiden.
|
||
|
||
Nebenbefund dabei: `_zielbasis()` benutzte `os.path.normpath` — unter Windows
|
||
werden daraus Backslashes und die Prüfung greift nicht mehr; das gewählte Ziel
|
||
wäre still auf den Standard zurückgefallen. Genau die Falle, die
|
||
`_arbeitsverzeichnis()` drei Zeilen weiter dokumentiert und mit `posixpath`
|
||
vermeidet. Live war es nie (nur aus `rip_disc`, das auf Windows verriegelt
|
||
ist), jetzt konsistent.
|
||
|
||
### GEFUNDEN, NICHT ANGETASTET — vier tote Endpunkte
|
||
|
||
Nirgends im UI referenziert (mechanisch gegengeprüft: alle `api.*`-Aufrufe
|
||
gegen alle Routen):
|
||
|
||
| Endpunkt | Lage |
|
||
|---|---|
|
||
| `POST /jellyfin/format` | ersetzt durch `medien.py` im Worker; zieht `nfo_generator.py` + `image_downloader.py` in der API mit, die sonst niemand nutzt |
|
||
| `POST /prescan` | ohne Aufrufer (die `PreScan`-Klasse selbst wird woanders sehr wohl gebraucht) |
|
||
| `GET /stream/jobs` | niemand konsumiert ihn; der Kommentar behauptet einen „Fix 23.07.", der ihn funktionsfähig machte — gebraucht wird er trotzdem nicht |
|
||
| `GET /worker-setup/windows-gui` | seit der `.exe` (v3.9) unreferenziert |
|
||
|
||
Bewusst nicht entfernt: `test_api_smoke.py` prüft `/prescan` als verdrahtete
|
||
Route, und Entfernen ist eine Entscheidung, keine Reparatur. **Der Commander
|
||
entscheidet.**
|
||
|
||
### NOCH OFFEN / EHRLICH UNGEKLÄRT
|
||
|
||
- **Was die Platte am 25.07. mittags füllte, ist nicht belegt.** Es gibt keine
|
||
Kopier-Reste, kein `original`-Verzeichnis und **keinen einzigen Log-Eintrag
|
||
von `_original_aufheben`** — das loggt in beiden Zweigen. Zwischen 10:21:50
|
||
und 17:49 steht überhaupt nichts im Log. Der EXDEV-Mechanismus ist jetzt
|
||
belegt (siehe oben), dass er DAMALS zuschlug, ist es nicht.
|
||
- **`tracks:/dev/sr0` meldet `{"status":"done","tracks":[]}`** — null Titel für
|
||
eine Disc, die MakeMKV mit `TCOUNT:5` öffnet. Nicht weiter verfolgt.
|
||
- **Der Discord-Webhook und der MakeMKV-Key liegen im Klartext** in der
|
||
settings-Tabelle. Für Heimnetz erwartbar, aber der Webhook ist eine echte
|
||
Zugangsberechtigung.
|
||
- **Zwei neue API-Tests laufen nur in der Ampel** — `test_api_smoke.py`
|
||
überspringt sich unter Windows selbst (`main.py` braucht `fcntl`).
|
||
|
||
### GEBAUT — „Abbrechen" wirkt jetzt sofort
|
||
|
||
Der Fund aus dem Nachtrag (Commander, am laufenden Job beobachtet) ist behoben.
|
||
Ursache war genau wie dort beschrieben: Der Abbruch wurde nur in
|
||
`datei_fortschritt` geprüft, und diese Closure stieg oben sofort wieder aus,
|
||
wenn sich die Prozentzahl nicht geändert hatte. Bei einem Prozent je halber
|
||
Stunde sah „Abbrechen" entsprechend lange wirkungslos aus.
|
||
|
||
Jetzt gibt es in `run_handbrake` einen **eigenen Abbruch-Kanal** neben dem
|
||
Fortschritts-Callback — dasselbe Muster, das `run_makemkv` schon für `log_cb`
|
||
benutzt, und aus demselben Grund. Er wird bei JEDER Ausgabezeile aufgerufen
|
||
und ist im Worker auf 5 Sekunden gedrosselt (`ABBRUCH_INTERVALL_SEKUNDEN`).
|
||
Nebeneffekt: Er greift auch während des Scan-Durchlaufs, der überhaupt keine
|
||
Encode-Prozente liefert — dort war ein Abbruch vorher grundsätzlich unmöglich.
|
||
Die Leseschleife ist als `_handbrake_schleife()` herausgezogen, damit die
|
||
Reihenfolge (Abbruch VOR Fortschritt) ohne echtes HandBrake testbar ist.
|
||
|
||
### ERLEDIGT UM 19:30 — deployt und live gegengeprüft
|
||
|
||
`a1aabd5` läuft auf der VM. Belege, nicht Behauptungen:
|
||
|
||
- **Container:** alle 5 up, api/postgres/redis `healthy`.
|
||
- **Die neue Auslese antwortet ehrlich** (`GET /capabilities`):
|
||
`cpu-x264, cpu-x265, cpu-av1` — **kein Phantom-`vaapi`** mehr, obwohl die
|
||
alte Fassung es bei vorhandenem `/dev/dri` gemeldet hätte. Dazu
|
||
`cpu_modell: QEMU Virtual CPU version 2.5+`, `cpu_kerne: 4`,
|
||
`cpu_simd: sse4_2` → die AVX2-Warnung im UI greift.
|
||
- **Zombie-Erkennung:** 19:26:09, exakt 120 s nach Worker-Start,
|
||
`{'geprueft': 0, 'aufgeraeumt': []}` — nachgesehen, nichts in Arbeit
|
||
gefunden, korrekt nichts angetastet.
|
||
- **604 Disc-Schlüssel** haben den Rebuild überlebt.
|
||
- **Aufgeräumt:** das unbrauchbare 4K-Fragment (67.633.152 B) gelöscht; der
|
||
Akira-Job wurde um 19:07 aus der Liste entfernt, wodurch der 75-GB-Rohschnitt
|
||
verwaiste (kein Job-Datensatz zeigte mehr darauf, im UI unsichtbar,
|
||
„Neu komprimieren" unmöglich) — auf Entscheid des Commanders gelöscht, samt
|
||
vier leerer Alt-Ordner. **Platte: 37 GB → 111 GB frei.**
|
||
|
||
⚠️ **Merken für die Job-Verwaltung:** „Job aus der Liste entfernen" löscht
|
||
bewusst keine Dateien — das ist richtig, macht die Rohdaten aber unerreichbar,
|
||
weil beides nur über die Job-ID verbunden ist. Ein Rohschnitt ohne Job-Zeile
|
||
taucht nirgends mehr auf. Das UI sollte beim Löschen sagen, wie viel daneben
|
||
liegen bleibt. Nicht gebaut.
|
||
|
||
### NOCH OFFEN
|
||
|
||
**1. Die UHD-Strategie** (aus dem Nachtrag, unverändert gültig).
|
||
Preset-je-Disc-Typ war richtig, reicht aber nicht: Software-HEVC in 4K ist auf
|
||
dieser CPU keine Option. Drei Wege, keiner davon gebaut:
|
||
- **UHD gar nicht komprimieren** — Roh-MKV behalten. Ehrlichste Variante,
|
||
kostet Platz (75–100 GB je Film, gehört dann auf die NAS).
|
||
- **Hardware-Encoder** — Remote-Worker mit GPU (`nvenc`/`vaapi`). Rippy kann
|
||
das schon routen (bewiesen v3.7); es fehlt die Maschine. Achtung: Das
|
||
Worker-Image kann selbst keinen Hardware-Encoder, ein GPU-Worker braucht ein
|
||
HandBrake-Build mit `nvenc_*`/`qsv_*` — die neue Anzeige sagt das jetzt.
|
||
- **CPU-Typ der VM auf `host`** — schaltet AVX2 frei, bringt bei x265 typisch
|
||
Faktor 2–4. Aus 28–55 h werden damit aber immer noch Stunden bis Tage; das
|
||
allein löst 4K nicht, hilft aber jedem 1080p-Encode.
|
||
|
||
**2. Vier tote Endpunkte** — entfernen oder behalten (Tabelle oben). Alle vier
|
||
sind Überreste eines ersetzten Entwurfs: `/jellyfin/format` (die Arbeit macht
|
||
seit v3.2 `medien.py` im Worker), `/prescan` (Metadaten-Seite ist seit v3.4
|
||
weg; die `PreScan`-Klasse selbst wird sehr wohl gebraucht), `/stream/jobs`
|
||
(kein `EventSource` im UI — das Dashboard pollt `setInterval(…, 4000)`) und
|
||
`/worker-setup/windows-gui` (seit der `.exe` in v3.9 ohne Aufrufer; die Datei
|
||
steckt weiter in der `.exe`). **`/stream/jobs` ist der unangenehmste:** keine
|
||
harmlose Leiche, sondern eine Endlosschleife je Verbindung, die jeder erreichen
|
||
kann. Empfehlung: alle vier raus, plus `nfo_generator.py` und
|
||
`image_downloader.py` in der API (nutzt sonst nichts) — und `test_api_smoke.py`
|
||
prüft `/prescan` als verdrahtete Route, der Test muss also mit.
|
||
|
||
**3. Akira liegt jetzt gar nicht mehr vor.** Fragment und Rohschnitt sind
|
||
gelöscht (siehe oben). Wer den Film will, legt die Disc neu ein — der
|
||
Schlüsselspeicher steht (604 Schlüssel), der Rip dauert rund eine Stunde. Vor
|
||
dem nächsten UHD-Versuch aber Punkt 1 entscheiden, sonst läuft dasselbe
|
||
50-Stunden-Rennen wieder an.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.13 — ÜBERGABE (25.07.2026, 18:05)
|
||
|
||
> Dieser Block ist eine Übergabe an die nächste Sitzung. Er trennt bewusst
|
||
> **gemessen** von **vermutet** — in dieser Sitzung wurden zwei Behauptungen
|
||
> aufgestellt, die sich als falsch erwiesen (siehe „Vertrauensnotiz" unten).
|
||
> Im Zweifel: selbst nachmessen, nicht diesem Dokument glauben.
|
||
|
||
### GEMESSEN, Stand 18:05 (alles per Befehl auf der VM geprüft)
|
||
|
||
- **Container:** api/postgres/redis/ui/worker alle `Up`, api + postgres +
|
||
redis `healthy`.
|
||
- **Platte:** `/dev/sda2` 148 G, 105 G belegt, **37 G frei** (75 %).
|
||
- **Läuft gerade:** `HandBrakeCLI --input
|
||
/app/temp/raw/73b89777-…/title_t00.mkv --output
|
||
"/app/media/movies/Akira (1988)/title_t00.mkv" --preset
|
||
"H.265 MKV 2160p60 4K" --all-audio --all-subtitles`
|
||
- **Job `73b89777-a808-426f-8159-d406d27d0ec8`:** `status='transcoding'`,
|
||
`progress=99` (⚠️ **Altwert aus dem Absturz, NICHT der echte Fortschritt** —
|
||
der Lauf hat um 18:02 begonnen), `disc_type='uhd'`,
|
||
`output_path='/app/media/movies/Akira (1988)'`.
|
||
- **Dateien:** `…/Akira (1988)/title_t00.mkv` ist **0 Bytes** (HandBrake hat
|
||
die vorherige 1080p-Fassung beim Start gekürzt und schreibt gerade neu).
|
||
Roh-Rip `/app/temp/raw/73b89777-…/` = **75 GB, unversehrt.**
|
||
- **Git:** `8bb075c` ist HEAD und deployt. Davor `c065967`, `e84afc1`,
|
||
`f449c4e`, `0935766`. Alle Ampeln waren grün.
|
||
- **Schlüsselspeicher:** 604 Disc-Schlüssel, `/system/keystore` antwortet.
|
||
- **NAS:** `//192.168.178.62/rippy` auf `/srv/rippy/media/rippy` gemountet,
|
||
erreichbar, **2311 GB frei**. Wird als Ablageziel gelistet.
|
||
|
||
### NACHTRAG 18:35 — der 4K-Lauf wurde abgebrochen, zwei neue Befunde
|
||
|
||
- **4K-HEVC ist auf dieser CPU nicht machbar.** Gemessen: von 18:02 bis 18:31
|
||
kam der Lauf von 0 auf **1 %** → hochgerechnet **~50 Stunden** für den Film.
|
||
Der Commander hat um 18:31 abgebrochen. **Konsequenz, die noch zu
|
||
entscheiden ist:** entweder UHD gar nicht komprimieren (Roh-MKV behalten,
|
||
`transcodeEnabled` für UHD aus), oder ein Hardware-Encoder (Remote-Worker
|
||
mit GPU, `nvenc`/`vaapi`), oder bewusst bei 1080p bleiben. Das eben
|
||
gebaute Preset-je-Disc-Typ ist damit richtig, aber allein nicht genug.
|
||
- **Abbruch wirkt verzögert (FEHLER, nicht gebaut).** Job steht seit 18:31 auf
|
||
`canceling`, **HandBrake lief um 18:35 immer noch**. Ursache: Der Abbruch
|
||
wird nur in `datei_fortschritt` geprüft, und diese Closure läuft nur, wenn
|
||
sich die PROZENTZAHL ändert (`tasks.py`, `if gesamt == letzter[0]: return`).
|
||
Bei 1 % alle 30 Minuten heißt das: bis zu eine halbe Stunde, in der
|
||
„Abbrechen" für den Nutzer wirkungslos aussieht. Der Abbruch muss unabhängig
|
||
vom Fortschritt geprüft werden (z. B. zeitgesteuert beim Lesen der
|
||
HandBrake-Ausgabe).
|
||
- **Die 1080p-Fassung ist weg.** HandBrake hat sie beim Start auf 0 Bytes
|
||
gekürzt; aktuell liegen dort ~64 MB 4K-Fragment. Der **75-GB-Rohschnitt ist
|
||
unversehrt** — es ist also nichts unwiederbringlich verloren, aber im
|
||
Akira-Ordner liegt gerade eine unbrauchbare Datei.
|
||
|
||
### WAS ALS NÄCHSTES ANSTEHT
|
||
|
||
1. **Ausgang des 4K-Laufs prüfen.** Erwartung, die noch NICHT bewiesen ist:
|
||
Der Job endet **erfolgreich**, und „Original behalten" (Setting steht auf
|
||
`true`) meldet nur eine **Warnung**, weil 75 GB nicht neben 37 GB freien
|
||
Platz passen. Genau dieser Pfad ist neu (`_original_aufheben` in
|
||
`tasks.py`) und in der Praxis noch nie gelaufen. Wenn er hält, ist der
|
||
Ausfall von heute Mittag strukturell behoben.
|
||
2. **Zombie-Erkennung fehlt (gefunden, NICHT gebaut).** Nach dem Absturz stand
|
||
der Job auf `transcoding 96 %`, obwohl weder ein Prozess lief noch etwas in
|
||
den Celery-Queues stand (beide `llen` = 0). Folge: keine Anzeige, kein
|
||
Download, und der „Neu komprimieren"-Knopf fehlt, weil
|
||
`_kann_neu_komprimieren` (main.py) `status == "failed"` verlangt. Der
|
||
Worker sollte beim Start solche Leichen erkennen und ehrlich auf `failed`
|
||
setzen.
|
||
3. **`keepOriginal` steht auf `true`** — von dieser Sitzung gesetzt, um den
|
||
4K-Rohschnitt zu retten. Bewusst entscheiden, ob das so bleibt: mit
|
||
Arbeitsverzeichnis auf der NAS-Freigabe wäre es ein reines Umhängen statt
|
||
einer Vollkopie.
|
||
4. **75 GB Rohschnitt** liegen weiter in `/app/temp/raw/73b89777-…`. Nach
|
||
erfolgreichem 4K-Lauf entscheiden, ob er weg kann.
|
||
|
||
### VERTRAUENSNOTIZ — zwei Fehlschlüsse dieser Sitzung
|
||
|
||
- **„MakeMKVs Schlüssel-Kanal ist abgeschaltet"** — falsch. Stützte sich auf
|
||
zwei tote Hostnamen aus alten Forumsbeiträgen, die MakeMKV längst nicht mehr
|
||
benutzt. Richtig: `makemkvcon` unter **Linux** fragt nie, die
|
||
**Windows**-Version schon. Korrigiert in v3.11.
|
||
- **„Celery hat die Aufgabe nach dem Deploy erneut zugestellt"** — falsch.
|
||
Aus dem Status `transcoding` geraten, ohne Prozesse oder Queues zu prüfen.
|
||
Es war ein Zombie-Eintrag (Punkt 2 oben).
|
||
|
||
Beide Male war das Muster dasselbe: **aus einem Zustandswert auf einen
|
||
Mechanismus geschlossen, statt den Mechanismus zu messen.**
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.12 — Preset je Disc-Typ (25.07.2026)
|
||
|
||
- **Der Fund:** Beim ersten echten UHD-Rip aufgefallen — die Kompression
|
||
fragte den Disc-Typ **gar nicht**: `preset = einstellungen.get(
|
||
"transcodePreset")`, ein globales Preset für alles. Live eingestellt war
|
||
`HQ 1080p30 Surround`. Der laufende Akira-Rip wäre also verlustfrei in 4K
|
||
gerippt und danach **auf 1080p heruntergerechnet** worden — und mit
|
||
`keepOriginal: False` wäre der 4K-Rohschnitt anschließend gelöscht worden.
|
||
Aufgefallen ist es nur, weil der Commander gefragt hat, ob Rippy das
|
||
UHD-Preset automatisch nimmt.
|
||
- **Sofortmaßnahme am laufenden Job:** `keepOriginal` auf `True` gesetzt
|
||
(nur dieses eine Feld, gegengeprüft: kein anderer Schlüssel verändert).
|
||
Damit überlebt der 4K-Rohschnitt die Kompression auf jeden Fall.
|
||
- **Gebaut:** `preset_fuer(disc_type, einstellungen)` in `ripping.py` (pure,
|
||
getestet) plus drei Einstellungen `transcodePresetDvd` / `…Bluray` /
|
||
`…Uhd`. Reihenfolge: Preset des Disc-Typs → allgemeines
|
||
`transcodePreset` → `DEFAULT_HB_PRESET`. **Bestandsinstallationen ändern
|
||
ihr Verhalten nicht**, solange die neuen Felder nicht gespeichert sind.
|
||
`transcode_files` holt den Disc-Typ aus dem Job-Datensatz und schreibt ihn
|
||
mit ins Log.
|
||
- **UI (Einstellungen → Verarbeitung):** drei Auswahlfelder statt einem, mit
|
||
Klartext dazu, warum 4K auf ein 2160p-Preset gehört. Alle Preset-Namen
|
||
stammen aus `HandBrakeCLI --preset-list` im Worker-Image (1.6.1) — nicht
|
||
geraten (AGENTS Regel D).
|
||
- **⚠️ Deploy bewusst zurückgehalten:** `docker compose up -d --build`
|
||
würde den Worker-Container neu erstellen und den **laufenden Akira-Rip
|
||
abbrechen**. Erst deployen, wenn der Job durch ist. Der 4K-Rohschnitt ist
|
||
durch `keepOriginal` geschützt; danach reicht „Neu komprimieren" im UI,
|
||
um mit dem richtigen Preset in 4K zu komprimieren.
|
||
- **Nebenbefund:** `ps` gibt es im Worker-Image nicht (python-slim). Frühere
|
||
Prüfungen auf laufende Rips per `ps | grep` lieferten deshalb still
|
||
„nichts aktiv" — richtig geht es über `/proc`.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.11 — 4K-UHD GELÖST: Akira geht auf (25.07.2026)
|
||
|
||
- **🎉 Der Durchbruch:** Nach Übernahme des Schlüsselspeichers öffnet
|
||
`makemkvcon` auf der VM die Akira-UHD: „Operation successfully
|
||
completed", **`TCOUNT:5`**, fünf Titel — identisch zum Windows-Ergebnis.
|
||
**Erster belegter UHD-Disc-Zugriff auf der Rippy-Maschine.**
|
||
- **Die echte Ursache — und sie ist eine andere als in v3.10:**
|
||
`makemkvcon` unter **Linux** ruft Disc-Schlüssel **nie** ab. Die
|
||
**Windows**-Version tut es. Gegenprobe mit demselben Laufwerk und
|
||
derselben Disc:
|
||
|
||
| | 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" | **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`. Immer:
|
||
keine Verbindung. Die Meldungsvorlage „Downloading latest %1 to %2 ..."
|
||
steckt sehr wohl im Linux-Binary — sie löst nur nie aus. Gleiches
|
||
Symptom im MakeMKV-Forum, seit Jahren offen (t=25782, t=34022).
|
||
- **⚠️ Richtigstellung zu v3.10 (direkt darunter):** Dort steht, MakeMKVs
|
||
Schlüssel-Kanal sei abgeschaltet. **Das war falsch.** Die Herleitung
|
||
stützte sich auf zwei Hostnamen aus alten Forumsbeiträgen
|
||
(`hkdata.fairuse.org`, `hkdata.crabdance.com`), die tatsächlich nicht
|
||
mehr auflösen — MakeMKV benutzt sie aber längst nicht mehr. **Der Dienst
|
||
lebt, der Worker erreicht ihn sogar** (Verbindungstest auf
|
||
185.84.108.20:443 erfolgreich); er wird unter Linux nur nie gefragt.
|
||
Aufgedeckt hat das der Commander mit dem Einwand, unter Windows ginge es
|
||
sofort. Alles in v3.10 Gebaute bleibt richtig und nötig — nur die
|
||
`KEYDB.cfg` ist nicht der Haupt-, sondern der Ersatzweg.
|
||
- **Gebaut — Schlüsselspeicher übernehmbar:** `GET`/`POST
|
||
/system/keystore` plus die Helfer in `makemkv_daten.py` (beide
|
||
Zwillinge). Der Rohkörper der Anfrage IST die Datei — binär, deshalb
|
||
kein JSON und kein Base64. Die Prüfung lehnt einen Speicher **ohne**
|
||
`hkd_*.bin` ab, sonst lädt jemand den leeren Vorrat einer frischen
|
||
Installation hoch und wundert sich, dass nichts passiert.
|
||
- **Gebaut — UI:** neuer Block „Disc-Schlüssel für 4K-UHD" **über** dem
|
||
KEYDB-Block, mit Schlüssel-Anzahl, Upload und der Schritt-für-Schritt-
|
||
Anleitung für den Windows-Umweg. KEYDB.cfg ist jetzt als **Notnagel**
|
||
beschriftet. Die Worker-Plakette zeigt die Anzahl bekannter Schlüssel;
|
||
`0` heißt sichtbar „4K-UHD scheitert".
|
||
- **Gebaut — ehrliche Texte:** Der UHD-Fehlertext nennt jetzt den
|
||
Windows-Weg und die Anzahl der Schlüssel dieses Workers. Alle
|
||
Falschaussagen korrigiert: UI (3 Stellen), Anleitung (2), README (3),
|
||
KONZEPT §8 + §10, Modulkopf von `makemkv_daten.py`, Worker-Dockerfile
|
||
und `makemkv_key.py` (dort stand: „Den AACS-Schlüssel zieht MakeMKV via
|
||
LibreDrive ohnehin selbst aus dem Laufwerk" — gilt für Blu-ray, NICHT
|
||
für UHD).
|
||
- **So hältst du den Vorrat aktuell:** Laufwerk an den Windows-PC, Disc in
|
||
MakeMKV öffnen, dann `_private_data.tar` aus dem MakeMKV-Datenverzeichnis
|
||
(*Preferences → General*) unter Einstellungen → System hochladen. Der
|
||
Speicher der Windows-Installation liegt bereits auf der VM unter
|
||
`/srv/rippy/makemkv/`.
|
||
- **Offen:** Der volle UHD-Rip inklusive Transcode-E2E ist noch nicht
|
||
durch — belegt ist der Disc-Zugriff, nicht die komplette Kette bis zur
|
||
fertigen Datei. Und ob sich der Abruf unter Linux doch anstoßen lässt,
|
||
ist ungeklärt; der Code dafür ist im Binary vorhanden.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.10 — 4K-UHD: KEYDB.cfg statt Warten auf MakeMKV (25.07.2026)
|
||
|
||
- **Der Befund (am 25.07. live auf der VM im Worker-Container
|
||
nachgemessen — kein Verdacht, alles belegt):** Eine 4K-UHD (Akira,
|
||
MKB v76, Pressung Dezember 2020) scheitert mit „The volume key is
|
||
unknown for this disc". **Laufwerk und MakeMKV sind dabei in Ordnung:**
|
||
makemkvcon meldet „Using LibreDrive mode (v06.3)" und „Using direct
|
||
disc access mode", liest die Disc und legt den AACS-Dump ab
|
||
(Meldung 3332). Der Fehler liegt also NICHT an der Hardware.
|
||
- **Die echte Ursache — MakeMKV fragt gar nicht erst:** Das Debug-Log
|
||
geht ohne einen einzigen Netz-Versuch von „Loaded content hash table"
|
||
direkt auf „The volume key is unknown". **Beweise:**
|
||
`/root/.MakeMKV/_private_data.tar` enthielt nur die Index-Datei und
|
||
KEINE einzige `hkd_*.bin` — es wurde also nie ein Schlüssel geladen.
|
||
Auch mit erzwungener frischer Prüfung (`update.conf` gelöscht,
|
||
Meldung 5074 belegt den Web-Kontakt) und mit `app_UpdateEnable = "1"`
|
||
kam keiner. Und die im MakeMKV-Forum dokumentierten Schlüssel-Server
|
||
`hkdata.fairuse.org` und `hkdata.crabdance.com` lösen weltweit nicht
|
||
mehr auf (NXDOMAIN gegen Fritz!Box, 8.8.8.8 und 1.1.1.1).
|
||
- **Richtigstellung zu v3.3 (weiter unten korrigiert):** Dort stand, die
|
||
Ursache sei „Disc neuer als MakeMKVs Schlüssel-DB" und ein
|
||
MakeMKV-Update werde das lösen. Das ist widerlegt — es gibt keine
|
||
nachladbare Schlüssel-Datenbank mehr. **Warten auf ein MakeMKV-Update
|
||
hilft bei diesem Fehler nicht.**
|
||
- **Der einzige Weg, der heute funktioniert: `KEYDB.cfg`** — GROSS
|
||
geschrieben (unter Linux case-sensitiv) im MakeMKV-Datenverzeichnis.
|
||
Rippy macht diesen Weg jetzt begehbar, statt auf MakeMKV zu warten.
|
||
- **Gebaut — persistentes Datenverzeichnis:** `docker-compose.yml` mountet
|
||
`${MAKEMKV_DATA_HOST:-/srv/rippy/makemkv}` vom Host — im Worker auf
|
||
`/root/.MakeMKV`, in der API auf `/app/makemkv-data`; beide Container
|
||
bekommen `MAKEMKV_DATA_DIR`. Damit überleben `KEYDB.cfg` und die
|
||
AACS-Dumps jeden Rebuild. `entrypoint.sh` schreibt `settings.conf`
|
||
jetzt ergänzend statt zerstörend (sonst hätte der Beta-Key den Rest
|
||
überbügelt) und setzt `app_UpdateEnable = "1"`.
|
||
- **Gebaut — eine einzige Wahrheit über das Verzeichnis:** neues
|
||
Zwillings-Modul `makemkv_daten.py` (identisch in `docker/api/` und
|
||
`docker/worker/`) mit reinen Helfern — Status lesen, Inhalt prüfen,
|
||
atomar schreiben, löschen, AACS-Dumps auflisten. Nur reine Funktionen,
|
||
damit die Ampel sie ohne Postgres/Redis testen kann.
|
||
- **Gebaut — Bedienung im UI:** Einstellungen → System zeigt den
|
||
`KEYDB.cfg`-Status (Pfad, Größe, Anzahl Disc-Einträge, Datum), nimmt die
|
||
Datei über einen ganz normalen Datei-Dialog entgegen (der Browser liest
|
||
sie und schickt den Text als JSON — serverseitig bewusst KEIN
|
||
Multipart-Upload, es gibt kein `python-multipart`, das würde die API
|
||
beim Import töten), lehnt
|
||
unplausiblen Inhalt mit deutschem Klartext ab, kann die Datei wieder
|
||
entfernen und die AACS-Dumps zum Download anbieten.
|
||
- **Gebaut — man sieht endlich, was MakeMKV sagt:** `parse_msg()` in
|
||
`ripping.py` plus Log-Callback in `tasks.py` schreiben MakeMKV-Meldungen
|
||
ins Rippy-Log (gedrosselt: Code 1003 raus, keine Wiederholungen, max. 40
|
||
je Rip). Der UHD-Fehlertext ist ehrlich neu geschrieben. `caps.py`
|
||
meldet zusätzlich `keydb: ja | nein | unbekannt` je Worker.
|
||
- **Abgrenzung, die überall durchscheint:** **Rippy liefert KEINE
|
||
Schlüssel mit, lädt keine herunter und verteilt keine.** Rippy stellt
|
||
nur den Platz für eine Datei bereit, die der Nutzer selbst mitbringt,
|
||
und zeigt ehrlich an, was dort liegt. Genau die Grenze zieht schon
|
||
`docker/api/makemkv_key.py` (Zeile 14) für den Beta-Key: das ist die
|
||
Software-LIZENZ, nicht das Entschlüsseln oder Verteilen von
|
||
Disc-Schlüsseln.
|
||
- **⚠️ NOCH NICHT end-to-end bewiesen — ehrlich gesagt:** Zum Zeitpunkt
|
||
dieser Änderung lag KEINE `KEYDB.cfg` vor, die den Akira-Schlüssel
|
||
enthält. Belegt sind der Befund oben und die neue Mechanik (Mount,
|
||
Modul, Endpunkte, UI) — **nicht** ein erfolgreicher UHD-Rip. Der
|
||
Nachweis steht aus und braucht eine echte Schlüssel-Datei.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.9 — Windows-Installer als echte .exe (Icon, kein Konsolenfenster) (24.07.2026)
|
||
|
||
- **RippyWorkerSetup.exe** ersetzt den .vbs/.bat-Weg (Commander-Einwand:
|
||
.vbs ist abgekündigt + wird als gefährlich geflaggt). install-gui.ps1 via
|
||
ps2exe kompiliert: eingebettetes Rippy-Disc-Icon, KEIN Konsolenfenster
|
||
(-noConsole), WinForms (-STA). Vorgebaut auf Windows
|
||
(deploy/worker-windows/build-exe.ps1) + committet — Windows-.exe geht
|
||
nicht von Linux (Rippy-Host). API: GET /worker-setup/windows-exe.
|
||
UI (Worker → Windows): „Installer herunterladen (.exe)" als Haupt-Weg.
|
||
**E2E bewiesen**: von der VM geladen → Fenster öffnet, conhost-Zähler
|
||
unverändert (kein Konsolenfenster), Icon eingebettet.
|
||
- **Wichtig — friert nichts ein**: Die .exe holt HandBrake zur Laufzeit
|
||
(GitHub latest) und den Worker-Code live von Rippy. Nur bei Änderung der
|
||
GUI (install-gui.ps1) neu bauen (build-exe.ps1), NICHT bei Tool-Updates.
|
||
- **Update-Story dokumentiert** (Commander-Frage): MakeMKV → .env-Bump +
|
||
Rebuild (Update-Check zeigt es); HandBrake Docker = Debian-stabil,
|
||
native Worker = latest beim Installieren.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.8 — Grafischer Windows-Installer + Versionslage klar (24.07.2026)
|
||
|
||
- **Grafischer Windows-Installer** (statt CLI): install-gui.ps1 (WinForms,
|
||
ASCII-only) — Fenster mit Feldern (Rippy-IP, Worker-Name, Autostart) +
|
||
Install-Knopf mit Live-Log + „Worker starten". Gleiche Schritte wie der
|
||
CLI-Installer (Worker-Code, HandBrake latest, venv, Tray/Start/Uninstall).
|
||
UI (Worker → Windows): Knopf „Grafischen Installer herunterladen (.bat)" —
|
||
die .bat wird CLIENT-seitig mit der eingetragenen LAN-IP erzeugt,
|
||
Doppelklick lädt+startet die GUI von Rippy (GET /worker-setup/windows-gui).
|
||
CLI-Befehl bleibt als Profi-Alternative. Bewiesen: GUI-Fenster öffnet
|
||
sauber auf dem Commander-PC (Titel „Rippy Encoding-Worker - Installation").
|
||
- **Werkzeug-Versionslage exakt dargestellt** (Commander-Wunsch): System-Tab
|
||
erklärt jetzt klar — MakeMKV aktualisierbar (wichtig wegen Schlüssel-DB),
|
||
HandBrake im Docker-Worker bewusst Debian-stabil (1.6.1, KEIN Alarm mehr),
|
||
native Worker holen die neueste. Update-Check zeigt MakeMKV mit „✓ aktuell"
|
||
bzw. Update-Befehl, HandBrake neutral als Info.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.7 — Drei Praxis-Bugs (Mounts, HandBrake, Encoder-Wahl) (24.07.2026)
|
||
|
||
Alle drei live auf der VM verifiziert:
|
||
- **Speicher-Mounts robust**: Ein toter CIFS-Mount (NAS weg/Rebuild) war
|
||
mounted:false, verschwand aus „Verfügbare Ziele" und ließ sich nicht neu
|
||
anlegen („Name existiert"). Jetzt: `reachable`-Status (bounded `timeout 3
|
||
ls` — Endpoint lädt in 0,014 s statt 10 s), `umount -l`-Fallback,
|
||
`reparieren()` (lazy abhängen + frisch mounten), Re-Add repariert statt
|
||
409, POST /storage-mounts/{name}/repair, eigene „Netzwerk-Mounts"-Liste im
|
||
UI mit Status + Reparieren/Entfernen. Bewiesen: Reparatur des `rippy`-
|
||
Mounts → mounted:true, writable:true.
|
||
- **HandBrake-Versionen konsistent**: Windows-Installer zieht dynamisch die
|
||
neueste (GitHub latest) — bewiesen: HandBrake 1.11.2 installiert (statt
|
||
fest 1.9.2). Update-UI erklärt: Docker = Debian-stabil (bewusst älter),
|
||
Windows = neueste. Nebenbei ein latenter Installer-Bug gefixt: PowerShell
|
||
5.1 liest .ps1 als ANSI — ein Gedankenstrich zerschoss das Skript →
|
||
install.ps1 ist jetzt ASCII-only.
|
||
- **Encoder-/Worker-Wahl beim Rip**: Celery `worker_direct=True`, gezieltes
|
||
Routing (transcode_queue) mit sicherem Fallback auf die geteilte Queue.
|
||
Bewiesen mit ping_worker: Task landet exakt beim gewählten Node. Dropdown
|
||
im Rip-Dialog ab 2 Online-Workern. Node-Zuordnung disambiguiert bei
|
||
mehreren Workern pro Host. Nebenfund gefixt: DeviceDiscovery leitete die
|
||
Titel-Auswahl (titles) gar nicht weiter.
|
||
⚠️ Gezieltes Routing braucht AKTUELLEN Worker-Code (worker_direct) — ein
|
||
vor dieser Version installierter Remote-Worker pingt zwar, konsumiert aber
|
||
seine Direkt-Queue nicht → neu installieren.
|
||
- **Voller Transcode-E2E weiterhin durch die UHD-Key-Lage blockiert** (keine
|
||
entschlüsselbare Disc) — die Routing-Mechanik ist per ping_worker bewiesen.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.6 — Design 2.0 gelandet + Ein-Branch-Umstellung (24.07.2026)
|
||
|
||
- **Design 2.0 ist in `main`** (von Gemini umgesetzt): UI von 428
|
||
`theme === 'dark'`-Ternaries auf Tailwind-`dark:` + UI-Primitives
|
||
(`components/ui/`, `lib/design.ts`) umgebaut, „Cinematic Cinema OS"-Look.
|
||
Ampel grün (49 Tests, Ruff, Vite-Build), Live auf der VM.
|
||
- **Nur noch EIN Branch: `main`** (Commander-Entscheid). Der
|
||
`stable`-Zwischenbranch samt Grün-Gate ist abgeschafft — er war
|
||
vestigial, weil die VM ohnehin aus `main` deployt. Konsequenzen:
|
||
- ci.yml: Beförderungs-Schritt raus, die Ampel PRÜFT nur noch.
|
||
- deploy.sh: nutzt `main` statt `stable`.
|
||
- AGENTS §C / README / DESIGN-Briefing entsprechend umgeschrieben.
|
||
- Gelöschte Branches: `stable`, `design-2.0` (gemergt), `kernumbau-2026-07-23` (alt).
|
||
- **Deploy-Weg ab jetzt:** push → Ampel grün prüfen → auf der VM
|
||
`git pull` (in ~/projects/rippy) bzw. `./deploy.sh`.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.5 — Track-Tabelle, nativer Windows-Worker, Anleitungs-Tab (24.07.2026, Claude)
|
||
|
||
- **Volle Titel-Auswahl vor dem Rip**: „Disc scannen" im Rip-Dialog →
|
||
Worker-Task scan_tracks (makemkvcon info; Ergebnis via settings-Tabelle
|
||
'tracks:<device>', UI pollt) → Tabelle mit Checkbox/Dauer/Größe/Kapiteln,
|
||
Vorauswahl ab 5 min. Gewählte Titel gehen als meta.titles in den Job;
|
||
der Worker rippt sie einzeln (makemkvcon kann pro Aufruf nur einen Titel
|
||
oder all), Fortschritt anteilig. Parser mit Tests (apdefs-Attr 8/9/11).
|
||
- **Nativer Windows-Worker (ohne Docker!)**: Einstellungen → Worker bietet
|
||
jetzt ZWEI Varianten — Linux (Docker, wie gehabt) und Windows (nativ,
|
||
braucht nur Python). Die Rippy-Instanz versorgt sich selbst:
|
||
GET /worker-setup/windows liefert install.ps1, /worker-setup/paket den
|
||
Worker-Code als Zip (beides liegt via api-Dockerfile im Image).
|
||
install.ps1: venv + Abhängigkeiten, HandBrakeCLI 1.9.2 vom offiziellen
|
||
GitHub-Release (URL verifiziert), start-worker.bat (celery -Q transcode
|
||
--pool=solo), optional -Autostart (schtasks onlogon). tasks.py lädt auf
|
||
Windows ohne fcntl (Import-Guard); rip_disc ist dort hart verriegelt.
|
||
Für echte Transcodes übersetzt RIPPY_PATH_MAP die Container-Pfade aufs
|
||
Netzlaufwerk (pfad_lokal, mit Tests) — Voraussetzung bleibt eine
|
||
Freigabe der Rippy-Ablage (derselbe offene Infra-Punkt wie beim
|
||
Linux-Remote-Worker/AI-Box).
|
||
**E2E-BEWEIS (24.07., Commander-PC):** Installer in einem Rutsch
|
||
durchgelaufen (venv, Abhängigkeiten, HandBrakeCLI 1.9.2), Worker
|
||
gestartet und in Rippy erschienen:
|
||
`test-windows-nativ | online: True | HandBrake: 1.9.2 | IP: 192.168.178.98`
|
||
— echte LAN-IP, Celery-Ping grün. Testeintrag danach wieder entfernt.
|
||
- **Tray-Symbol + rückstandsfreie Deinstallation (v3.5.1, bewiesen):**
|
||
tray.py (pystray/Pillow, nur Windows-Worker) — Disc-Symbol neben der
|
||
Uhr mit Status, Start/Stopp, „Rippy öffnen", Log, Beenden; Celery läuft
|
||
als Kind ohne Konsolenfenster. install.ps1 erzeugt start-tray.bat
|
||
(empfohlen), start-worker.bat (Debug) und uninstall.ps1. **E2E bewiesen
|
||
auf dem Commander-PC:** Frisch installiert → Tray + celery-Kind liefen →
|
||
`tray-test` online in Rippy → uninstall.ps1 -Force stoppte alle
|
||
Prozesse, meldete den Worker per DELETE /workers/{name} ab und löschte
|
||
den Ordner restlos (danach: 0 Prozesse, Ordner weg, in Rippy nur noch
|
||
rippy-hauptworker).
|
||
- **Anleitungs-Tab** im UI: kompletter Selbsterklärer (Disc-Weg, Serien,
|
||
NAS, Media-Server, Benachrichtigungen, Key, Worker, Downloads, FAQ).
|
||
- Design 2.0 kommt bewusst in eine FRISCHE Session (Commander-Entscheid) —
|
||
Infrastruktur steht (darkMode 'class'), reine Konvertierungsarbeit.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.4 — Restefeger: der Ideen-Katalog ist abgearbeitet (24.07.2026, Claude)
|
||
|
||
**Commander-Entscheid: AUTH IST KOMPLETT RAUS** (Heimnetz-only; das UI hatte
|
||
nie einen Login, die Endpoints waren Placebo, passlib/bcrypt brach die Ampel).
|
||
/token + /api-keys + auth.py + Abhängigkeiten entfernt, JWT_SECRET_KEY ist
|
||
keine Pflicht mehr — der Schnellstart läuft ohne .env-Zwang. KONZEPT §10.
|
||
|
||
**Neu in v3.4 (Details in ROADMAP Etappe 15):**
|
||
- **Serien-Flow**: Rip-Dialog fragt Serienname + Staffel → Ablage
|
||
`<Serie>/Season NN`, tvshow.nfo/poster im Serien-Ordner, und die
|
||
**Episoden werden per Laufzeitabgleich (TMDB) erkannt und benannt**
|
||
(„Serie S01E02.mkv") — nur bei eindeutiger Zuordnung, sonst ehrliches Log.
|
||
Komplette Staffel auf einer Disc klappt auch bei uniformen Anime-Laufzeiten.
|
||
- **Jellyfin/Emby-Refresh** nach jedem fertigen Rip (URL/API-Key +
|
||
Test-Knopf in Einstellungen → Ripping) — Disc rein, Film erscheint im
|
||
Server, null Klicks dazwischen.
|
||
- **Duplikat-Warnung** per Disc-Fingerabdruck (Karte zeigt „bereits
|
||
gerippt", Vollautomatik überspringt).
|
||
- **„Nur Hauptfilm" funktioniert jetzt wirklich** (Info-Lauf → längster
|
||
Titel; pro Rip im Dialog wählbar). Vorher wirkungsloses Setting.
|
||
- **OMDb-Treffer werden eingedeutscht** (TMDB /find über die IMDb-ID).
|
||
- Dashboard: **Speicherplatz-Anzeige** (amber < 60 GB) + **CSV-Export**.
|
||
- **Metadaten-Seite entfernt** (Korrektur-Popup ist der einzige Weg) samt
|
||
Placebo-Endpoints; Doppel-Jahr „(2009) (2009)" gefixt.
|
||
- **Remote-Worker-Blocker behoben**: redis/postgres waren NIE veröffentlicht
|
||
— Ports 6379/5432 jetzt offen, API_URL für Worker gesetzt. Damit sind
|
||
AI-Box/Windows-Worker überhaupt erst anschließbar.
|
||
|
||
**Bewusst offen** (ROADMAP „Ideen-Katalog (Rest)"): volle Track-Tabelle,
|
||
nativer Windows-Worker (braucht Testlauf auf Ziel-Hardware), Design-2.0-
|
||
Konvertierung (Infrastruktur steht), AI-Box-NFS-Export, Kodi-Refresh.
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.3 — Praxis-Feedback-Runde (24.07.2026, Claude)
|
||
|
||
**Zwei echte Bugs mit Beweis gefixt:**
|
||
1. **SMB-Mount „Unable to apply new capability set"**: mount.cifs hebt
|
||
CAP_DAC_READ_SEARCH an — die fehlt in Dockers Default-Caps. Auf der VM
|
||
reproduziert (Bounding-Set a82425fb, Bit 2 fehlt) und mit
|
||
`cap_add: DAC_READ_SEARCH` bewiesen behoben (docker-compose.yml).
|
||
2. **TMDB fiel still aus**: Der Client konnte nur v4-Bearer-Tokens — der
|
||
eingetragene übliche v3-Key (32 Hex) bekam still 401, Suche lieferte nur
|
||
OMDb. Jetzt beide Key-Arten (ist_v4_token, mit Tests); Einstellungen →
|
||
APIs hat „Verbindung prüfen" mit Live-Status je Quelle (am Cache vorbei).
|
||
|
||
**Neu in v3.3:**
|
||
- **4K UHD als eigener Disc-Typ** (classify ≥ 55 GiB, beide detection.py,
|
||
Tests): eigene Badge-Farbe überall, Prescan-Label „4K UHD".
|
||
- **UHD-Kette diagnostiziert (Nachtrag, gleicher Tag): Der BU40N-Flash IST
|
||
erledigt** — makemkvcon meldet „Using LibreDrive mode (v06.3)". Der
|
||
Summer-Wars-Fehlschlag lag NICHT am Laufwerk, sondern an „The volume key
|
||
is unknown" — auf der VM mit 1.17.7 UND der aktuellsten 1.18.4
|
||
reproduziert. Konsequenzen:
|
||
MakeMKV auf **1.18.4** gehoben (Scan-Hänger durch überall genutztes
|
||
--noscan umgangen, auf der BU40N sauber gelaufen; URL-Base → /download),
|
||
run_makemkv reicht kritische Meldungen (volume key/Key abgelaufen) in
|
||
den Fehlertext durch, UHD-Klartext unterscheidet jetzt „Laufwerk kann
|
||
kein UHD" von „Disc-Schlüssel fehlt" inkl. Forum-Dump-Hinweis
|
||
(MakeMKV speichert den AACS-Dump automatisch unter /root/.MakeMKV/).
|
||
**⚠️ Korrigiert am 25.07.2026 (siehe v3.10 ganz oben):** Die hier
|
||
ursprünglich genannte Erklärung „die Disc ist neuer als MakeMKVs
|
||
Schlüssel-DB, ein MakeMKV-Update löst das" ist FALSCH. Nachgemessen:
|
||
MakeMKV hat gar keine nachladbare Schlüssel-DB mehr und versucht auch
|
||
keinen Online-Abruf; die alten Schlüssel-Server sind tot. Der Weg zum
|
||
Ziel heißt `KEYDB.cfg`, nicht „warten auf die nächste Version".
|
||
- **Vollautomatik** (Einstellungen → Ripping): Disc erkannt → Rip startet
|
||
ohne Popup in den passenden Schnellwahl-Ordner (Serie/Film/Musik).
|
||
- **Job-Verwaltung**: „Neu komprimieren" nur noch, wenn Rohdaten wirklich
|
||
daliegen (can_retry); Jobs einzeln löschbar (Papierkorb) + „Erledigte
|
||
aufräumen" mit Bestätigungs-Dialog — Dateien bleiben immer liegen.
|
||
- **„Alle herunterladen"** im Job-Detail (gestaffelte Einzel-Downloads —
|
||
bewusst kein Server-seitiges 40-GB-Zip).
|
||
- **Worker zuordenbar**: WORKER_NAME-Env als stabiler Anzeigename (compose:
|
||
rippy-hauptworker; Remote-Worker: frei wählbar) — fixt zugleich die
|
||
Offline-Leichen nach Rebuilds; IP + Container-ID werden mit angezeigt,
|
||
verwaiste Einträge sind löschbar (DELETE /workers/{name}). Online-Abgleich
|
||
läuft jetzt über info.hostname.
|
||
- **Disc-Karte**: „Quelle: TMDB/OMDb/MyAnimeList · xx % sicher" statt des
|
||
nackten „Übereinstimmung xx %"; TMDB-Metadaten sind Deutsch (language=
|
||
de-DE war schon überall dran — sie kamen nur nie an, siehe Key-Bug).
|
||
- **Ripping-Tab nach Medium** gegliedert (Video / Audio-CD / Allgemein) +
|
||
Klartext: alle Tonspuren & Untertitel bleiben erhalten (--all-audio/
|
||
--all-subtitles) — wichtig für Anime.
|
||
- **Ordner-Verwaltung** (Ex-„Dateibrowser") ist jetzt beschriftet, erklärt
|
||
und standardmäßig eingeklappt.
|
||
- **Docker-Pflicht beim Worker**: ehrlich im UI beantwortet; nativer
|
||
Windows-Dienst steht als Ausbaustufe in der ROADMAP (Ideen-Katalog).
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.2 — Universal-Komfort-Runde + Ampel entrostet (24.07.2026, Claude)
|
||
|
||
**Wichtigster Befund zuerst: die Ampel war seit dem 23.07. ROT und `stable`
|
||
hing 10 Commits hinter `main`** — deshalb kam nichts Neues mehr auf die VM.
|
||
Zwei Ursachen, beide behoben:
|
||
1. bcrypt ≥ 4.1 bricht passlib 1.7.4 (`__about__` entfernt → Selbsttest wirft
|
||
„password cannot be longer than 72 bytes") → **bcrypt==4.0.1 gepinnt**.
|
||
2. Der cache_keys-Test kannte den Disc-Fingerprint im Prescan-Key (23.07.)
|
||
nicht → Test an das echte Format angepasst + Fingerprint-Testfall dazu.
|
||
|
||
**Neu in v3.2 (Commander-Sammelauftrag, alles mit Tests / Vite-Build grün):**
|
||
- **Media-Server-Integration**: Setting `mediaServer` (Wizard + Einstellungen →
|
||
Ripping): Zielordner „Titel (Jahr)" statt Job-UUID; für Jellyfin/Emby/Kodi
|
||
zusätzlich movie.nfo/tvshow.nfo + poster.jpg (Worker: medien.py). Plex = nur
|
||
Benennung. Job speichert Disc-Metadaten jetzt mit (jobs.meta, Migration).
|
||
- **Benachrichtigungen ECHT**: notify.py in API+Worker (Discord/Slack/ntfy/
|
||
generisch, Erkennung an der URL) — das Feld war vorher ein Placebo. Meldung
|
||
bei fertig/fehlgeschlagen/abgebrochen; Anleitung + „Test senden" im UI.
|
||
- **SMB-Scan-Fix**: „NT_STATUS_ACCESS_DENIED" heißt jetzt im Klartext „Gast-
|
||
Abfrage verweigert → Benutzer/Passwort eintragen"; Credential-Felder stehen
|
||
im UI VOR dem Auflisten-Knopf. NAS-Ziel-Anlage quittiert per Toast.
|
||
- **4K-UHD-Vorsorge**: Arbeitsverzeichnis `workDir` konfigurierbar (auf
|
||
NAS-Freigabe legbar), Platz-Check per Disc-Größe (ioctl) VOR dem Rip mit
|
||
Klartext-Abbruch statt voller Platte bei 40 GB.
|
||
- **Einstellungen → System**: Werkzeug-Versionen je Worker (MakeMKV/HandBrake,
|
||
ENV MAKEMKV_VERSION im Image), Key-Quelle (ui/env/keiner), freier Platz;
|
||
**MakeMKV-Beta-Key im UI pflegbar** — gilt ab dem nächsten Rip, ohne Rebuild.
|
||
- **Job-Detail-Popup** (Klick auf Titel in „Neueste Jobs"): Poster, Jahr,
|
||
Beschreibung, Genres, Ablagepfad, Fehler (GET /jobs/{id}/detail).
|
||
- **Download fertiger Rips im Browser**: „Download"-Knopf bei fertigen Jobs
|
||
(Aktion-Spalte) → Dateiliste mit Größen im Detail-Popup, Stream via
|
||
GET /jobs/{id}/files/{name} (Pfad-Validierung strikt unter /app/media,
|
||
realpath-Check gegen Symlink-Ausbrüche) — vorher nur per scp erreichbar.
|
||
- **UI-Feedback**: Toast-System (ToastContext, ploppt oben rechts), drehende
|
||
Refresh-Knöpfe, Logs-Pills um Warnung/Fehler ergänzt, Datei-Browser zeigt
|
||
jetzt auch DATEIEN (grau, mit Größe) — der „leere" Bluray-Ordner war voll.
|
||
- **Favicon** (Disc, Indigo-Verlauf) + **Footer** „Created with ❤️ by LucyAI,
|
||
Claude and KrBrZ".
|
||
- **Doku**: README (Media-Server, Benachrichtigungen, UHD-Arbeitsverzeichnis,
|
||
„Rippy woanders bereitstellen"), ROADMAP Etappe 13 + Ideen-Katalog,
|
||
KONZEPT-Fortschreibungen (Abschnitt 10), AGENTS-Stand.
|
||
|
||
**Nächste Schritte:** unverändert die Fäden aus v3.1 (unten) + Ideen-Katalog
|
||
in der ROADMAP (Serien-Flow, Duplikat-Warnung, Jellyfin-Refresh, Auth).
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.1 — E2E BEWIESEN + Universal-Runde (24.07.2026, Claude)
|
||
|
||
**Der Beweis steht: Evangelion 2.22 (BD-50) komplett durch die Kette** —
|
||
erkannt → verlustfrei gerippt (43 GB, LibreDrive) → H.264-komprimiert →
|
||
**4,8 GB Endergebnis** (Hauptfilm 3,3 GB + 4 Extras), Rohdaten automatisch
|
||
gelöscht. Retry-transcode dabei live bewiesen (x265 war auf 4 vCPUs zu lahm
|
||
→ Abbruch + Neustart mit H.264 OHNE Neu-Rip).
|
||
|
||
Seit v3.0 dazugekommen (alles deployt, Ampel grün):
|
||
- **Korrektur-Flow**: „Nicht korrekt?!"-Popup an der Disc-Karte; Suche über
|
||
alle Quellen (GET /metadata/search), Wahl wird 30 Tage per
|
||
Disc-Fingerabdruck gemerkt (POST /metadata/override)
|
||
- **Metadaten-Kette**: BD-Klartext-Titel via ro-Mount (bdmt_*.xml),
|
||
Jikan/MAL (keyless, Ähnlichkeits-Score), OMDb-Qualitäts-Gate,
|
||
Wort-Strip-Degradation, ehrliches Cache-TTL (unknown nie cachen)
|
||
- **Worker-Verwaltung** (Einstellungen → Worker): Live-Erreichbarkeit
|
||
(Celery-Ping + Minuten-Herzschlag), Copy-Paste-Anbindung neuer Maschinen
|
||
- **Speicherziele**: SMB-Freigaben-Auflistung, Schreibtest beim Mount,
|
||
lokaler Ordner-Browser + mkdir; Mounts via UI (CAP_SYS_ADMIN + rshared)
|
||
- **First-Run-Wizard**, Job-Abbruch (kooperativ), Transcode als eigener
|
||
Task auf Queue `transcode` (Basis Remote-GPU-Worker), ruff.toml gepinnt
|
||
|
||
**Nächste Schritte:** AI-Box als VAAPI-Transcode-Worker (VCN4; NFS-Export
|
||
nötig, deploy/remote-transcode-worker.yml) · TMDB-Key eintragen ·
|
||
Arcane-GitSync-Binding auf `stable` (aktuell Notfall-Deploy-Weg) ·
|
||
Metadaten-Seite entfernen, wenn Popup abgenommen · Jellyfin-Postprocessing
|
||
an Worker · Auth vor schreibende Endpoints · MAKEMKV_APP_KEY erneuern
|
||
(~Ende Juli, Forum t=1053).
|
||
|
||
---
|
||
|
||
## Vorheriger Stand: v3.0 — Kernumbau (23.07.2026, Claude)
|
||
|
||
**Der Zweck existiert jetzt wirklich.** Komplett-Audit ergab: „Disc rein →
|
||
gerippt raus" hatte nie einen Code-Pfad (Details in ROADMAP Etappe 11).
|
||
|
||
Kernpunkte des Umbaus:
|
||
- **Rip-Kette komplett neu**: POST /jobs → Celery → Worker (MakeMKV 1.18.4
|
||
verlustfrei, Etappe 10) → Postgres-Job-Status → UI. CD weiter via abcde.
|
||
- **Disc-Erkennung** über Kernel-ioctls (CDROM_DISC_STATUS + Größe), Watcher
|
||
pollt statt udev (im Container gibt es kein udev).
|
||
- **UI**: echter Vite-Build hinter nginx mit /api-Proxy — vorher Dev-Server
|
||
und hartkodiertes localhost:8000 (deshalb waren nie Laufwerke zu sehen).
|
||
- **Compose**: Laufwerk als devices: (Bind-Mounts gaben EPERM), Ausgabe auf
|
||
media-Volume (vorher /output → nicht gemountet + read-only-Falle).
|
||
- **Placebos entfernt**: Mock-Logs, toter SSE-Stream, udevadm-Discovery,
|
||
14 Troubleshooting-Altdateien (ARCAN-*.md, Setup-Skripte, udev-Rules).
|
||
|
||
**Hardware-Kette (23.07.):** Laufwerk (Verbatim 4K BD RW, BU40N 1.05) hängt am
|
||
Proxmox-Host; LPM-Quirk `usbcore.quirks=18a5:0428:k` gefixt die Serien-Disconnects
|
||
(reboot-fest in GRUB). VM 106 bekommt es per USB-Passthrough `host=18a5:0428`.
|
||
⚠️ Firmware 1.05 kann KEIN UHD-Ripping (verschlüsselt) — Crossflash auf 1.03-MK
|
||
ist der dokumentierte Weg, separater Faden. DVD/BD normal geht.
|
||
|
||
**Offen:** E2E mit echter Disc · Jellyfin-Post-Processing an Worker anbinden ·
|
||
Auth vor schreibende Endpoints · MAKEMKV_APP_KEY in Arcane-Env pflegen (monatlich).
|
||
|
||
---
|
||
|
||
## Vorheriger Stand
|
||
|
||
**v1.10 — Complete Dark Mode Implementation (22.07.2026)**
|
||
|
||
Rippy läuft auf Arcane VM (192.168.178.162):
|
||
- ✅ Arcane WebUI: http://192.168.178.162:3552
|
||
- ✅ Rippy UI: http://192.168.178.162:80
|
||
- ✅ Rippy API: http://192.168.178.162:8000
|
||
- ✅ Theme Context ausgelagert (App.tsx → ThemeContext.tsx + useDarkMode.ts)
|
||
- ✅ Config Validation mit TMDB-API-Key Pflicht
|
||
- ✅ Cache Key Centralization (cache/keys.py)
|
||
- ✅ Dark Mode mit Theme-Toggle und localStorage persistence (UI-Only)
|
||
- ✅ **Alle UI-Komponenten komplett auf Dark Mode aktualisiert:**
|
||
- `App.tsx`, `Dashboard.tsx`, `Settings.tsx`, `MetadataPreview.tsx`
|
||
- ✅ Sidebar Navigation mit Dark Mode Support
|
||
- ✅ Einstellungen-Page mit Tab-Struktur
|
||
- ✅ Doppelte Arcane-Einträge behoben (`rippy` statt `Rippy`)
|
||
- ✅ Import-Fixes (relative → absolute Imports)
|
||
- ✅ Git Sync in Arcane konfiguriert
|
||
- ✅ Commit: `d2fb281` — Complete Dark Mode Implementation
|
||
|
||
### Docker-Container
|
||
|
||
| Container | Port | Status |
|
||
|-----------|------|--------|
|
||
| rippy-api | 8000 | Healthy |
|
||
| rippy-worker | - | Running |
|
||
| rippy-ui | 80 | Running |
|
||
| rippy-postgres | 5432 | Healthy |
|
||
| rippy-redis | 6379 | Healthy |
|
||
|
||
### Features
|
||
|
||
- ✅ **Etappe 3**: SQLite-Cache, TMDB/MusicBrainz/TheTVDB Clients, Pre-Scan, Metadaten-Preview
|
||
- ✅ **Etappe 4**: Jellyfin-Formatierung (NFO-Generator, Image-Downloader)
|
||
- ✅ **Etappe 5**: JWT-Auth (15min/7T), Rate-Limiting (100/min), API-Key-Management
|
||
- ✅ **Etappe 6**: Docker read_only, tmpfs, healthchecks, minimale Images
|
||
- ✅ **Etappe 7**: API UI Modernisiert, Import-Fixes, Doppelte Einträge behoben
|
||
- ✅ **Etappe 8**: Dark Mode mit Theme-Toggle, Separation of Concerns
|
||
- ✅ **Etappe 9**: Complete Dark Mode Implementation (alle UI-Komponenten)
|
||
- ✅ **Dokumentation**: README, KONZEPT.md, ROADMAP.md, SAVEPOINT.md
|
||
|
||
### Nächste Schritte
|
||
|
||
- Job-Verlauf UI (aktuell nur leere Listen)
|
||
- TMDB API Schlüssel in Arcane Environment konfigurieren
|
||
- Proxmox LXC Template
|
||
- Ansible Playbooks
|
||
|
||
### SoC Refactoring — Abgeschlossen (Etappe 9)
|
||
|
||
- ✅ **Theme-Context**: Theme-Logik aus App.tsx ausgelagert
|
||
- ✅ **Dark Mode Utility**: useDarkMode Hook implementiert
|
||
- ✅ **Component-Struktur**: Dark Mode props von inneren Komponenten versteckt
|
||
- ✅ **Config Validation**: TMDB-API-Key ist Pflicht
|
||
- ✅ **Cache Key Centralization**: cache/keys.py erstellt
|
||
- ✅ **CD-Ripping**: abcde-Integration implementiert
|
||
|
||
### Git-Log
|
||
|
||
```
|
||
d2fb281 - fix: complete dark mode implementation with all UI components
|
||
43dfce5 - feat(ui): implement dark mode with theme toggle
|
||
rippy-ui-modern - UI Modernisiert & Import-Fixes
|
||
3d87c8c - Dokumentation aktualisiert
|
||
bdb9f8d - SAVEPOINT v1.5: Sicherheit abgeschlossen
|
||
efa642e - Etappe 6: Sicherheit
|
||
```
|
||
|
||
---
|
||
|
||
## v2.0 — Fix-Runde nach externem Code-Review (22.07.2026, Claude)
|
||
|
||
**Alle Befunde des Reviews behoben, echte Tests eingeführt, Ampel-CI aktiv.**
|
||
|
||
Gefixt:
|
||
- **Metadaten-Preview WIEDERHERGESTELLT**: Beim SoC-Refactoring hatte ein Stub-Paket
|
||
die echte prescan-Implementierung überschattet — die Preview lieferte immer
|
||
„Unknown Disc". Echte Logik liegt jetzt im Paket, tote Altmodule (cache.py,
|
||
prescan.py flach) gelöscht.
|
||
- Fortschrittsmeldung: Celery `update_state` statt Aufrufe eines nie existierenden
|
||
Tasks; `self.send_task` (erfundene API) entfernt.
|
||
- abcde-Kommando korrigiert (`-o` war doppelt → CD-Ripping war nie funktionsfähig);
|
||
Zielverzeichnis jetzt via OUTPUTDIR-Config; Kommando-Bau als testbare Funktion.
|
||
- JWT: fester Schlüssel PFLICHT (kein Zufalls-Fallback pro Prozess mehr);
|
||
Logout blacklistet wirklich; Cleanup löscht nur Abgelaufene (vorher: alles).
|
||
- main.py: crashende Endpoints repariert (fehlende Imports Path/secrets,
|
||
nicht existentes api_keys-Dict → ratelimit-Store), Audio-`year`-Bug,
|
||
Admin-Zugang aus .env statt hartkodiert.
|
||
- Ruff komplett grün (29 Funde), package-lock.json committet.
|
||
- Tests: test_auth, test_cache_keys, test_ripping_helpers (der giftige
|
||
test_health-Placebo ist raus).
|
||
|
||
## ✅ ENTSCHIEDEN (22.07. abends): Das KONZEPT gilt — MakeMKV kommt
|
||
|
||
**MakeMKV lossless (Muss-Feature) wird umgesetzt — als eigene Etappe 10 in der
|
||
ROADMAP** (Worker-Container + makemkvcon + Beta-Key, in Zed zu bauen, E2E mit
|
||
echter Disc). Bis dahin bleibt HandBrake als SICHTBARER Übergang aktiv — jede*r
|
||
weiß: aktuell wird transkodiert, nicht verlustfrei gesichert.
|
||
|
||
## Deploy-Weg seit 22.07. abends: GRÜN-GATE (vollautomatisch)
|
||
Push auf `main` → Ampel prüft → grün → CI befördert auf Branch `stable` →
|
||
**Arcane-GitSync zieht `stable` und deployt**. Rot deployt NIE. `./deploy.sh`
|
||
ist nur noch der Notfall-Hebel; SSH zur VM bleibt als Fallback erlaubt.
|