Files
HMS MediaEngine Agent 362e089be0 AUFGERAUMT: Root auf 10 sichtbare Elemente reduziert
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).
2026-09-11 23:44:06 +02:00

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,
}