- Faktenfehler korrigiert: Gitea ist oeffentlich per HTTPS erreichbar (gemessen, § 3.6) — Updates kommen direkt daraus, Drei-Wege-Tabelle weg - node:sqlite in Electron 44 im utilityProcess bewiesen (§ 3.4, beweise/sqlite-main.js + sqlite-kern.js) — better-sqlite3 nicht noetig - Disc-Wache umgedreht: 3-Sekunden-Takt ist Plan A, WM_DEVICECHANGE spaetere Verfeinerung (§ 5) - Entscheid 7 verschaerft: main-Aufraeumen sofort, nicht erst nach W-6 - Entscheid 9 neu: Zielgruppe Bekannte mit Link, Lizenztexte liegen bei - MakeMKV-Lage tagesaktuell bestaetigt (Key bis Ende September 2026, Kaufseite defekt = Dauerzustand seit Sommer 2025) - Electron-Pflege-Regel (§ 6.8), npm-11-Sperre trifft auch Electron selbst (§ 3.5), Release = drei Dateien, 4K-Schluesselkette in § 10, Risikotabelle aktualisiert Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
60 KiB
KONZEPT — Rippy für Windows
Rippy v5. Ein eigenständiges Windows-Programm, gebaut mit Electron und TypeScript. Grüne Wiese: kein Docker-Code, kein Python, keine Container-Reste.
Stand: 30.08.2026, zweite Fassung · Branch
worktree-windows-electron
Was die zweite Fassung vom selben Tag unterscheidet: Das Konzept wurde
geprüft, tagesaktuell gegenrecherchiert und nachgemessen. Vier Dinge haben
sich geändert: (1) Ein Faktenfehler ist korrigiert — das Gitea des Commanders
ist entgegen der ersten Fassung öffentlich erreichbar, die Update-Frage
löst sich damit fast von selbst (§ 3.6, Entscheid 6). (2) Die letzte
technische Unbekannte ist gemessen — node:sqlite funktioniert in Electron 44,
im echten Einsatzkontext (§ 3.4). (3) Die Disc-Erkennung ist vom Kopf auf die
Füße gestellt — der Prüf-Takt ist Plan A, das Windows-Ereignis die spätere
Verfeinerung (§ 5). (4) Drei Entscheide des Commanders sind eingearbeitet:
Update-Quelle, Zielgruppe, und der Zeitpunkt des Aufräumens (Entscheide 6, 7
und 9).
0. Leseanleitung
| § | Frage |
|---|---|
| 1 | Warum wird neu gebaut statt repariert? |
| 2 | Was hat der Commander entschieden? |
| 3 | Was wurde gemessen, bevor entschieden wurde? |
| 4–5 | Wie ist das Programm aufgebaut, und was passiert, wenn eine Disc reingeht? |
| 6–9 | Features, Oberfläche, Setup, Werkzeuge |
| 10 | Was kommt aus dem alten Rippy mit? |
| 11 | Was aus main entfernt wird |
| 12–14 | Etappen, Risiken, was NICHT gebaut wird |
Was dieses Dokument NICHT tut: Es erfindet keine Messungen. Alles, was hier
als Zahl oder Verhalten steht, ist entweder in § 3 an dieser Maschine gemessen,
im alten Rippy belegt (SAVEPOINT.md, AGENTS.md), am 30.08.2026 gegen das
Netz geprüft oder ausdrücklich als Annahme markiert. Die Trennung ist
wichtig, weil dieses Projekt schon mehrfach teuer dafür bezahlt hat, dass
jemand eine plausible Erklärung für eine gemessene gehalten hat. Die erste
Fassung dieses Konzepts hat es selbst vorgemacht: Sie behauptete, Gitea sei
von außen nicht erreichbar — eine Messung von dreißig Sekunden zeigte das
Gegenteil (§ 3.6).
1. Warum neu gebaut wird
Die heutige Windows-Fassung ist kein Windows-Programm. Sie ist der Docker-Code in einer EXE:
RippySetup.exe (PyInstaller)
├─ docker/api/ → FastAPI, uvicorn auf 127.0.0.1:7788
├─ docker/worker/ → der Celery-Worker, nur ohne Celery
├─ docker/ui/dist/ → dieselbe React-Oberfläche wie im Browser
└─ pywebview → ein Fenster davor
Das Ergebnis steht im SAVEPOINT.md: elf Release-Kandidaten in drei Tagen.
Und die Funde sind fast alle vom selben Typ — Linux-Annahmen, die unter Windows
etwas anderes bedeuten:
| Fund | Was passierte |
|---|---|
timeout 4 ls -d <pfad> als Verzeichnisprüfung |
Unter Windows gibt es timeout.exe, aber sie kennt weder ls noch -d. Antwort war „weg" für jedes Verzeichnis — Rohdaten waren grundsätzlich unsichtbar. Dazu blitzten Konsolenfenster auf. |
shutil.which("makemkvcon") |
Findet unter Windows nie etwas — Programme liegen in Program Files, nicht im PATH. Die 4K-Schlüssel-Automatik lief deshalb nie an. |
os.path.isdir("/app") |
Rippy hielt sich für einen fremden Docker-Worker. Zweimal gefunden, an zwei Stellen. |
Routen /dev/{name} |
Das UI ruft mit G auf, gebaut war /dev/G. Auswerfen und Disc-Scan antworteten immer mit 404. |
F:\ wurde zu F: |
Unter Windows ist F: ohne Trenner der aktuelle Ordner auf F, nicht dessen Wurzel. 16,5 GB Rohschnitt unsichtbar; der Dialog bot nur „Neu rippen" an. |
makemkvcon überlebte den Elternprozess |
Windows räumt Kindprozesse nicht auf. Zwei Waisen hielten das Laufwerk fest. |
| Zwei Speicher für dieselben Ordner | Die Oberfläche schrieb outputDir in die Datenbank, der Betrieb las storage.medien aus einer Konfigurationsdatei, die niemand schrieb. Eingestellt E:\Rippy, angezeigt C:\Users\...\Videos\Rippy. |
Diese Liste ist nicht das Problem — sie ist das Symptom. Jeder einzelne Fund war eine Stelle, an der Code, der für einen Linux-Container geschrieben wurde, unter Windows etwas anderes bedeutet. Solange die Grundlage ein umgebogener Container ist, ist der nächste Fund dieser Sorte nur eine Frage der Zeit.
Die Entscheidung ist deshalb nicht „das ist schlecht gebaut", sondern: das ist am falschen Ort gebaut. Ein Windows-Programm fängt bei Windows an, nicht bei einem Container, dem man Windows beibringt.
2. Die Entscheidungen (Commander, 30.08.2026)
Neun Entscheide, alle am selben Tag — die Entscheide 6, 7 und 9 in ihrer heutigen Form aus der Prüfung der ersten Fassung. Sie stehen hier, damit später nachvollziehbar ist, was Entscheidung war und was Vorschlag.
Entscheid 1 — Alles TypeScript/Node
Es gibt keinen Python-Anteil in Rippy für Windows. Kein Sidecar, keine mitgelieferte Laufzeit, keine IPC-Brücke zwischen zwei Sprachen. Eine Sprache, eine Werkzeugkette, ein Setup.
Was das kostet: Die rund 18.000 Zeilen Python werden nicht übernommen. Was übernommen wird, ist ihr Wissen — die Parser-Regeln, die gemessenen Fallen, die Kommandozeilen (§ 10). Das ist der teure Teil an ihnen, und der wandert vollständig mit.
Was das bringt: Der ganze Fehlertyp aus § 1 kann nicht mehr entstehen. Es gibt keinen Container-Pfad, den jemand vergessen könnte, weil es nie einen gab.
Entscheid 2 — Die Docker-Version bleibt unangetastet
Rippy auf der VM läuft weiter wie heute. Es wird nicht angefasst, nicht migriert, nicht mitgepflegt. Zwei getrennte Produkte, keine geteilten Module.
Begründung: Geteilte Module zwischen zwei Betriebssystemen sind genau die
Konstruktion, an der v1 gelitten hat — drei Dateien lagen byte-identisch
doppelt im Repo, und db.py schrieb es sogar in den Kopfkommentar: „Wer die
Struktur ändert, ändert BEIDE Dateien."
Entscheid 3 — Reiner Einzelplatz
Ein Rechner macht alles: erkennen, rippen, komprimieren, ablegen. Kein Server, keine Netz-Queue, keine Worker-Verwaltung, keine Pfad-Übersetzung zwischen Maschinen.
Was damit ersatzlos wegfällt: Celery, Redis, Postgres, die Worker-Tabelle,
worker_direct, die Lease-Mechanik über Netz, RIPPY_PATH_MAP, die
Zombie-Erkennung, die Mount-Wache, das Rate-Limit (es gibt keinen fremden
Client mehr), /worker-setup/*, die Encoder-Auswahl je Knoten.
Grob geschätzt sind das 40 % der heutigen Komplexität — und zwar der Teil, der die meisten Fehlerbilder erzeugt hat.
Was bleibt: Die Ablage darf trotzdem auf dem NAS liegen. Ein UNC-Pfad
(\\nas\medien) oder ein verbundenes Netzlaufwerk ist für Rippy nur ein Pfad.
Windows mountet, Rippy prüft — dieselbe Trennung wie in Entscheid 3 des
v2-Konzepts, nur ohne Container drumherum.
Entscheid 4 — Eigener Branch im selben Gitea-Repo
Ein Git-Worktree unter .claude/worktrees/windows-electron auf dem Branch
worktree-windows-electron. main bleibt unberührt und jederzeit deploybar.
Entscheid 5 — Kein Code-Signing-Zertifikat
„ist egal, brauchen wir nich"
Die EXE bleibt unsigniert. Zwei Folgen, beide bewusst getragen:
- SmartScreen. Beim ersten Start eines Downloads zeigt Windows den Hinweis „Der Computer wurde geschützt"; über Weitere Informationen → Trotzdem ausführen geht es weiter. Das gehört in die Anleitung, nicht unter den Teppich — samt der Angabe, woran man die echte Datei erkennt (Größe und Prüfsumme stehen beim Release).
- Updates ohne Echtheitsprüfung. Ohne Signatur kann
electron-updaterein heruntergeladenes Update nicht auf Echtheit prüfen. Die Absicherung liegt damit vollständig beim Transportweg — deshalb die HTTPS-Pflicht in § 6.8, Regel 1.
Entscheid 6 — Updates aus dem öffentlichen Gitea
„Gerne das Gitea Release, mit Möglichkeit dass auch EXTERNE diese Updates fahren können" — und in der zweiten Fassung konkretisiert: das öffentliche Gitea direkt, kein Spiegel.
Die erste Fassung hielt das für ein Infrastruktur-Problem („Gitea ist von
außen nicht erreichbar") und entwarf drei Auswege. Die Messung in § 3.6 hat
das erledigt: Gitea ist längst öffentlich erreichbar —
https://git.tobisniceshomelab.ddnsfree.com, mit gültigem TLS-Zertifikat,
Lesen ohne Anmeldung. Die HTTPS-Pflicht aus § 6.8 ist damit erfüllbar, und
zwar für den Commander und für Externe, ohne dass irgendetwas neu
aufgebaut wird.
Was bleibt:
- Die Update-Adresse steht in der Konfiguration, vorbelegt mit den Releases
dieses Gitea. Wer einen eigenen Server hat, trägt seine eigene Adresse ein —
electron-updaterbraucht nur einen statischen HTTPS-Ort. - Jedes Release besteht aus drei Dateien, nicht zwei:
latest.yml(die Update-Auskunft), das Setup und die.blockmap(macht aus einem Voll-Download einen Differenz-Download). - ⚠️ Ein Handgriff für Etappe W-6: Gitea-Release-Downloads hängen an
ihrem Tag (
/releases/download/v5.0.1/...) —electron-updaterbraucht fürlatest.ymlaber eine feste Adresse. Ob Gitea 1.27 das GitHub-Musterreleases/latest/download/...bedient, ist ungeprüft (2024 war es dort noch ein offener Wunsch). Falls nein, ist die Rückfallebene simpel: ein festes Update-Tag, dessen drei Dateien der Bau bei jedem Release ersetzt. Beides ist eine Bau-Einstellung, keine Programmänderung.
Entscheid 7 — Der alte Windows-Weg wird entfernt, sofort, auch aus main
„Nein — direkt weg, auch aus dem Original Repo. Das neue Standalone Windows Rippy wird ein komplett neues Produkt und kein Aufbau auf die Docker-Architektur."
Die PyInstaller-Fassung bleibt nicht parallel installierbar, und ihr Code verlässt das Repo. Die erste Fassung hatte das Aufräumen auf „erst wenn v5 installierbar ist" gelegt; der Commander hat bei der Prüfung der zweiten Fassung anders entschieden: sofort, nicht erst nach Etappe W-6.
Was das bedeutet, gehört ehrlich hingeschrieben: Zwischen dem Aufräumen und W-6 liefert das Repo kein installierbares Windows-Rippy. Die auf dem Commander-PC installierte rc11-Fassung läuft lokal weiter, bekommt aber keine Reparaturen mehr; wer in der Zwischenzeit rippen will, nutzt sie oder die Docker-Version. Das ist der Preis für ein Repo ohne Zwitter — und er ist bewusst bezahlt.
Das ist kein Widerspruch zu Entscheid 2. „Docker bleibt unangetastet" meint die Docker-Funktion; der Windows-Standalone-Zweig ist gerade nicht Docker, sondern der Fremdkörper darin. Was genau entfernt wird, steht in § 11 — mit einer Unterscheidung, die beim Aufräumen entscheidend ist.
Entscheid 8 — Der Remote-Worker bleibt bei Docker
„Das soll NICHT Teil des neuen Standalone-Produktes sein, da dieser NUR für die Docker-Variante verwendet wird."
Der „Rippy Worker" auf einem Hilfsrechner ist eine Funktion der Docker-Installation, kein Standalone-Rippy. Er wird weder abgeräumt noch nach v5 übernommen. Warum das so ist und was genau er tut, steht in § 11.1 — dort, wo die Unterscheidung gebraucht wird.
Entscheid 9 — Zielgruppe: Bekannte mit Link
Neu in der zweiten Fassung: Rippy v5 wird kein öffentliches Produkt. Der Commander gibt die Download-Adresse gezielt weiter — Familie, Freunde. Keine öffentliche Ankündigung, kein Support-Anspruch Fremder.
Konsequenzen:
- Anleitung, SmartScreen-Erklärung und Prüfsummen bleiben schlank — sie müssen einen wohlwollenden Bekannten durchbringen, kein anonymes Publikum.
- Die Lizenztexte gehören trotzdem dazu. Weitergabe an Bekannte ist Weitergabe: HandBrake (GPL-2) und FLAC (BSD-artig) verlangen Lizenztext und Quellverweis im Paket (§ 9). Das ist keine Formalie für später, sondern Bestandteil von Etappe W-6.
- Das Repo bleibt lesbar wie bisher; beworben wird nichts. Sollte v5 eines Tages doch öffentlich werden, ändert sich am Programm nichts — nur an Anleitung und Sorgfaltstiefe.
3. Was gemessen wurde, bevor entschieden wurde
Electron bedeutet: Die Arbeit macht Node, nicht Python. Damit hängt das ganze Konzept an einer Frage, die vorher niemand geprüft hat:
Kann Node überhaupt alles, was Rippy am Laufwerk braucht?
Wäre die Antwort nein, wäre das Konzept wertlos. Also gemessen — am
30.08.2026, auf diesem Rechner, am echten Laufwerk. Die Skripte liegen in
beweise/ und sind dort nachstellbar dokumentiert.
3.1 Die Werkzeuglage
Node v24.19.0
npm 11.17.0
Electron 44.0.0 (Chromium 152.0.7977.54 · Node 24.18.1)
WebView2 151.0.4129.107
Laufwerk G: HL-DT-ST BD-RE BU40N USB Device (Medium eingelegt)
Zur Einordnung, am 30.08.2026 gegen das Netz geprüft: Electron 44 ist die aktuelle stabile Linie, koffi 3.1.6 die aktuelle Version, Node 24 ist LTS. Das Konzept baut also nicht auf Auslaufendem auf — was Electron-Versionen betrifft, gilt aber die Pflege-Regel in § 6.8.
3.2 Win32 aus Node — die Laufwerks-Steuerung
koffi 3.1.6 installiert, dieselben Steuercodes wie in
src/rippy/drives/win_ioctl.py (die dort aus dem CTL_CODE-Makro hergeleitet
sind, nicht abgeschrieben). Nur lesende Aufrufe, nichts ausgeworfen:
1. GetLogicalDrives + GetDriveTypeW -> optische Laufwerke: [ 'G' ]
2. CreateFileW \\.\G: (Zugriff 0) -> offen
CreateFileW \\.\G: (GENERIC_READ) -> offen
3. IOCTL_STORAGE_QUERY_PROPERTY -> Hersteller: HL-DT-ST | Modell: BD-RE BU40N
| Rev: 1.03 | Serial: 0025114C0149
4. IOCTL_STORAGE_CHECK_VERIFY2 -> Medium eingelegt
5. IOCTL_CDROM_DISK_TYPE -> Win32-Fehler 50
6. IOCTL_DISK_GET_LENGTH_INFO -> 33.759.690.752 Bytes (33,76 GB) => Blu-ray
Punkt 5 ist kein Fehlschlag, sondern eine Bestätigung. Fehler 50 ist
ERROR_NOT_SUPPORTED — genau das, was auch der Python-Treiber an diesem
Laufwerk sieht (SAVEPOINT.md, rc11). Node verhält sich identisch. Und die
Lehre daraus steht schon im alten Code: Die Disc-Einordnung darf sich nicht
auf IOCTL_CDROM_DISK_TYPE verlassen — die Größe ist der verlässliche Weg.
3.3 Die Prozess-Leine — überlebt makemkvcon einen Absturz?
Der Befund aus rc10: Windows räumt Kindprozesse nicht auf. Ein hart beendeter
Rippy hinterlässt ein makemkvcon, das das Laufwerk festhält. Die Lösung dort
war eine Windows-Arbeitsgruppe (Job Object) mit
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE.
In Node nachgestellt — Job Object gesetzt, Kind gestartet, Eltern mit
taskkill /F ohne /T abgeschossen (genau das, was bei einem Absturz und
beim Drüber-Installieren passiert):
1. CreateJobObjectW -> Arbeitsgruppe angelegt
2. SetInformationJobObject -> KILL_ON_JOB_CLOSE gesetzt
3. AssignProcessToJobObject -> dieser Prozess hängt in der Gruppe
4. Kindprozess gestartet, PID 16040
vor dem Abschuss: Eltern lebt: True Kind lebt: True
taskkill /F /PID 29488 -> ERFOLGREICH
danach: Eltern lebt: False Kind lebt: False
3.4 Datenbank ohne native Abhängigkeit — in Electron gemessen
Node 24 bringt SQLite mit (node:sqlite, DatabaseSync). Keine
better-sqlite3-Kompilierung, kein node-gyp, kein Visual-Studio-Build in der
Bau-Kette.
Die erste Fassung musste hier eine Warnung setzen: Electron kompiliert sein
Node mit eigenen Flags, und ob node:sqlite dort vorhanden ist, war nur für
Node pur gemessen. Das ist erledigt — am 30.08.2026 in Electron 44.0.0
gemessen, und zwar im utilityProcess, also exakt dem Kontext, in dem
kern/speicher/db.ts laufen wird (§ 4.1):
KERN-ANTWORT: {"ok":true,"wert":"geht","node":"24.18.1"}
Kern beendet mit 0
Anlegen, Schreiben, Lesen — alles grün. Die Rückfallebene better-sqlite3
wird nicht gebraucht. Skripte: beweise/sqlite-main.js + sqlite-kern.js.
3.5 Ein Nebenbefund für die Bau-Kette — zweimal bestätigt
npm 11 blockiert Install-Skripte fremder Pakete standardmäßig:
npm warn allow-scripts koffi@3.1.6 (install: node ./cnoke.cjs -P . --prebuild --release)
koffi lädt trotzdem — es bringt vorgebaute Binärdateien mit. Electron
selbst trifft die Sperre härter: Sein Install-Skript lädt die eigentliche
Programmdatei herunter; wird es geblockt, liegt nach npm install ein Paket
ohne dist/electron.exe da, und nichts startet. Bei der sqlite-Messung
(§ 3.4) selbst hineingelaufen; node node_modules/electron/install.js holt
die Binary nach. Beides gehört in die Bau-Anleitung, sonst sucht jemand eines
Tages an der falschen Stelle.
3.6 Die Update-Quelle — gemessen statt vermutet
Die erste Fassung behauptete: „Gitea läuft auf 192.168.178.153 im Heimnetz.
Von außen ist das nicht erreichbar." Am 30.08.2026 von außerhalb des
Heimnetzes gemessen:
https://git.tobisniceshomelab.ddnsfree.com/Hitonabi/rippy
-> lädt anonym, ohne Anmeldung, über den Reverse-Proxy des Commanders
-> TLS-Zertifikat gültig
-> Gitea 1.27.2 (/api/v1/version)
-> bisher 0 Releases, 0 Tags — der Release-Weg ist frei
Die interne Adresse 192.168.178.153:3000 existiert daneben weiter; für
Updates zählt die öffentliche. Damit ist Entscheid 6 keine Infrastruktur-Frage
mehr, sondern eine Bau-Einstellung. Offen bleibt nur die
Fest-Adresse-Feinheit für latest.yml (Entscheid 6, ⚠️-Punkt) — die wird in
W-6 am ersten echten Release gemessen.
4. Aufbau
4.1 Drei Teile, drei Prozesse
┌──────────────────────────────────────────────────────────────┐
│ Rippy.exe — Electron Main-Prozess │
│ ├─ Tray-Symbol, Fensterverwaltung, Autostart, Selbst-Update │
│ └─ hält die Prozess-Leine (§ 3.3) — ALLES stirbt mit ihm │
└───────────┬─────────────────────────────┬────────────────────┘
│ IPC │ MessagePort
┌───────────▼──────────────┐ ┌──────────▼───────────────────────┐
│ Fenster (Renderer) │ │ Kern (utilityProcess) │
│ React + Tailwind │◄──┤ die GANZE Arbeit │
│ zeigt an, sonst nichts │ │ ├─ Laufwerkswache (koffi/Win32) │
│ │ │ ├─ Ablauf-Steuerung │
│ kein Node-Zugriff │ │ ├─ Auftragstabelle (SQLite) │
│ (contextIsolation) │ │ └─ Werkzeuge als Kindprozesse: │
│ │ │ makemkvcon · HandBrakeCLI │
└──────────────────────────┘ └──────────────────────────────────┘
Warum drei und nicht einer:
- Ein Rip dauert 30–90 Minuten. Läuft er im Main-Prozess, friert die Oberfläche ein — Electrons eigene Dokumentation sagt das ausdrücklich.
- Der Kern darf abstürzen, ohne das Fenster mitzureißen. Dann steht dort „Der Kern ist abgestürzt, ich starte ihn neu" statt eines toten Fensters.
- Das Fenster darf zugehen, ohne den Rip zu beenden. Rippy lebt dann im Tray weiter — genau wie heute, nur ohne den Umweg über einen HTTP-Server.
Warum utilityProcess und nicht child_process.fork: Electrons eigene
Empfehlung. utilityProcess kann einen MessagePort direkt zum Renderer
aufbauen — der Fortschritt eines Rips geht damit ohne Umweg über den
Main-Prozess ins Fenster. Und § 3.4 hat gezeigt: node:sqlite steht genau
dort zur Verfügung.
Was es NICHT gibt: keinen HTTP-Server, keinen Port, kein localhost:7788,
keine REST-API, kein SSE. Fenster und Kern reden über Electrons IPC. Ein
lokaler Webserver in einer Einzelplatz-Anwendung ist eine offene Tür ohne
Gegenwert — und er war der Grund für das Rate-Limit, den Proxy-Kummer und die
Polling-Last im alten Rippy.
4.2 Ordner
rippy-windows/
├── package.json
├── electron.vite.config.ts
├── src/
│ ├── haupt/ Electron Main
│ │ ├── index.ts Start, Einzelinstanz-Sperre, Leine setzen
│ │ ├── fenster.ts Fenster anlegen, Zustand merken
│ │ ├── tray.ts Symbol + Kontextmenü
│ │ ├── autostart.ts HKCU\...\Run
│ │ └── update.ts electron-updater
│ │
│ ├── kern/ utilityProcess — die Arbeit
│ │ ├── laufwerk/
│ │ │ ├── win32.ts DER EINZIGE ORT MIT koffi
│ │ │ ├── wache.ts Einwurf/Auswurf erkennen (§ 5, Schritt 1)
│ │ │ └── disc.ts Typ, Label, Größe, TOC
│ │ ├── metadaten/
│ │ │ ├── tmdb.ts tvdb.ts omdb.ts musicbrainz.ts
│ │ │ ├── discmerkmale.ts Label + Laufzeiten + BDMV-Titel
│ │ │ └── zuordnung.ts Treffer + Sicherheitsgrad
│ │ ├── rip/
│ │ │ ├── makemkv.ts Kommandobau + Aufruf
│ │ │ ├── parser.ts TINFO/SINFO/PRGV/MSG (rein, testbar)
│ │ │ ├── audiocd.ts Roh-Sektoren + FLAC
│ │ │ └── iso.ts Datendiscs 1:1 sichern
│ │ ├── komprimieren/
│ │ │ ├── handbrake.ts Kommandobau + Aufruf + Fortschritt
│ │ │ ├── encoder.ts GEMESSEN, nicht behauptet
│ │ │ └── presets.ts
│ │ ├── ablage/
│ │ │ ├── struktur.ts Jellyfin/Emby/Kodi/Plex
│ │ │ ├── nfo.ts poster.ts medienserver.ts
│ │ ├── ablauf/
│ │ │ ├── pipeline.ts die Verkettung — NUR HIER
│ │ │ ├── zustand.ts Zustandsmaschine
│ │ │ └── auftraege.ts Warteschlange, Slots
│ │ ├── werkzeuge/
│ │ │ ├── katalog.ts wo liegt makemkvcon/HandBrakeCLI/flac
│ │ │ ├── beschaffen.ts holen, prüfen, einrichten
│ │ │ ├── schluessel.ts 4K-Schlüsselkette, Beta-Key samt Ablaufdatum (§ 9.1)
│ │ │ └── leine.ts Job Object (§ 3.3)
│ │ └── speicher/
│ │ ├── db.ts SQLite (node:sqlite — § 3.4 gemessen)
│ │ ├── einstellungen.ts EINE Quelle (§ 6.7)
│ │ └── bibliothek.ts
│ │
│ ├── gemeinsam/ Typen + Ereignis-Schema — Fenster UND Kern
│ └── fenster/ React
│
├── bau/ electron-builder, NSIS-Skript, Icon
└── test/ Vitest
4.3 Sechs Regeln, die den Aufbau tragen
Jede ist aus einem bezahlten Fehler abgeleitet. Sie sind mechanisch prüfbar und bekommen je einen Wächter-Test.
R1 — Win32 lebt nur in laufwerk/win32.ts.
Kein koffi-Import irgendwo sonst. Ein Wächter-Test greift bei jedem anderen
Fundort. (Grund: In v1 rief main.py eject() direkt auf — deshalb brauchte
der API-Container Geräte-Zugriff und SYS_ADMIN.)
R2 — Ein Fehlschlag löscht nie einen Zustand.
Kein catch { return [] }. Wer nichts Neues weiß, behält, was er wusste.
(Grund: Fünfmal catch(() => []) im alten UI — jeder verpasste Abruf hieß
„es gibt keine Jobs", die Liste leerte sich im Sekundentakt. Der Commander
meldete es als „wird oft neu geladen".)
R3 — Auswerfen heißt: entriegeln, auswerfen, nachsehen.
In dieser Reihenfolge. Kein Rückgabewert gilt als Beweis. (Grund: CDROMEJECT
quittiert auf einem verriegelten Laufwerk Erfolg und tut nichts. MakeMKV
verriegelt die Tür während des Rips.)
R4 — Jede Hintergrundschleife meldet ihren Fehler.
Kein stilles catch {}. (Grund: Ein except Exception: pass in einer
Vorrats-Schleife hat einmal eine Stunde gekostet.)
R5 — Externe Schnittstellen werden gemessen, nicht erinnert.
Jeder Kommandozeilen-Schalter, jeder IOCTL-Code trägt im Kommentar, wo er
herkommt. (Grund: --audio-codec gibt es bei HandBrakeCLI nicht — es heißt
-E/--aencoder. Ein unbekannter Schalter ist für HandBrake kein Fehler:
Rückgabewert 0. Das kostete einen fertigen 16,5-GB-Rip, und ein Test hatte den
Fehler festgeschrieben statt ihn zu finden.)
R6 — Alles läuft an der Leine. Jeder Werkzeugaufruf hängt in der Arbeitsgruppe aus § 3.3. Ausgenommen ist nur das Aufräum-Skript der Deinstallation — es muss Rippy überleben.
5. Der Ablauf — was passiert, wenn eine Disc reingeht
Der rote Faden des Commanders: so viel Arbeit abnehmen wie möglich.
1. Disc rein
│ Wache im 3-Sekunden-Takt (IOCTL_STORAGE_CHECK_VERIFY2 — § 3.2)
│ Verfeinerung später: WM_DEVICECHANGE-Ereignis (siehe unten)
▼
2. Was ist das?
│ Größe (33,76 GB → Blu-ray) · Audio-TOC? · Dateisystem lesbar?
│ → Film / Serie / Musik / Daten
▼
3. Was ist da drauf? ← DER SCHRITT, DER HEUTE ZU DÜNN IST
│ Disc-Label · Titel-Laufzeiten · BDMV-Titel · DVD-IFO · CD-DiscID
│ → TMDb / TVDb / OMDb / MusicBrainz
│ → Treffer mit SICHERHEITSGRAD
▼
4. Sicher genug?
│ ja → sofort losrippen, nur Bescheid sagen (Zero-Click)
│ nein → fragen: Fenster hoch, Vorschläge zur Wahl
▼
5. Rippen makemkvcon, verlustfrei, Fortschritt aus PRGV
▼
6. Komprimieren HandBrakeCLI, Encoder GEMESSEN, Preset je Disc-Typ
▼
7. Ablegen Zielstruktur · NFO · Poster/Fanart
▼
8. Melden Medienserver anstoßen · Benachrichtigung · Auswerfen
▼
9. Merken Bibliothek fortschreiben — beim nächsten Mal erkannt
▼
Warum der Takt Plan A ist und das Ereignis nicht. Die erste Fassung
versprach „Ereignis, kein Poll" — die Prüfung hat die Reihenfolge umgedreht.
WM_DEVICECHANGE ist eine Fenster-Nachricht: Sie wird nur an Fenster mit
Nachrichtenschleife zugestellt, und der Kern hat keines. Beide Auswege sind
machbar, aber krumm — entweder fängt der Main-Prozess die Nachricht am
Fenster ab und muss dann die Frage „welches Laufwerk?" aus einer
Zeiger-Struktur klauben, oder der Kern baut sich per koffi ein unsichtbares
Nachrichten-Fenster samt eigener Schleife. Der 3-Sekunden-Takt dagegen ist
eine Zeile (IOCTL_STORAGE_CHECK_VERIFY2, in § 3.2 gemessen, praktisch
kostenlos), und bei einem Vorgang, der 30–90 Minuten dauert, sind drei
Sekunden Erkennungsverzögerung bedeutungslos. Also: Takt zuerst, Ereignis
als spätere Verfeinerung — und wenn das Ereignis kommt, bleibt der Takt als
Rückfallebene bestehen, falls die Nachricht ausbleibt.
Was an Schritt 3 neu ist. Heute nimmt Rippy im Wesentlichen das Disc-Label und die längste Laufzeit. Das reicht bei „PIRATES_OF_THE_CARIBBEAN", aber nicht bei „LOGICAL_VOLUME_ID" — und dann fragt Rippy, obwohl die Antwort auf der Disc steht. Vier Quellen kommen dazu:
| Quelle | Wo | Was sie liefert |
|---|---|---|
| BDMV-Metadaten | BDMV/META/DL/bdmt_*.xml auf der Blu-ray |
Der vom Studio hinterlegte Disc-Titel, oft mit Sprachvarianten. Deutlich besser als das Volume-Label. |
| Titel-Struktur | makemkvcon info |
Die Anzahl und Länge der Titel ist ein Fingerabdruck: 1 langer + viele kurze = Film; 6–13 gleich lange = Serienstaffel. |
| DVD-Struktur | VIDEO_TS, IFO-Dateien |
Kapitelzahl und Titelsatz-Aufbau |
| CD-DiscID | Audio-TOC | Bereits gebaut und bewiesen (rc8): Spurlage → MusicBrainz → Album, Interpret, Jahr, jeder Titel. |
Dazu ein Sicherheitsgrad, der ehrlich ist. Rippy sagt nicht „das ist Akira", sondern „das ist sehr wahrscheinlich Akira (1988)" — und fragt nur, wenn es das nicht sagen kann. Die Schwelle ist einstellbar; wer will, lässt Rippy immer fragen, und wer will, lässt es immer durchlaufen.
Und wenn Rippy sich irrt: Der Titel lässt sich nachträglich ändern, und die Ablage wandert mit. Das ist der Unterschied zwischen „falsch geraten" und „falsch abgelegt".
6. Die Features
6.1 Automatische Erkennung (§ 5, Schritt 2–4)
Siehe oben. Kernsatz: Rippy fragt nur, wenn es wirklich nicht weiß.
6.2 Rippen
makemkvcon im Robot-Modus (--robot --messages=-stdout --progress=-same),
verlustfrei. Der Parser (TINFO/SINFO/PRGV/MSG) wandert aus dem Python-Code
nach TypeScript — er ist reine Textverarbeitung und damit vollständig
testbar, ohne Laufwerk.
Was aus dem alten Rippy zwingend mitkommt:
- Lesefehler heißen Lesefehler. MakeMKV kann 1 von 2 Titeln sichern und sich trotzdem mit 0 beenden. Rippy warnt nach dem Rip — auch und gerade dann, wenn er als Erfolg endete — und nennt die MSG-Nummer: MakeMKVs Texte sind übersetzt, die Nummern nicht.
- Erst nachsehen, dann rippen. Liegt keine Disc drin, sagt Rippy das in einem Satz, statt zwei Minuten in makemkvcon zu laufen und mit Code 11 zu enden. Aber: Wenn das Nachsehen selbst scheitert, wird trotzdem gerippt — „ich weiß es nicht" darf nie zu „es geht nicht" werden.
- Die Ausgabe binär lesen. makemkvcon mischt Kodierungen; ein
üim Pfad hat die Kompression einmal getötet (UnicodeDecodeErrorauf Byte 0x81).
6.3 Audio-CDs
Der Weg aus rc8, bewiesen: Roh-Sektoren über Win32 lesen (eine Audio-CD hat
kein Dateisystem — die Track01.cda sind 44-Byte-Platzhalter), dann durch
flac.exe. Dazu MusicBrainz über die DiscID.
Zwei Fallen, beide gemessen und beide dokumentiert: Die DiscID rechnet mit den 150 Frames Vorlauf, das Lesen ohne. Und die Leseadresse zählt in 2048er-Einheiten, obwohl ein Audio-Sektor 2352 Bytes hat.
6.4 ISO-Backup für Datendiscs (neu)
Die einzige echte Lücke gegenüber ARM. Wird eine Disc weder als Film noch als
Musik erkannt, wird sie 1:1 gesichert statt abgelehnt: sequenziell aus
\\.\G: lesen, Länge aus IOCTL_DISK_GET_LENGTH_INFO (in § 3.2 gemessen:
liefert exakte Bytes). Kein Fremdwerkzeug nötig.
6.5 Mehrere Laufwerke gleichzeitig (neu)
Laufwerke sind eigenständige Objekte mit stabiler Kennung (Seriennummer, nicht
Buchstabe — 0025114C0149 in § 3.2 gemessen). Ein Rip-Auftrag belegt genau
ein Laufwerk; die Zahl gleichzeitiger Rips und Kompressionen ist einstellbar.
⚠️ Annahme, zu messen bevor sie festgeschrieben wird: Mehrere
makemkvcon-Prozesse teilen sich ein Datenverzeichnis (_private_data.tar,settings.conf). Der Entwurf sieht deshalb vor: Rip-Phase parallel, Schlüssel-Phase serialisiert. Das ist aus der Aktenlage abgeleitet, nicht gemessen — und gehört an zwei Laufwerken geprüft, bevor die Grenze im Code steht.
6.6 Bibliothek (neu)
Eine Ansicht über alles Gerippte: Cover, Größe, Datum, Ablageort, Dauer des Vorgangs. Und der praktische Teil: Rippy erkennt beim Einlegen, wenn eine Disc schon einmal durchgelaufen ist (über die Disc-Merkmale aus § 5) und fragt nach, statt stumm zu doppeln.
6.7 Arbeitsverzeichnis und Ablage — eine Quelle
Der Fund aus rc11: Die Oberfläche schrieb in die Datenbank, der Betrieb las
aus einer Konfigurationsdatei, die niemand schrieb. Eingestellt E:\Rippy,
angezeigt C:\Users\...\Videos\Rippy.
In v5 gibt es genau einen Speicher für Einstellungen (speicher/einstellungen.ts,
SQLite). Ein Wächter-Test prüft mechanisch, dass kein zweiter Ort entsteht.
Dazu die Pfad-Regeln aus rc11, als reine Funktionen mit Tests:
- Eine Laufwerkswurzel behält ihren Trenner (
F:\, nichtF:) - UNC-Wurzeln bleiben absolut
- Verzeichnisprüfungen sind windows-nativ — kein
timeout ls -d - Pro Rip darf ein anderes Arbeitsverzeichnis gewählt werden, und gesucht wird später unter der Wahl des Jobs, nicht unter der heutigen Einstellung
6.8 Selbst-Update (neu)
electron-updater gegen die Releases im öffentlichen Gitea (Entscheid 6).
Rippy prüft beim Start und danach täglich, lädt im Hintergrund und installiert
beim nächsten Start — nie mitten in einem Rip.
Die Quelle steht in der Konfiguration und ist vorbelegt. Ein nicht erreichbarer Update-Server ist kein Fehler, sondern eine Zeile im Protokoll — das gilt ausdrücklich auch, wenn das Heimnetz des Commanders gerade nicht antwortet.
Vier Regeln, die zum Entscheid gehören:
- Nur HTTPS. Ohne Code-Signing (Entscheid 5) kann
electron-updaterein heruntergeladenes Update nicht auf Echtheit prüfen — die Absicherung liegt damit ganz beim Transportweg. Einehttp://-Update-Adresse wird abgelehnt, nicht stillschweigend akzeptiert. (Die Prüfsumme auslatest.ymlsichert nur die Übertragung — sie kommt über denselben Kanal wie die Datei und ist deshalb kein Ersatz für den sicheren Kanal selbst.) - Nie während eines Rips. Weder herunterladen noch installieren. Ein Neustart mitten in einem 90-Minuten-Rip wäre der teuerste Fehler, den ein Update-Mechanismus machen kann.
- Ein Fehlschlag ist sichtbar, aber nicht laut. Die Prüfung darf still scheitern (WLAN weg, Server aus) — aber der Zeitpunkt der letzten erfolgreichen Prüfung steht im Über-Dialog. Wer nie prüft, weiß sonst nicht, dass er nie prüft.
- Die Version, die läuft, ist ablesbar. Im Fenster und im Protokollkopf. Eine Fehlermeldung ohne Versionsnummer ist bei einem sich selbst aktualisierenden Programm die halbe Miete verloren.
Und eine Pflege-Regel, die das Selbst-Update erst wertvoll macht: Electron bringt etwa alle acht Wochen eine neue Hauptversion und pflegt nur die letzten drei — wer stehen bleibt, sitzt nach rund einem halben Jahr auf einem Chromium mit bekannten Sicherheitslücken. Deshalb: Bei jedem Rippy-Release wird geprüft, ob ein Electron-Sprung ansteht. Das Verteilen kostet dank Selbst-Update nichts; das Nicht-Verteilen kostet irgendwann Vertrauen.
6.9 Erst-Einrichtung (neu gedacht)
Der Befund des Commanders zur heutigen Fassung: „Dann hätte ich beim Setup auch erwartet, dass ein echtes Setup passiert — wo will ich das hinspeichern, ein Pre-Requirement-Check usw. Da kommt gar nichts, Rippy geht einfach auf."
Der Assistent läuft nach der Installation, im Programm selbst, in fünf Schritten:
| Schritt | Was passiert |
|---|---|
| 1 Willkommen | Was Rippy tut, in vier Sätzen |
| 2 Prüfung | Laufwerke · Werkzeuge · Plattenplatz · Internet · WebView2 — jeder Befund sagt, was zu tun ist |
| 3 Werkzeuge | Was fehlt, wird geholt (§ 9) — mit Fortschritt, nicht mit einem eingefrorenen Fenster |
| 4 Ordner | Ablage und Arbeitsverzeichnis, mit echten Windows-Ordnerdialogen und Platzanzeige |
| 5 Automatik | Wie viel soll Rippy allein entscheiden? Je Disc-Typ einstellbar. |
Zwei Regeln, die aus dem alten Setup übernommen werden:
- Nur ein Fehler blockiert. Eine Warnung, die den Knopf sperrt, ist Bevormundung; ein Fehler, der nur warnt, ist eine Falle. Kein optisches Laufwerk ist eine Warnung — eine reine Komprimier-Maschine ist ein vorgesehener Betriebsfall.
- Ein Setup meldet nie Erfolg, während ein Pflichtwerkzeug fehlt. Der Bestand wird VOR und NACH dem Versuch gelesen; berichtet wird, was danach wirklich da ist.
6.10 Was unverändert erhalten bleibt
Alles, was der Commander heute benutzt:
Kompression je Disc-Typ abwählbar (4K verlustfrei durchreichen) · Preset-Wahl je Typ · Sprachwahl für Ton und Untertitel vor dem Rip · Original behalten · Vollautomatik · Nur-Hauptfeature · automatischer Auswurf · Medienserver-Refresh (Jellyfin/Emby/Plex/Kodi) · NFO + Poster + Fanart · Serien-Staffelablage mit Episoden-Zuordnung per Laufzeitabgleich (nur bei eindeutiger Zuordnung wird umbenannt) · Webhook-Benachrichtigungen (Discord/Slack/ntfy/generisch) · Live-Log · Job-Detailansicht · Wiederholen ab Rip oder ab Kompression · 4K-Schlüsselkette in drei Stufen · Restzeit-Schätzung.
7. Die Oberfläche
Entscheid: Neu bauen, Look behalten.
Wiedererkennbar bleibt die Design-Sprache — dunkel/hell, die Kachel-Anordnung, das Kino-Banner, die Farbwelt. Neu ist, dass die Oberfläche eine Einzelplatz-Anwendung bedient statt eines Docker-Clusters.
Was verschwindet: Worker-Verwaltung · Container-Platte · „Prüfen:
docker compose ps" · Speicherziele-Einhängen · Pfad-Map · Worker-Setup-Paket ·
Encoder-Auswahl je Knoten · alles, was einen zweiten Rechner voraussetzt.
Was dazukommt:
- Echte Windows-Ordnerdialoge statt eines nachgebauten Dateibrowsers im Web. Das ist ein spürbarer Unterschied im Alltag: Der Nutzer sieht seine Netzlaufwerke, seine Schnellzugriffe, seine gewohnte Oberfläche.
- Tray-Symbol mit Zustand — auf einen Blick: läuft ein Rip, wie weit, wie lange noch. Rechtsklick: Öffnen, Pause, Beenden.
- Windows-Benachrichtigungen (echte Toasts, nicht Browser-Popups), mit Klick direkt in den Job.
- Fortschritt in der Taskleiste — Windows kann einen Fortschrittsbalken über dem Symbol zeigen. Bei einem 90-Minuten-Rip ist das genau die Information, die man will, ohne das Fenster zu öffnen.
- Die Bibliothek als eigene Ansicht (§ 6.6).
Was die Oberfläche NIE tut: Eine Liste auf leer setzen, weil eine Nachricht ausblieb (R2). Bei einem Aussetzer bleibt der letzte Stand stehen, und ein Banner sagt, dass gerade nichts Neues kommt.
8. Setup, Autostart, Deinstallation
Entscheid: pro Benutzer, ohne Administratorrechte, Windows 10 (ab 1809) und 11, x64.
| Installer | electron-builder → NSIS, ein RippySetup.exe |
| Ziel | %LOCALAPPDATA%\Programs\Rippy — kein UAC-Dialog |
| Autostart | HKCU\Software\Microsoft\Windows\CurrentVersion\Run |
| Update | electron-updater, NSIS-Ziel (§ 6.8) |
| Deinstallation | Über die Windows-Programmliste, räumt wirklich auf |
Zu Windows 10, tagesaktuell eingeordnet: Die Verbraucher-Sicherheitsupdates (ESU) enden im Oktober 2026, die Chromium-Familie läuft auf Windows 10 aber erklärtermaßen weiter (Edge/WebView2 bis mindestens Oktober 2028). Electron 44 läuft dort. Für Rippy heißt das: bauen ja, und ein Satz in der Anleitung, dass Windows 10 selbst ausläuft — mehr nicht.
Warum kein Windows-Dienst: Ein Dienst startet vor der Anmeldung — klingt besser, kostet aber bei jeder Installation und jedem Update eine Administrator-Abfrage, und er kann kein Tray-Symbol zeigen (keine Benutzersitzung). Für einen Rechner, an dem jemand sitzt und Discs einlegt, ist der Autostart-Eintrag der richtige Weg.
Drei Dinge, die aus den alten Fehlern übernommen werden:
- Drüber-Installieren funktioniert. Rippy läuft fast immer (Autostart) —
der Installer beendet die laufende Fassung, bevor er kopiert. Sonst landet
die neue Version als
Rippy.exe.neudaneben. (Genau das ist passiert.) - Die Deinstallation räumt die WebView-Reste weg. Beim letzten Mal blieben 148 Dateien liegen, weil die Renderer-Hilfsprozesse den Zwischenspeicher offen hielten — und der Deinstallierer meldete trotzdem „Rippy wurde entfernt."
- Das Aufräum-Skript darf keine Laufwerkswurzel löschen. Wenn der Installationsort aus der Registry eine Wurzel wäre, löschte die Deinstallation das Laufwerk. Nicht beobachtet — aber nicht wiedergutzumachen.
Zum SmartScreen-Hinweis beim ersten Start und zur Update-Folge der fehlenden Signatur: beides steht bei Entscheid 5 — die Anleitung erklärt den Weg, das Release nennt Größe und Prüfsumme, und Updates laufen nur über HTTPS (§ 6.8).
9. Die Werkzeuge
Der Entscheid vom 28.08.2026 gilt unverändert: „handbrake und makemkv MÜSSEN mitgeliefert werden oder während des Setups separat installiert werden." Die Wege unterscheiden sich, und der Grund ist die Lizenz, nicht die Bequemlichkeit.
| Weg | Warum | |
|---|---|---|
| HandBrakeCLI | mitgeliefert (~35 MB) | GPL-2 erlaubt die Weitergabe, solange Lizenztext und Quellverweis dabei sind. Damit komprimiert Rippy auch ohne Internet. |
| FLAC | mitgeliefert (~2 MB) | Xiph-Lizenz (BSD-artig), Weitergabe erlaubt. ⚠️ flac.exe braucht libFLAC.dll daneben — mit nur der EXE endet jeder Aufruf ohne eine Zeile Ausgabe. |
| MakeMKV | beim Einrichten geholt | Proprietär — die Lizenz erlaubt Dritten keine Weitergabe. Rippy lädt die offizielle Datei vom Hersteller und startet dessen Installer. |
Die Lizenztexte und Quellverweise für HandBrake und FLAC liegen dem Setup bei — wegen Entscheid 9 wird die EXE weitergegeben, und damit ist das Pflicht, nicht Kür.
Die Bezugskette für MakeMKV (aus dem 28.08.-Entscheid, unverändert): eigene Quelle → Hersteller-Seite → Hersteller-Forum → Internet Archive. Mit zwei Feinheiten, beide gemessen: Die höchste Versionsnummer gewinnt, nicht die erste (das Archiv meldet sonst 1.18.2 statt 1.18.4), und jeder Versuch bekommt eine knappe Zeitgrenze (8 s), weil das Forum in zwei von drei Abrufen ausfiel.
MakeMKV signiert seinen Installer nicht (NotSigned, an der echten Datei
gemessen) — geprüft wird deshalb die Versions-Ressource
(CompanyName: GuinpinSoft inc). Das ersetzt keine Signatur, fängt aber ab,
was hier wirklich droht: eine Fehlerseite mit .exe-Namen, ein abgebrochener
Download, eine falsche Fassung.
9.1 Der Beta-Key — ein Termin, kein Detail
MakeMKVs freier Beta-Key ist bis Ende September 2026 gültig. Die Kaufseite für die Dauerlizenz ist defekt — der Hersteller verweist selbst auf den Beta-Key. (Am 30.08.2026 gegen Forum und Fachpresse geprüft.)
Zur Einordnung, die in der ersten Fassung fehlte: Das ist kein frischer Unfall, sondern ein Dauerzustand seit Sommer 2025 — das Kaufsystem fällt seither immer wieder aus, und der Beta-Key wurde bisher stets kurz vor Ablauf verlängert (zuletzt Anfang August 2026, gültig bis Ende September). Rippy plant also nicht für eine einmalige Panne, sondern für einen Rhythmus. Das Restrisiko — der Hersteller verschwindet ganz — kann kein Programm der Welt auffangen; was ein Programm auffangen kann, ist das Überraschtwerden:
- Der Key wird automatisch geholt (wie heute) — aus dem Forum-Thread, in dem der Hersteller ihn veröffentlicht.
- Rippy zeigt das Ablaufdatum im Dashboard und warnt sieben Tage vorher — statt dass ein Rip mitten in der Nacht scheitert und niemand weiß, warum. Ohne gültigen Key geht keine Blu-ray und keine 4K-Disc mehr auf; DVDs laufen weiter.
- Ein abgelaufener Key ist eine klare Meldung, kein rätselhafter MakeMKV-Fehlercode.
- Ein eingetragener Dauerlizenz-Schlüssel schlägt alles. Wer eine Lizenz hat, trägt sie ein und ist raus aus dem Thema.
10. Was aus dem alten Rippy mitkommt
Kein Code. Aber jede teuer bezahlte Erkenntnis.
Das ist der Kern des Grüne-Wiese-Ansatzes: Der Python-Code wird nicht portiert, aber er ist die beste verfügbare Dokumentation darüber, wie sich MakeMKV, HandBrake und Windows-Laufwerke wirklich verhalten. Diese Tabelle ist die Arbeitsliste für den Neubau.
| Herkunft | Was übernommen wird | Wohin |
|---|---|---|
ripping.py |
TINFO/SINFO/PRGV/MSG-Parser, Kommandobau, laengster_titel, episoden_titel, Sprach-Zusammenfassung |
rip/parser.ts, rip/makemkv.ts |
win_ioctl.py |
Die hergeleiteten Steuercodes samt Herleitung — in § 3.2 aus Node bestätigt | laufwerk/win32.ts |
windows.py, winlauf.py |
Zugriffsgründe je Fehlernummer, CREATE_NO_WINDOW, Standby verhindern, die Prozess-Leine |
laufwerk/, werkzeuge/leine.ts |
caps.py |
Encoder messen statt behaupten (HandBrakeCLI --help auswerten) |
komprimieren/encoder.ts |
handbrake_aufruf.py |
--aencoder (nicht --audio-codec), Container aus dem Preset erzwingen, letzte 12 Zeilen puffern, unknown option-Erkennung |
komprimieren/handbrake.ts |
medien.py |
Zielstruktur, NFO-Schema, Episoden-Zuordnung per Laufzeit, Medienserver-Refresh | ablage/ |
prescan.py, clients/* |
TMDb/TVDb/OMDb/MusicBrainz/Jikan-Abfragen, Zwischenspeicher, Confidence | metadaten/ |
pfade.py |
Laufwerkswurzeln, UNC, naechster_vorhandener ohne Endlosschleife |
speicher/pfade.ts |
musicbrainz_cd.py, audio_cd.py |
DiscID-Rechnung (mit/ohne 150 Frames), 2048-vs-2352-Falle | rip/audiocd.ts |
makemkv_daten.py |
Die 4K-Schlüsselkette: Beta-Key-Abruf aus dem Forum-Thread, Schlüsselspeicher (_private_data.tar), KEYDB als Notnagel — samt der dort dokumentierten Fehldiagnosen |
werkzeuge/schluessel.ts |
presets.py, eta.py, phasen.py |
Preset-Zuordnung je Disc-Typ, Restzeit, Phasenmodell | komprimieren/, ablauf/ |
beschaffen.py, katalog.py |
Suchreihenfolge für Werkzeuge, Registry-Auswertung, Ausweichquellen | werkzeuge/ |
AGENTS.md |
Die sechs Regeln aus § 4.3 | Wächter-Tests |
Die Tests wandern sinngemäß mit. Von den 977 heutigen Tests ist der größte Teil reine Textverarbeitung (Parser, Pfade, Kommandobau) — die Testfälle gelten unverändert, nur die Sprache wechselt. Das ist kein Nebeneffekt, sondern die Absicherung: Ein neu geschriebener Parser, der dieselben Testfälle besteht wie der alte, hat dieselben Fallen abgedeckt.
11. Was aus main entfernt wird
Entscheid 7 — und zwar sofort. Die Arbeit gehört in den main-Branch,
nicht hierher — dieser Abschnitt ist die Arbeitsliste dafür, damit sie nicht
aus dem Gedächtnis gemacht wird.
11.1 Der Windows-Anteil in main sind DREI Dinge, nicht eins
Diese Unterscheidung ist der ganze Abschnitt. Wer sie überspringt, löscht entweder zu wenig oder reißt die Docker-Version mit.
Zuerst in Klartext, ohne Dateinamen:
A ist Rippy. B ist ein Handlanger für die VM. C sind Notizzettel, die wegen A eingeklebt wurden.
A — „Rippy" auf einem Windows-PC. Das Programm, das man heute kennt:
RippySetup.exe, Doppelklick, Symbol in der Taskleiste, ein Fenster geht auf.
Disc rein, Rippy erkennt sie, rippt, komprimiert, legt ab. Ein vollständiges
Rippy, das alles allein macht. Genau das wird durch v5 ersetzt.
B — „Rippy Worker" auf einem Hilfsrechner. Ein anderes Programm,
RippyWorkerSetup.exe. Es rippt nichts und hat keine Bedienoberfläche.
Beim Installieren fragt es drei Dinge: IP der Rippy-VM? Name dieses Helfers?
Wie viele Kerne? Danach wartet es. Will die Docker-Rippy auf der VM einen
Film komprimieren und ist selbst zu langsam, schickt sie die Arbeit dorthin.
VM (Docker-Rippy) Ein Windows-PC
├─ Disc einlesen
├─ rippen
└─ komprimieren? zu langsam ──────► B: „Rippy Worker"
komprimiert und
Ergebnis ◄───────────────────── schickt zurück
B läuft nur zufällig auf Windows — es gehört zur Docker-Welt. Entscheid 8: B bleibt bei Docker — es wird weder abgeräumt (es ist Docker, und Docker bleibt unangetastet) noch nach v5 übernommen (v5 ist Einzelplatz, Entscheid 3 — es gibt dort keinen zweiten Knoten, dem man etwas schicken könnte).
C — Notizzettel im Docker-Code. Keine eigenen Dateien, sondern verstreute Stellen mitten in Dateien, die Docker jeden Tag benutzt, wo jemand schrieb: „falls wir gerade auf Windows laufen, mach es anders". Eingebaut wurden sie, damit A funktioniert.
Der Unterschied zwischen A und C ist nicht der Inhalt, sondern der Ort:
| Bild | Aufräumen heißt | |
|---|---|---|
| A | Ganze Ordner, auf denen „Windows" steht. Docker schlägt sie nie auf. | Ordner wegwerfen. Ganze Dateien löschen, fertig. |
| C | Einzelne Seiten mit Windows-Notizen, die in Ordnern liegen, die Docker täglich benutzt. | Seiten einzeln durchgehen. Die Datei bleibt, ein paar Zeilen gehen — und bei jeder Zeile ist zu prüfen, ob wirklich nur A sie brauchte. |
Deshalb ist C der heikle Teil: Erwischt man eine Zeile, die Docker doch
braucht, geht auf der VM etwas kaputt. Und manche Windows-Zeile braucht sogar
B weiter — etwa die Regel, dass eine Laufwerkswurzel F:\ mit Trenner
geschrieben werden muss (§ 1). Der Handlanger läuft ja auf Windows.
In Dateien ausgedrückt:
| Was es ist | Schicksal | |
|---|---|---|
| A | Die Standalone-App — PyInstaller-Setup, Tray, WebView2-Fenster, Einrichtungs-Assistent, lokale Queue, Werkzeug-Beschaffung, Win32-Treiber | weg — v5 ersetzt sie |
| B | Der Remote-Encode-Worker — deploy/worker-windows/, /worker-setup/*, Pfad-Map |
bleibt |
| C | Windows-Zweige im Docker-Code — die os.name == "nt"-Stellen in main.py, betrieb.py, ablauf.py, rohdaten.py, dazu die Fähigkeiten-Auskunft im UI |
einzeln prüfen |
11.2 Teil A — die Standalone-App (weg)
src/rippy/windows_app.py Installer, Dienst, Deinstallation
src/rippy/fenster.py WebView2-Fenster
src/rippy/setup_fenster.py Einrichtungs-Assistent
src/rippy/einrichtung.py Voraussetzungs-Prüfungen
src/rippy/standalone.py lokale Zustellung statt Celery
src/rippy/drives/windows.py Win32-Laufwerkstreiber
src/rippy/drives/win_ioctl.py die Steuercodes
src/rippy/platform/winlauf.py CREATE_NO_WINDOW, Waisen, Job Object
src/rippy/platform/win_registry.py
src/rippy/platform/verknuepfungen.py
src/rippy/platform/dateiangaben.py
src/rippy/tools/ Werkzeug-Katalog + Beschaffung (Windows-only)
src/rippy/rip/audio_cd.py Audio-CD über Win32
src/rippy/rip/musicbrainz_cd.py DiscID-Rechnung
packaging/windows/ der PyInstaller-Bau
dist/windows/ die gebaute EXE + vendor/
+ die zugehörigen test_*.py
Dazu: src/rippy/queue/lokal.py und queue/laeufer.py (die lokale Queue hat
außerhalb der Standalone-App keinen Aufrufer) und bus/waechter.py, soweit er
nur die Windows-Disc-Wache bedient.
Die Steuercodes und Parser sterben nicht — sie sind bereits nach v5
übernommen (§ 3.2 hat sie aus Node bestätigt, § 10 listet den Rest). Was
gelöscht wird, ist die Python-Fassung, nicht das Wissen. Wichtig fürs
Löschen von makemkv_daten.py-Verwandten: Die Schlüsselketten-Erkenntnisse
(§ 10) VOR dem Löschen in v5-Notizen sichern, falls W-7 noch nicht begonnen
hat — das Wissen darf nicht nur im Git-Verlauf liegen.
11.3 Teil C — die verstreuten Zweige (einzeln prüfen)
Hier ist blindes Löschen gefährlich, weil manches auch ohne die Standalone-App gebraucht wird — vom Remote-Worker (Teil B) oder von der Pfad-Behandlung allgemein.
| Fundort | Prüfen |
|---|---|
docker/api/main.py — betrieb.windows_laufwerke(), die Browse-Sonderfälle, /betrieb-Fähigkeiten |
Die Fähigkeiten-Auskunft bleibt sinnvoll (Docker-AiO vs. verteilt), nur die Windows-Werte fallen weg |
src/rippy/betrieb.py |
Ganz raus oder auf Docker-Fälle eindampfen |
docker/worker/ablauf.py, rohdaten.py |
Die Windows-Pfadzweige raus — aber nativ_nachsehen() prüfen: gilt es auch für den Remote-Worker? |
docker/api/rohdaten.py, mounts.py |
dito |
src/rippy/pfade.py |
Bleibt. Laufwerkswurzeln und UNC braucht auch der Remote-Worker |
UI: useBetrieb, WorkerVerwaltung, Anleitung, Settings |
Nur die Standalone-Texte raus; die Worker-Verwaltung bedient Teil B |
src/rippy/test_keine_container_reste.py |
Der Wächter-Test wird gegenstandslos — mit weg |
11.4 Wie das gemacht wird
- Jetzt, nicht erst wenn v5 steht. Commander-Entscheid vom 30.08.2026 (zweite Fassung): Das Aufräumen wartet nicht auf Etappe W-6. Die Konsequenz steht bei Entscheid 7 — zwischen Aufräumen und W-6 liefert das Repo kein installierbares Windows-Rippy; die installierte rc11-Fassung läuft lokal weiter, bekommt aber keine Reparaturen mehr.
- Ein eigener Branch, nicht direkt auf
main. Der Umfang ist zu groß für einen Freihand-Commit. - In der Reihenfolge A → C → (B bleibt). Erst die eindeutigen Dateien, dann die verstreuten Zweige — sonst sucht man Aufrufer, die es noch gibt.
- Die Ampel nach jedem Schritt.
AGENTS.mdRegel A gilt unverändert; ein Aufräumen, das die Tests rot macht, ist nicht fertig, sondern angefangen. - Ein SAVEPOINT-Eintrag dazu, mit der Zahl der entfernten Zeilen und dem Hinweis, wo das Wissen jetzt liegt.
12. Etappen
Grundregel: Jede Etappe endet mit grüner Ampel und einem Programm, das man starten kann. Kein großer Umbau, nach dem monatelang nichts geht.
Parallel dazu, unabhängig von den Etappen: das Aufräumen von main
(§ 11.4) — es startet sofort und braucht auf nichts hiervon zu warten.
| # | Titel | Inhalt | Fertig, wenn |
|---|---|---|---|
| W-0 | Gerüst | Electron 44 + TypeScript + Vite + Vitest, drei Prozesse, IPC, node:sqlite anbinden (§ 3.4 — bereits bewiesen), Prozess-Leine, CI-Ampel, npm-Skript-Sperre in der Bau-Anleitung (§ 3.5) |
Ein Fenster geht auf, der Kern läuft, ein Testlauf ist grün |
| W-1 | Laufwerk | laufwerk/win32.ts aus dem § 3.2-Beweis, Wache im 3-Sekunden-Takt (§ 5), Disc-Typ, Verriegeln, Auswerfen mit Nachsehen |
Disc rein → Rippy sagt korrekt, was es ist. Auswerfen wirkt (nachgemessen, nicht geglaubt) |
| W-2 | Rippen | makemkvcon-Aufruf, Parser, Fortschritt, Abbruch, Lesefehler-Warnung, Werkzeug-Beschaffung | Eine DVD und eine Blu-ray laufen durch, verlustfrei |
| W-3 | Komprimieren + Ablegen | HandBrake, Encoder gemessen, Presets, Zielstruktur, NFO, Poster, Medienserver | Ein Film liegt fertig in Jellyfin und ist dort sichtbar |
| W-4 | Metadaten-Automatik | Die vier Quellen aus § 5, Sicherheitsgrad, Nachkorrektur | Fünf verschiedene Discs richtig erkannt, ohne Nachfrage |
| W-5 | Oberfläche | Dashboard, Einstellungen, Logs, Bibliothek, Tray, Windows-Toasts, Taskleisten-Fortschritt | Der Commander bedient Rippy einen Abend lang ohne Rückfrage |
| W-6 | Setup + Update | NSIS, Autostart, Erst-Einrichtung, Selbst-Update gegen das öffentliche Gitea (inkl. Messung der Fest-Adresse für latest.yml, Entscheid 6), Lizenztexte beilegen (Entscheid 9), Deinstallation |
Frischer Rechner: Setup → Disc rein → MKV raus. Und: drüber-installieren geht |
| W-7 | Der Rest | Audio-CD, ISO-Backup, mehrere Laufwerke, 4K-Schlüsselkette (werkzeuge/schluessel.ts), WM_DEVICECHANGE als Wache-Verfeinerung (§ 5) |
Je Feature ein Nachweis |
Reihenfolge-Begründung: W-1 bis W-3 sind die Kette, ohne die Rippy nichts tut. W-4 und W-5 machen sie bequem. W-6 macht sie weitergebbar. W-7 sind die Ergänzungen, die ohne die Kette keinen Sinn hätten.
13. Risiken und offene Punkte
| Risiko | Bewertung | Behandlung |
|---|---|---|
| MakeMKV-Beta-Key läuft Ende September 2026 ab | hoch × sicher | § 9.1 — Ablaufdatum sichtbar, Warnung 7 Tage vorher, klare Meldung, Dauerlizenz eintragbar. Einordnung: Dauerzustand seit Sommer 2025, der Key wurde bisher stets verlängert. Bleibt der akuteste Termin im Dokument. |
| Kein installierbares Windows-Rippy zwischen Aufräumen und W-6 | sicher × akzeptiert | Folge von Entscheid 7 („sofort"). Die installierte rc11-EXE läuft lokal weiter; die Docker-Version deckt die VM ab. Bewusst bezahlter Preis |
| Neubau dauert länger als eine Reparatur | sicher | Deshalb Entscheid 2: Die Docker-Version läuft weiter. Es entsteht keine Lücke auf der VM |
| Electron-Paket ~150–200 MB | sicher, gering | Ein einmaliger Download. Der Gegenwert ist eine Werkzeugkette statt zweier |
| Electron altert schnell (alle ~8 Wochen neue Hauptversion, nur 3 gepflegt) | sicher × planbar | Pflege-Regel in § 6.8: bei jedem Rippy-Release den Electron-Sprung prüfen. Das Selbst-Update macht das Verteilen billig |
| SmartScreen bei unsignierter EXE | mittel | Entscheid 5: kein Zertifikat. Anleitung + Prüfsumme beim Release — reicht für die Zielgruppe aus Entscheid 9 |
| Update ohne Signaturprüfung | mittel × Folge von Entscheid 5 | § 6.8 — nur HTTPS, http:// wird abgelehnt. Der Transportweg ist die einzige Absicherung, deshalb darf er nicht optional sein |
Feste latest.yml-Adresse im Gitea |
niedrig × messbar | Entscheid 6, ⚠️-Punkt — in W-6 am ersten Release messen; Rückfallebene festes Update-Tag. Eine Bau-Einstellung, keine Programmänderung |
| Updates hängen am Heimnetz des Commanders | niedrig | § 6.8 Regel 3 — ein stummer Server ist eine Protokollzeile, kein Fehler. Wer eine eigene Quelle will, trägt sie ein |
Aufräumen von main reißt Docker mit |
mittel × vermeidbar | § 11 — drei Teile sauber getrennt, Remote-Worker bleibt, eigener Branch, Ampel nach jedem Schritt |
| koffi + Electron + npm-Install-Sperre | niedrig | § 3.5 gemessen: koffi lädt mit vorgebauten Binärdateien, Electron braucht install.js von Hand. Beides steht in der Bau-Anleitung |
| Parallel-Rip vs. MakeMKV-Datenverzeichnis | mittel | § 6.5 — messen, bevor die Grenze festgeschrieben wird |
| Ein neu geschriebener Parser bringt neue Fehler | mittel | Die alten Testfälle wandern mit (§ 10). Ein Parser, der sie besteht, kennt dieselben Fallen |
| 4K-UHD-Schlüssel | gelöst | Unter Windows holt makemkvcon sie selbst — der strukturelle Vorteil dieser Plattform, gemessen 25.07.2026 |
node:sqlite in Electron ungeprüft |
gelöst | § 3.4 — am 30.08.2026 im utilityProcess von Electron 44 gemessen. Rückfallebene better-sqlite3 nicht gebraucht |
| gelöst | § 3.6 — Gitea ist öffentlich per HTTPS erreichbar, Entscheid 6 nutzt es direkt |
Stand der Entscheidungen (30.08.2026, zweite Fassung)
Alle offenen Punkte der ersten Fassung sind entschieden und die Prüfung hat zwei davon zusätzlich vereinfacht: Code-Signing nein (Entscheid 5) · Update-Quelle öffentliches Gitea, direkt (Entscheid 6, durch Messung § 3.6 von einer Infrastruktur-Frage zu einer Bau-Einstellung geschrumpft) · alter Windows-Weg wird sofort entfernt (Entscheid 7) · Remote-Worker bleibt bei Docker (Entscheid 8) · Zielgruppe Bekannte mit Link (Entscheid 9). Was daraus an Arbeit folgt, steht in § 11 und § 12.
14. Was NICHT gebaut wird
- Kein Python. Auch nicht „nur für den einen Parser".
- Kein HTTP-Server, kein Port, kein localhost. Fenster und Kern reden über IPC.
- Keine Docker-Kompatibilität. Kein geteiltes Modul, kein gemeinsames Schema, keine Container-Pfade.
- Kein Linux, kein macOS. „100 % für Windows gebaut" heißt: Wo eine Windows-Lösung besser ist als eine portable, gewinnt die Windows-Lösung.
- Kein ARM-Fork. Rippy bleibt ein Eigenbau.
- Keine Auth. Einzelplatz, kein Netzdienst — es gibt nichts zu schützen.
- Kein öffentlicher Auftritt. Entscheid 9: Weitergabe per Link an Bekannte, kein Marketing, kein Support-Versprechen an Fremde.
Anhang — Verhältnis zu den bestehenden Konzepten
KONZEPT.md (v1) und KONZEPT-V2.md (v2) bleiben gültig für die
Docker-Version. Dieses Dokument ersetzt sie nicht, es steht daneben.
Drei Punkte aus v2 werden für Windows bewusst anders entschieden — jeweils mit Begründung:
| v2 sagt | v5 macht | Warum |
|---|---|---|
| Entscheid 4: kein Electron, pywebview + WebView2 (8 MB statt 150 MB) | Electron | Die Rechnung war richtig und die Schlussfolgerung trotzdem falsch: Sie hat nur die Fenster-Frage betrachtet. Der Preis für pywebview war nicht 0 MB, sondern eine zweite Werkzeugkette — PyInstaller, hidden imports, pythonnet, und ein Kern, der aus Container-Code bestand. Electron kostet 150 MB und schenkt uns eine Sprache von der Oberfläche bis zum Laufwerk. |
| Eine Anwendung, drei Verdrahtungen (Ports/Treiber) | Ein Windows-Programm | Die Ports-Architektur ist richtig für ein Produkt, das drei Betriebsarten tragen muss. Bei Entscheid 2 (Docker bleibt getrennt) trägt sie nichts mehr — sie wäre Abstraktion auf Vorrat. |
| REST + SSE als Schnittstelle | IPC | Ein lokaler Webserver in einer Einzelplatz-Anwendung ist eine offene Tür ohne Gegenwert. |
Rippy v5 · Konzept, zweite Fassung · 30.08.2026 · Branch worktree-windows-electron