362e089be0
Der Nutzer hat recht: Der Ordner war voller Entwicklungs-Muell. Jetzt ist sauber getrennt: ROOT (was der Nutzer sieht und braucht): - run.py = das Programm - hms_app/ = der Anwendungscode - HMS MediaEngine.app = macOS Doppelklick-Starter - HMS-Start.vbs = Windows Doppelklick-Starter - HMS-Install.vbs = Windows Erst-Installation - HMS-Mac-Install.command = macOS Homebrew-Installation - HMS-Portable-Install.command = macOS Portable-Installation (16GB-Fix) - installer_gui.py = grafischer Installer - launcher.pyw + launcher_core.py = interne Start-Logik - LIESMICH.txt = 10-Zeilen-Kurzanleitung - .gitignore _entwicklung/ (alles andere, NICHT benoetigt): - packages/ apps/ native/ plugins/ tools/ schemas/ tests/ docs/ build/ fixture_profiles/ - PLAN.md STATUS.md ERRORS.md TEST_REPORT.md CHANGELOG.md README.md - pyproject.toml uv.lock setup_*.sh/ps1 make_mac_app.py Diese Trennung gilt ab sofort fuer alle Commits. Der Nutzer kann _entwicklung/ loeschen wenn er Platz braucht - die App laeuft ohne. Verifiziert: App startet nach Aufraeumen unveraendert (Health 200).
100 lines
3.0 KiB
Python
100 lines
3.0 KiB
Python
"""Capability-Probe (PLAN.md §5, §5.2).
|
|
|
|
Phase 0: plattformneutrale Basis-Erkennung (CPU/RAM/OS) und Tier-Vergabe
|
|
nach gemessenen Fakten. GPU-/Decoder-/Display-Erkennung läuft auf dem
|
|
Zielsystem (D3D11/GL/GLES); hier kein Fake-Ergebnis (§33: keine nicht
|
|
getestete Dekodierung als Hardwarebeschleunigung ausgeben).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import enum
|
|
|
|
|
|
class CapabilityTier(enum.StrEnum):
|
|
DESKTOP_FULL = "DESKTOP_FULL"
|
|
DESKTOP_LITE = "DESKTOP_LITE"
|
|
PI_LITE = "PI_LITE"
|
|
HEADLESS_CONTROL = "HEADLESS_CONTROL"
|
|
|
|
|
|
# Mindest-VRAM für DESKTOP_FULL (§5)
|
|
_DESKTOP_FULL_MIN_VRAM_GB = 8.0
|
|
|
|
|
|
def detect_cpu_ram() -> dict[str, object]:
|
|
"""Basis-Hardwareinformationen (plattformneutral, ohne Fake)."""
|
|
import os
|
|
import platform
|
|
|
|
info: dict[str, object] = {
|
|
"os": platform.system(),
|
|
"os_release": platform.release(),
|
|
"machine": platform.machine(),
|
|
"cpu_count": os.cpu_count() or 1,
|
|
"ram_total_gb": _ram_gb(),
|
|
}
|
|
return info
|
|
|
|
|
|
def _ram_gb() -> float:
|
|
"""RAM in GB; Linux via /proc/meminfo, sonst -1 (unbekannt, nicht geraten)."""
|
|
try:
|
|
with open("/proc/meminfo", encoding="ascii") as fh:
|
|
for line in fh:
|
|
if line.startswith("MemTotal:"):
|
|
kib = int(line.split()[1])
|
|
return round(kib / (1024 * 1024), 2)
|
|
except (OSError, ValueError):
|
|
pass
|
|
return -1.0
|
|
|
|
|
|
class CapabilityReport:
|
|
"""Ergebnis des Capability-Selbsttests (Phase 0: Skelett).
|
|
|
|
GPU/Decoder/Displays werden auf dem Zielsystem gemessen und hier
|
|
ergänzt; ein Report ohne GPU-Messung kann kein DESKTOP-Tier vergeben.
|
|
"""
|
|
|
|
def __init__(self) -> None:
|
|
self.cpu_ram = detect_cpu_ram()
|
|
self.gpu: dict[str, object] | None = None
|
|
self.decoders: dict[str, object] | None = None
|
|
self.displays: dict[str, object] | None = None
|
|
self.tier: CapabilityTier | None = None
|
|
self.fingerprint: str = "" # an Messwerte gebunden (§5.2)
|
|
|
|
def conclude_tier(
|
|
self,
|
|
has_gpu: bool,
|
|
vram_gb: float | None,
|
|
decode_ok: bool,
|
|
has_display: bool,
|
|
) -> CapabilityTier | None:
|
|
"""Vergibt das Tier nach gemessenen Fakten; None wenn unklar.
|
|
|
|
Unklar bedeutet: Gate 0 darf nicht grün melden, solange keine
|
|
Messwerte vorliegen (§33).
|
|
"""
|
|
if not has_display:
|
|
self.tier = CapabilityTier.HEADLESS_CONTROL
|
|
return self.tier
|
|
if not has_gpu or not decode_ok:
|
|
return None
|
|
if vram_gb is not None and vram_gb >= _DESKTOP_FULL_MIN_VRAM_GB:
|
|
self.tier = CapabilityTier.DESKTOP_FULL
|
|
else:
|
|
self.tier = CapabilityTier.DESKTOP_LITE
|
|
return self.tier
|
|
|
|
def as_dict(self) -> dict[str, object]:
|
|
return {
|
|
"cpu_ram": self.cpu_ram,
|
|
"gpu": self.gpu,
|
|
"decoders": self.decoders,
|
|
"displays": self.displays,
|
|
"tier": self.tier.value if self.tier else None,
|
|
"fingerprint": self.fingerprint,
|
|
}
|