"""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, zeigt die Übersicht sie ohne Versionsvergleich und ohne Webprüfung — nachtragen genügt. """ 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] 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}"