feat(windows): echtes Fenster statt Browser-Tab (WebView2 statt Electron)

Auf die Frage des Commanders: "Warum nutzen wir fuer Windows weiterhin
einen Browser? Warum nutzen wir kein Electron oder sowas und machen daraus
einen echten Client."

Die erste Haelfte trifft zu und ist umgesetzt. Die zweite ist abgelehnt --
gemessen, nicht geschaetzt:

    pywebview + WebView2     8,0 MB in der Bau-Umgebung, 2,7 MB in der EXE
    Electron               150-210 MB, dazu eine zweite Laufzeitumgebung

Windows 11 bringt die WebView2-Laufzeit mit (hier 151.0.4129.107).
Nachgemessen statt angenommen, was sie rendert:

    navigator.userAgent  ...Chrome/151.0.0.0 Safari/537.36 Edg/151.0.0.0
    fetch ja   EventSource ja   CSS Grid ja   Pfeilfunktionen ja

Dasselbe Chromium, das auch in Electron steckt -- nur ohne es ein zweites
Mal mitzuschleppen. RippySetup.exe waechst von 29,0 auf 31,7 MB.

Drei Dinge gehoeren dazu, nicht als Beiwerk:

* Kein stiller Rueckfall auf MSHTML. Der alte IE-Renderer stellt die
  React-Oberflaeche nicht dar. Fehlt WebView2, oeffnet Rippy den Browser
  und SAGT warum -- ein leeres Fenster waere schlimmer als ein Tab.
* Fenster und Tray sind getrennte Prozesse. pystray belegt unter Windows
  den Haupt-Thread, das Fenster braucht ihn genauso.
* Die eigene Konsole wird versteckt, eine geerbte nie. GetConsoleProcessList
  unterscheidet beides: genau ein Prozess an der Konsole heisst, sie
  gehoert uns. Ohne diese Unterscheidung haette "Rippy.exe --status" im
  Terminal das Terminal des Nutzers verschwinden lassen.

fix(windows): Oberflaeche neben das Programm legen statt aus %TEMP% bedienen

Beim Nachsehen im laufenden Betrieb gefunden: Ein Dienst lief eine Stunde,
/api/health gab HTTP 200, / gab 404. Im Fenster stand {"detail":"Not Found"}.

Der Server war in Ordnung. Sein Entpack-Verzeichnis war es nicht:

    _MEI000074b02   31 Eintraege,  5 Ordner   -- kein ui, kein api
    _MEI000082e82   44 Eintraege, 16 Ordner   -- vollstaendig

Eine PyInstaller-Onefile-EXE liest bei JEDER Anfrage aus %TEMP%\_MEIxxxxx.
Ein Temp-Verzeichnis ist kein Ort fuer etwas, das eine Woche liegen bleibt.
Und der Ausfall ist der schlimmstmoegliche: Die API antwortet weiter, der
Dienst gilt als gesund, nur die Oberflaeche ist weg.

Genau davor warnte ROADMAP.md beim Bau-Verfahren ("one-dir statt one-file").
Die Abweichung bleibt, die Luecke wird geschlossen: Der Installer legt die
Oberflaeche neben das Programm, daemon._ui_pfad() nimmt diese Kopie zuerst.
Zeigt sich derselbe Ausfall an den API-Modulen, ist one-dir die Antwort.

Ampel: 562 gruen, ruff sauber. Fenster mit der echten Oberflaeche im
Bildschirmfoto nachgewiesen, nicht nur der Titel geprueft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-08-28 12:14:15 +02:00
co-authored by Claude Opus 5
parent 069fc46f44
commit c01ef1081c
12 changed files with 971 additions and 34 deletions
+32 -4
View File
@@ -619,15 +619,43 @@ Medien.
plus Worker) UND ein Verbindungsabriss keine Liste leert.
### V2-4: Windows nativ
- [ ] `drives/windows.py` — Win32 statt ioctl (`IOCTL_STORAGE_CHECK_VERIFY2`,
- [x] `drives/windows.py` — Win32 statt ioctl (`IOCTL_STORAGE_CHECK_VERIFY2`,
`IOCTL_STORAGE_MEDIA_REMOVAL`, `IOCTL_STORAGE_EJECT_MEDIA`,
MMC `GET CONFIGURATION` für den Disc-Typ)
- [ ] Disc-Einwurf per `WM_DEVICECHANGE` statt Polling
- [ ] Dienst (WinSW) + Tray als GETRENNTE Prozesse; WebView2-Fenster
- [ ] Nuitka `--standalone` (one-dir, nicht one-file) + Inno Setup
- [ ] Disc-Einwurf per `WM_DEVICECHANGE` statt Polling**offen**, läuft
vorerst über den Poll aus `drives/detection.py`
- [x] Dienst + Fenster als GETRENNTE Prozesse; **WebView2-Fenster**
(`fenster.py`, Entscheid 4 in `KONZEPT-V2.md` § 10)
- [x] Eintrag in „Programme und Features" und im Taskmanager als `Rippy.exe`
(ausdrücklicher Wunsch des Commanders)
- [x] Desktop-Symbol und Startmenü-Eintrag, im Setup abschaltbar
- [x] Werkzeug-Erkennung und -Beschaffung (`tools/katalog.py`,
`tools/beschaffen.py`) — Rippy findet, holt und aktualisiert
HandBrake/MakeMKV selbst
- [ ] Standby blocken via `SetThreadExecutionState`, ohne `ES_DISPLAY_REQUIRED`
**offen**
- **Fertig, wenn:** auf einem frischen Win-11-Rechner gilt: Installer →
Disc rein → MKV raus. Und der UHD-Schlüssel kommt automatisch.
**Noch offen:** ein echter Rip auf Windows ist ungeprüft — das Laufwerk
hängt an der VM.
> **Abweichung vom Plan, bewusst und mit Folgen.** Statt Nuitka `--standalone`
> (one-dir) + Inno Setup wurde **PyInstaller onefile** genommen: ein Programm,
> drei Betriebsarten (`RippySetup.exe`, `--dienst`, `--deinstallieren`), kein
> zweites Werkzeug in der Kette.
>
> Der Preis stand oben schon im Plan — *„ein Onefile-Paket entpackt sich bei
> jedem Start neu nach `%TEMP%`"* — und er ist am 28.08.2026 fällig geworden:
> Ein Dienst lief eine Stunde, `/api/health` gab 200, `/` gab **404**. Vom
> Entpack-Verzeichnis des laufenden Prozesses waren 31 statt 44 Einträge übrig,
> `ui` und `api` fehlten. Die API meldete sich gesund, während die Oberfläche
> weg war.
>
> **Gegenmaßnahme:** Der Installer legt die Oberfläche als Kopie NEBEN das
> Programm (`windows_app.ui_auspacken`), und `daemon._ui_pfad()` nimmt diese
> Kopie vor dem Entpack-Verzeichnis. Zwei Tests halten das fest. Sollte sich
> derselbe Ausfall an den API-Modulen zeigen, ist one-dir die richtige Antwort
> — dann ist diese Abweichung zurückzunehmen.
### V2-5: Docker neu
- [ ] EIN Image, drei Profile (`standalone`, `api`, `node`)