DOPPELKlick-WELT: Grafischer Installer + App-Bundles (kein Terminal mehr noetig)
Der Nutzer will KEINE Konsole - jetzt ist alles Doppelklick: 1) GRAFISCHER INSTALLER (installer_gui.py, 336 Zeilen): - Fenster mit Status-Checks (Python/GStreamer/Homebrew: fehlt/vorhanden), Fortschrittsbalken beim Download, Log-Bereich, grosse Buttons - macOS: Homebrew + GStreamer + PyGObject + tkinter via brew; Passwort-Dialog kommt NATIV von macOS (osascript administrator privileges) - kein sudo-Tippen - Windows: laedt und startet die OFFIZIELLEN Installer-GUIs (GStreamer-MSI + Python-Setup) - Nutzer klickt nur Weiter/Fertig - Nach Installation: Button 'MediaEngine starten' spawnt die Engine UNSICHTBAR im Hintergrund und oeffnet den Browser - Smoke-Test im Container bestanden (xvfb): Fenster baut sich auf, Statuschecks laufen, sauber beendet 2) macOS: 'HMS MediaEngine.app' (echtes App-Bundle im Repo): - CFBundleExecutable HMS-Launcher (Bash): sucht brew-python3, prueft GStreamer unsichtbar -> Engine nohup im Hintergrund + Browser oeffnet sich; fehlt etwas -> grafischer Installer - make_mac_app.py: App neu erzeugen falls noetig - HMS-Mac-Install.command: Doppelklick-Installation mit nativen osascript-Dialogen (Abbrechen/Weiter) + GUI-Installer am Ende 3) Windows: HMS-Start.vbs (unsichtbar) + HMS-Install.vbs (sichtbar): - HMS-Start.vbs: findet pythonw (4 Pfade + versteckte PATH-Suche ohne Konsolenblitz), startet launcher.pyw KOMPLETT unsichtbar (CREATE_NO_WINDOW) -> nur Browser erscheint - HMS-Install.vbs: oeffnet grafischen Installer; fehlt Python, oeffnet offizielle Downloadseite mit Hinweis auf PATH-Haeckchen - launcher_core.py: gemeinsame Logik (gst_ok -> Engine-Spawn -> Health-Poll -> webbrowser.open; sonst Installer-Fenster) 4) BEWEISE (im Container ausgefuehrt): - Launcher-E2E: launch() -> Engine unsichtbar gestartet, Health gruen, Browser-URL korrekt (http://localhost:8080), RC=0 - GUI-Smoke-Test: Fenster + 'Alles bereit' + sauber beendet - VBS: sh.Run-Zeilen geprueft (Chr(34)-Konstruktion, versteckte cmd-Suche) - Alle 5 Regressionssuiten unveraendert gruen: Projekte 25/25 + Cue 35/35 + Verteilung 33/33 + App 14/14 + FX 16/16 = 123 Checks Download: TAR.GZ (macOS, erhaelt Exec-Bits!) oder ZIP (Windows)
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Gemeinsame Launcher-Logik fuer Windows-Starter und macOS.
|
||||
|
||||
Unsichtbarer Ablauf: GStreamer vorhanden -> Engine im Hintergrund
|
||||
starten, auf die Web-UI warten, Browser oeffnen.
|
||||
Fehlt etwas -> grafischer Installer (installer_gui.py) oeffnen.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import urllib.request
|
||||
import webbrowser
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
IS_WIN = sys.platform == "win32"
|
||||
|
||||
|
||||
def web_port() -> int:
|
||||
try:
|
||||
cfg = json.loads((ROOT / "config.json").read_text("utf-8"))
|
||||
return int(cfg.get("web", {}).get("port", 8080))
|
||||
except Exception: # noqa: BLE001
|
||||
return 8080
|
||||
|
||||
|
||||
def gst_ok() -> bool:
|
||||
try:
|
||||
import gi # noqa: F401
|
||||
gi.require_version("Gst", "1.0")
|
||||
from gi.repository import Gst
|
||||
Gst.init(None)
|
||||
return True
|
||||
except Exception: # noqa: BLE001
|
||||
return False
|
||||
|
||||
|
||||
def _spawn(py: str, target: str, hidden: bool) -> None:
|
||||
if IS_WIN and hidden:
|
||||
subprocess.Popen(
|
||||
[py, str(ROOT / target)], cwd=str(ROOT),
|
||||
creationflags=0x08000000, # CREATE_NO_WINDOW
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
else:
|
||||
subprocess.Popen(
|
||||
[py, str(ROOT / target)], cwd=str(ROOT),
|
||||
stdout=open("/tmp/hms-mediaengine.log", "ab"),
|
||||
stderr=subprocess.STDOUT, start_new_session=not IS_WIN)
|
||||
|
||||
|
||||
def wait_health(port: int, timeout_s: float = 25.0) -> bool:
|
||||
deadline = time.monotonic() + timeout_s
|
||||
while time.monotonic() < deadline:
|
||||
try:
|
||||
with urllib.request.urlopen(
|
||||
f"http://localhost:{port}/api/health",
|
||||
timeout=1.5) as r:
|
||||
if json.loads(r.read().decode()).get("status") == "ok":
|
||||
return True
|
||||
except Exception: # noqa: BLE001
|
||||
time.sleep(0.4)
|
||||
return False
|
||||
|
||||
|
||||
def launch() -> int:
|
||||
if gst_ok():
|
||||
_spawn(sys.executable, "run.py", hidden=True)
|
||||
port = web_port()
|
||||
if wait_health(port):
|
||||
webbrowser.open(f"http://localhost:{port}")
|
||||
return 0
|
||||
print("[Launcher] Engine antwortete nicht rechtzeitig – "
|
||||
"oeffne Installer.", file=sys.stderr)
|
||||
_spawn(sys.executable, "installer_gui.py", hidden=False)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(launch())
|
||||
Reference in New Issue
Block a user