Names check for a copied campus; the ATEM folder says when the page may not read Google Drive
Site setup > Companion lists every connection, Dante device and MIDI session the keys use that this campus does not report, with a map-to choice that renames it across checks, restart keys and fixes. The ATEM section explains the Full Disk Access step when the cloud folder looks empty to the background page. Verified on NA Ingest; Install the staged folder tested live there too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+56
-2
@@ -644,12 +644,21 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
return self.send(200, spotify_info(url))
|
||||
if path == "/api/atem-reference/folder":
|
||||
folder = os.path.expanduser((site.cfg.get("atem") or {}).get("source_folder") or "")
|
||||
files = sorted(glob.glob(os.path.join(folder, "*.xml")), key=os.path.getmtime, reverse=True) if folder and os.path.isdir(folder) else []
|
||||
return self.send(200, {"folder": folder, "mounted": bool(folder and os.path.isdir(folder)),
|
||||
mounted = bool(folder and os.path.isdir(folder))
|
||||
files = sorted(glob.glob(os.path.join(folder, "*.xml")), key=os.path.getmtime, reverse=True) if mounted else []
|
||||
blocked = False
|
||||
if mounted and not files:
|
||||
try:
|
||||
blocked = not os.listdir(folder) and "/Library/CloudStorage/" in folder # a cloud folder that looks empty to a background process
|
||||
except OSError:
|
||||
blocked = True
|
||||
return self.send(200, {"folder": folder, "mounted": mounted, "blocked": blocked,
|
||||
"files": [{"name": os.path.basename(f), "when": os.path.getmtime(f)} for f in files[:10]]})
|
||||
if path == "/api/live/midi":
|
||||
snap = site.read_json("snapshot.json", {}) or {}
|
||||
return self.send(200, {"local": snap.get("midi"), "remote": snap.get("remote_midi")})
|
||||
if path == "/api/site/names":
|
||||
return self.send(200, self.names_check((site.draft.read() or {}).get("config") or site.load()))
|
||||
if path == "/api/setup":
|
||||
return self.send(200, {"computers": scripts.setup_all(site.load())})
|
||||
if path == "/api/program/staged":
|
||||
@@ -878,6 +887,51 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
log.exception("%s %s", self.command, path)
|
||||
return self.send(500, {"error": str(e)})
|
||||
|
||||
def names_check(self, cfg):
|
||||
"""Every device name the keys use, against what this Companion, the Dante network and the Macs report now:
|
||||
the mapping step of a copied campus."""
|
||||
site = self.site
|
||||
try:
|
||||
live = {c["label"]: c.get("moduleId") for c in site.comp.connections()}
|
||||
companion_ok = True
|
||||
except Exception:
|
||||
live, companion_ok = {}, False
|
||||
used = {}
|
||||
for t in cfg.get("tiles", []):
|
||||
for c in t.get("checks", []):
|
||||
if c.get("conn") and c["type"] != "dante" or (c["type"] == "dante" and c.get("conn")):
|
||||
used.setdefault(c["conn"], {"keys": set(), "module": schema.EXPECTED_MODULE.get(c["type"])})["keys"].add(t.get("label", t["id"]))
|
||||
for k in (cfg.get("restart_page") or {}).get("keys", []):
|
||||
for w in k.get("watch", []):
|
||||
if w.startswith("conn:"):
|
||||
used.setdefault(w[5:], {"keys": set(), "module": None})["keys"].add("restart key " + k.get("label", k["id"]))
|
||||
conns = []
|
||||
for name, u in sorted(used.items()):
|
||||
cands = [l for l, m in live.items() if l not in used and (not u["module"] or not m or m == u["module"])]
|
||||
conns.append({"name": name, "keys": sorted(u["keys"]), "live": name in live, "module": u["module"],
|
||||
"live_module": live.get(name), "candidates": sorted(cands)})
|
||||
snap = site.read_json("snapshot.json", {}) or {}
|
||||
dmap = snap.get("dante_map") or {}
|
||||
dante = []
|
||||
for t in cfg.get("tiles", []):
|
||||
for c in t.get("checks", []):
|
||||
if c["type"] == "dante":
|
||||
for n in c.get("devices", {}):
|
||||
dante.append({"name": n, "seen": n in dmap, "candidates": sorted(x for x in dmap if x not in c["devices"])})
|
||||
local, remote = snap.get("midi") or {}, snap.get("remote_midi") or {}
|
||||
midi = []
|
||||
for t in cfg.get("tiles", []):
|
||||
for c in t.get("checks", []):
|
||||
if c["type"] == "midi_peer":
|
||||
src = (remote.get(c["host"]) or {}) if c.get("host") else local
|
||||
sess = src.get(c.get("session")) if isinstance(src, dict) else None
|
||||
peers = [p.get("name") for p in (sess or {}).get("peers", [])] if sess else []
|
||||
midi.append({"session": c.get("session"), "peer": c.get("peer"), "host": c.get("host"), "key": t.get("label", t["id"]),
|
||||
"session_seen": sess is not None, "peer_seen": c.get("peer") in peers,
|
||||
"sessions_seen": sorted(src) if isinstance(src, dict) else [], "peers_seen": peers})
|
||||
return {"companion_ok": companion_ok, "connections": conns, "dante": dante, "midi": midi,
|
||||
"missing": sum(1 for c in conns if not c["live"]) + sum(1 for d in dante if not d["seen"]) + sum(1 for m in midi if not m["session_seen"] or not m["peer_seen"])}
|
||||
|
||||
def staged(self):
|
||||
"""The staged folder (~/status-panel-install) against the running code."""
|
||||
src = os.path.expanduser("~/status-panel-install")
|
||||
|
||||
Reference in New Issue
Block a user