696e8eb1b3
URSACHE GEFUNDEN: macOS Installer.app verlangt 10-16 GB freien Speicher als SYSTEMRESERVE - obwohl GStreamer nur 146 MB gross ist. Diese Pruefung blockiert Installationen auf vollen Platten. LOESUNG: HMS-Portable-Install.command - Laedt GStreamer .pkg (146 MB) per curl - Entpackt mit 'pkgutil --expand-full' OHNE Installer.app (keine 16-GB-Pruefung, kein sudo, nichts systemweit) - Kopiert GStreamer.framework in runtime/ im Projektordner - Loescht Download + Temp (gibt ~750 MB zurueck) - Schreibt runtime/env.sh mit allen Umgebungsvariablen - Braucht NUR ca. 800 MB WAHREND der Installation - Danach: ca. 500-600 MB im Projektordner (portable, loeschbar) Integration: - run.py: laedt portable env automatisch VOR gi-Import (DYLD_LIBRARY_PATH, GST_PLUGIN_PATH, GI_TYPELIB_PATH, PYTHONPATH fuer gi-Bindings) - App-Launcher: sourced runtime/env.sh falls vorhanden - launcher_core.py: gleiche portable env-Logik - Freien Speicher pruefen (nur 800 MB noetig, nicht 16 GB) Drei Installationswege jetzt verfuegbar: 1. HMS-Portable-Install.command (wenig Speicher, nichts systemweit) 2. HMS-Mac-Install.command (Homebrew, mehr Komfort) 3. HMS-MediaEngine.app startet mit whichever verfuegbar ist
101 lines
3.1 KiB
Python
101 lines
3.1 KiB
Python
#!/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"
|
||
|
||
# Portable GStreamer laden (macOS: HMS-Portable-Install.command)
|
||
_fw = ROOT / "runtime" / "GStreamer.framework" / "Versions" / "1.0"
|
||
if _fw.is_dir():
|
||
import os as _os
|
||
_lib = str(_fw / "lib")
|
||
_os.environ["DYLD_LIBRARY_PATH"] = _lib + ":" + _os.environ.get("DYLD_LIBRARY_PATH", "")
|
||
_gst = str(_fw / "lib" / "gstreamer-1.0")
|
||
_os.environ["GST_PLUGIN_PATH"] = _gst
|
||
_os.environ["GST_PLUGIN_SYSTEM_PATH_1_0"] = _gst
|
||
_os.environ["GI_TYPELIB_PATH"] = (str(_fw / "lib" / "girepository-1.0")
|
||
+ ":" + _os.environ.get("GI_TYPELIB_PATH", ""))
|
||
for _v in ("python3.12", "python3.13", "python3.11"):
|
||
_sp = _fw / "lib" / _v / "site-packages"
|
||
if (_sp / "gi").is_dir():
|
||
sys.path.insert(0, str(_sp))
|
||
break
|
||
|
||
|
||
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())
|