"""Was in welchem Container steckt (Community-Scripts-Kennung aus /usr/bin/update im Gast). Stand der Bestandsaufnahme vom 24.09.2026: sechs Container, alle mit dem Etikett community-script. Wie eine App aktualisiert wird, ist je Community-Script verschieden (nachgelesen am 24.09. in ct/.sh): skript `update` im Gast spielt die App wirklich neu ein (Gitea: neues Programm von GitHub, NetBird: apt aus dem NetBird-Repository, NPMplus: neues Docker-Image) eigene-oberflaeche das Skript verweist auf den eingebauten Updater der App (AdGuard, PVE Scripts Local) pakete die App kommt als Paket; das Update der Pakete im Gast ist ihr Update (PBS) Nur beim Weg „skript“ bietet die Übersicht „Jetzt updaten“ für die App an. Neue Container mit dem Etikett erscheinen von selbst. Fehlt ihre Kennung hier, liest katalog.py (seit 25.09.2026) Name, GitHub-Projekt, Port und Weg aus ihrem Update-Skript; was hier von Hand steht, geht vor (etwa ein geänderter Port wie bei AdGuard). """ from dataclasses import dataclass @dataclass(frozen=True) class App: kennung: str name: str quelle: str | None = None # GitHub owner/repo für die neueste Version; None = über die Pakete des Gasts vergleich: str = "version" # „version“ oder „datum“ (Docker-Images ohne Versionsnummer) port: int | None = None # Weboberfläche; None = keine (z. B. NetBird-Client) https: bool = False pfad: str = "/" weg: str = "skript" # „skript“, „eigene-oberflaeche“ oder „pakete“ (siehe oben) KATALOG: dict[str, App] = {a.kennung: a for a in ( App("adguard", "AdGuard Home", "AdguardTeam/AdGuardHome", port=8080, weg="eigene-oberflaeche"), App("npmplus", "NPMplus", "ZoeyVid/NPMplus", vergleich="datum", port=81, https=True), App("netbird", "NetBird", "netbirdio/netbird"), App("pve-scripts-local", "PVE Scripts Local", "community-scripts/ProxmoxVE-Local", port=3000, weg="eigene-oberflaeche"), App("gitea", "Gitea", "go-gitea/gitea", port=3000), App("proxmox-backup-server", "Proxmox Backup Server", port=8007, https=True, weg="pakete"), )} # Gäste, die keine Community-Scripts sind, erkennt man am Namen. NACH_NAME: dict[str, App] = { "arcane": App("arcane", "Arcane (Docker)", port=3552, weg="eigene-oberflaeche"), } def app_fuer(kennung: str | None, name: str | None) -> App | None: if kennung and kennung in KATALOG: return KATALOG[kennung] if kennung: from services.homelab import katalog # der Katalog baut Apps aus diesem Modul — erst hier if gefunden := katalog.app(kennung): return gefunden return NACH_NAME.get(str(name or "").lower()) def adresse(app: App | None, ip: str | None) -> str | None: """Adresse der Weboberfläche, falls es eine gibt und die IP bekannt ist.""" if not app or not app.port or not ip: return None return f"{'https' if app.https else 'http'}://{ip}:{app.port}{app.pfad}"