Files
hms-mediaengine/hms_app/setup.py
T

249 lines
9.6 KiB
Python
Raw Normal View History

"""Bootstrap, Setup-Skripte für Windows/Linux, Einstellungs-Dialog."""
from __future__ import annotations
import shutil
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 == "darwin":
pkgs = ["python@3.12", "python-tk", "gstreamer",
"gst-plugins-base", "gst-plugins-good",
"gst-plugins-bad", "gst-plugins-ugly",
"gst-libav", "pygobject"]
brew = shutil.which("brew")
if brew:
print("[Bootstrap] Installiere GStreamer + PyGObject "
"via Homebrew (dauert evtl. einige Minuten)...")
try:
subprocess.run([brew, "install"] + pkgs,
check=False, timeout=1800)
print("[Bootstrap] Fertig. Programm mit brew-python3 "
"neu starten.")
except subprocess.TimeoutExpired:
print("[Bootstrap] Timeout. Manuell: brew install "
+ " ".join(pkgs))
else:
print("[Bootstrap] Homebrew nicht gefunden.")
print(" Erst Homebrew installieren:")
print(' /bin/bash -c "$(curl -fsSL '
'https://raw.githubusercontent.com/Homebrew/'
'install/HEAD/install.sh)"')
print(" Danach: ./setup_macos.sh")
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
MACOS_SETUP = r'''#!/bin/bash
# HMS MediaEngine - macOS Setup (Apple Silicon & Intel, einmalig ausfuehren)
set -e
echo "=== HMS MediaEngine macOS Setup ==="
echo "Architektur: $(uname -m)"
if ! command -v brew >/dev/null; then
echo "Homebrew fehlt. Zunaechst installieren:"
echo ' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
echo "Dann dieses Skript erneut ausfuehren."
exit 1
fi
echo "[1/2] Installiere GStreamer, PyGObject und tkinter (brew)..."
brew install python@3.12 python-tk gstreamer gst-plugins-base \
gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav pygobject
echo "[2/2] Umgebung pruefen..."
if [ "$(uname -m)" = "arm64" ] && [ -f /opt/homebrew/bin/brew ]; then
echo "Apple Silicon: Homebrew-Umgebung einbinden mit:"
echo ' eval "$(/opt/homebrew/bin/brew shellenv)"'
fi
echo "Pruefung:"
python3 -c "import gi; gi.require_version('Gst','1.0'); from gi.repository import Gst; Gst.init(None); print('GStreamer OK:', Gst.version_string())" || \
{ echo "PyGObject fehlt noch -> brew python3 verwenden (PATH!)"; exit 1; }
echo ""
echo "Hinweis: Die .pkg-Pakete von gstreamer.freedesktop.org/data/pkg/macos/"
echo "enthalten KEINE PyGObject-Bindings - Homebrew ist der empfohlene Weg."
echo ""
echo "=== Fertig ==="
echo "Start: python3 run.py"
echo "Dialog: python3 run.py --setup"
'''
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)
p3 = root / "setup_macos.sh"
p3.write_text(MACOS_SETUP, encoding="utf-8")
p3.chmod(0o755)
print(f"Erzeugt: {p1}")
print(f"Erzeugt: {p2}")
print(f"Erzeugt: {p3}")
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