#!/usr/bin/env python3 """HTML setup routine for DOSBox/ScummVM games. Nothing about which games exist is hardcoded here: available games are discovered by listing *.json manifests on the SMB share, one per game, each describing how to install/uninstall/start/stop that game. Drop a new .json (and matching zip) on the share and it shows up here with no image changes needed. Manifest schema (all fields required): { "name": "stuntcar", # must match the manifest's own filename "title": "Stuntcar Racer", "zip_path": "Games/dosbox/stuntcar.zip", # path to the zip, relative to the share root - # games can live anywhere on the share, not just # next to their manifest "release_date": "1989", "publisher": "MicroStyle", "start_cmd": ["dosbox", "run.bat", "-conf", "dosbox-0.74-3.conf"] } Uninstall is implicit (remove GAMES_HOME/); stop is implicit (terminate the process tracked from the last start_cmd). Manifests themselves always live in SMB_DIR (the catalog directory), even though the zip_path they point at may not. Install size isn't a manifest field - it's looked up live from the share (via `smbclient ls`) so it can't go stale. Each running game gets its own ephemeral X session (Xvnc + fluxbox + websockify on their own display/ports) instead of sharing one screen, so up to MAX_CONCURRENT_GAMES can run side by side without fighting over focus or being invisible to each other. Starting past that cap is refused. Audio is deliberately *not* per-game: server.sh starts one PulseAudio daemon and one pcm_ws_bridge.py (from docker-common) for the whole container's lifetime, capturing PulseAudio's single default sink. Every running game's audio mixes together there (normal PulseAudio behavior, no per-game routing needed) - simpler than per-slot audio isolation, at the cost of not being able to tell games' audio apart when more than one is running. Video and audio are deliberately on separate pages/tabs, not one wrapper page with an