Files
hms-mediaengine/launcher_core.py
T
HMS MediaEngine Agent 1e921a9085 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)
2026-09-11 19:41:26 +02:00

84 lines
2.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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())