"""Bootstrap, Setup-Skripte für Windows/Linux, Einstellungs-Dialog.""" from __future__ import annotations import subprocess import sys from pathlib import Path LINUX_PKGS = [ "gstreamer1.0-tools", "gstreamer1.0-plugins-base", "gstreamer1.0-plugins-good", "gstreamer1.0-plugins-bad", "gstreamer1.0-plugins-ugly", "gstreamer1.0-libav", "python3-gst-1.0", "gir1.2-gst-1.0", "python3-tk", ] def check_and_install_dependencies() -> bool: """Prüft GStreamer; installiert bei Bedarf (Linux) bzw. lädt MSI (Windows).""" print("[Bootstrap] Prüfe GStreamer...") try: import gi # noqa: F401 gi.require_version("Gst", "1.0") from gi.repository import Gst as _Gst _Gst.init(None) print(f"[Bootstrap] GStreamer {_Gst.version_string()} OK") return True except (ImportError, ValueError): pass if sys.platform == "linux": print("[Bootstrap] Installiere GStreamer (sudo apt-get)...") try: subprocess.run(["sudo", "apt-get", "update", "-qq"], check=True, timeout=180) subprocess.run( ["sudo", "apt-get", "install", "-y", "-qq"] + LINUX_PKGS, check=True, timeout=600) print("[Bootstrap] GStreamer installiert. Programm neu starten.") except (subprocess.CalledProcessError, subprocess.TimeoutExpired, FileNotFoundError): print("[Bootstrap] Manuell installieren:") print(" sudo apt-get install " + " ".join(LINUX_PKGS)) return False if sys.platform == "win32": url = ("https://gstreamer.freedesktop.org/data/pkg/windows/" "1.28.4/msvc/" "gstreamer-1.0-msvc-x86_64-1.28.4.msi") msi = Path.home() / "Downloads" / "gstreamer-1.0-msvc-x86_64.msi" try: import urllib.request if not msi.exists(): print(f"[Bootstrap] Lade {url}") urllib.request.urlretrieve(url, msi) subprocess.run(["msiexec", "/i", str(msi), "/quiet", "ADDLOCAL=ALL"], check=False) print("[Bootstrap] GStreamer-MSI gestartet. " "Nach Installation neu starten.") except Exception as e: # noqa: BLE001 print(f"[Bootstrap] Download-Fehler: {e}") print(f"[Bootstrap] Manuell installieren: {url}") return False return False WINDOWS_SETUP = r'''# HMS MediaEngine - Windows Setup (einmalig ausfuehren) $ErrorActionPreference = "Stop" Write-Host "=== HMS MediaEngine Windows Setup ===" -ForegroundColor Cyan $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $isAdmin) { Write-Host "Als Administrator ausfuehren (Rechtsklick -> Als Administrator ausfuehren)" -ForegroundColor Red exit 1 } Write-Host "[1/2] GStreamer 1.28.4 MSVC..." -ForegroundColor Yellow $gstRoot = [Environment]::GetEnvironmentVariable("GSTREAMER_1_0_ROOT_MSVC_X86_64", "Machine") if (-not $gstRoot) { $url = "https://gstreamer.freedesktop.org/data/pkg/windows/1.28.4/msvc/gstreamer-1.0-msvc-x86_64-1.28.4.msi" $msi = "$env:TEMP\gstreamer.msi" Invoke-WebRequest -Uri $url -OutFile $msi Start-Process msiexec.exe -ArgumentList "/i `"$msi`" /quiet ADDLOCAL=ALL" -Wait Write-Host " GStreamer installiert" } else { Write-Host " bereits vorhanden" } Write-Host "[2/2] Python 3.13 (falls fehlt) mit tkinter..." -ForegroundColor Yellow $py = Get-Command python -ErrorAction SilentlyContinue if (-not $py) { $pyUrl = "https://www.python.org/ftp/python/3.13.2/python-3.13.2-amd64.exe" $exe = "$env:TEMP\python-installer.exe" Invoke-WebRequest -Uri $pyUrl -OutFile $exe Start-Process $exe -ArgumentList "/quiet InstallAllUsers=1 PrependPath=1 Include_tcltk=1" -Wait Write-Host " Python installiert" } else { Write-Host " bereits vorhanden" } $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";$env:Path" Write-Host "" Write-Host "=== Fertig ===" -ForegroundColor Green Write-Host "Start: python run.py" Write-Host "Dialog: python run.py --setup" Write-Host "Media-Verwaltung, Layer und Einstellungen: Web-UI im Browser" ''' LINUX_SETUP = r'''#!/bin/bash # HMS MediaEngine - Linux Setup (einmalig ausfuehren) set -e echo "=== HMS MediaEngine Linux Setup ===" if command -v apt-get >/dev/null; then sudo apt-get update -qq sudo apt-get install -y -qq gstreamer1.0-tools gstreamer1.0-plugins-base \ gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \ gstreamer1.0-libav python3-gst-1.0 gir1.2-gst-1.0 python3-tk xvfb elif command -v dnf >/dev/null; then sudo dnf install -y gstreamer1 gstreamer1-plugins-base gstreamer1-plugins-good \ gstreamer1-plugins-bad-free gstreamer1-plugins-ugly gstreamer1-libav \ python3-gobject python3-tkinter fi echo "=== Fertig ===" echo "Start: python3 run.py" echo "Media-Verwaltung, Layer und Einstellungen: Web-UI im Browser" ''' def generate_setup_scripts(root: Path) -> None: p1 = root / "setup_windows.ps1" p1.write_text(WINDOWS_SETUP, encoding="utf-8") p2 = root / "setup_linux.sh" p2.write_text(LINUX_SETUP, encoding="utf-8") p2.chmod(0o755) print(f"Erzeugt: {p1}") print(f"Erzeugt: {p2}") def run_setup(settings: dict) -> dict: """Nativer Dialog für Port/Fullscreen; Medien-Verwaltung bleibt im Web.""" result = {"port": int(settings["web"]["port"]), "fullscreen": bool(settings["output"]["fullscreen"])} try: import tkinter as tk from tkinter import ttk except ImportError: print("tkinter nicht verfügbar (Linux: apt install python3-tk).") return result root = tk.Tk() root.title("HMS MediaEngine – Einstellungen") root.geometry("440x240") root.configure(bg="#16181d") style = ttk.Style(root) style.theme_use("clam") style.configure("TLabel", background="#16181d", foreground="#c8ccd4") main = ttk.Frame(root, padding=18) main.pack(fill="both", expand=True) ttk.Label(main, text="HMS MediaEngine", font=("System", 15, "bold")).pack(pady=(0, 2)) ttk.Label(main, text="Grundeinstellungen", foreground="#8a8f9a").pack(pady=(0, 12)) row = ttk.Frame(main) row.pack(fill="x", pady=4) ttk.Label(row, text="Web-UI Port:").pack(side="left") port_var = tk.StringVar(value=str(result["port"])) ttk.Entry(row, textvariable=port_var, width=7).pack( side="left", padx=8) fs_var = tk.BooleanVar(value=result["fullscreen"]) ttk.Checkbutton(row, text="Fullscreen-Output", variable=fs_var).pack(side="left", padx=10) def go(): try: result["port"] = int(port_var.get() or 8080) except ValueError: pass result["fullscreen"] = bool(fs_var.get()) root.destroy() ttk.Button(main, text="Starten", command=go).pack( fill="x", pady=(14, 0), ipady=6) root.mainloop() return result