182 lines
7.0 KiB
Python
182 lines
7.0 KiB
Python
|
|
"""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
|