READY page: the weekly worship checklist, checked against Planning Center
- readiness.py looks every 2 minutes (never while a HyperDeck records) at this weekend's PCO plan and what is in place for it: the Ableton set (songs, mix, routing, lighting cues), ProPresenter (every PCO item, MC announcements, baptism names, timelines, backgrounds), the LTC note of every song against the timecode the tracks play, the Band Lineup TV, Resolume's LED cross, and the tracks and ProP bundles for the locations. - READY key on the Status page (row 2, col 7; SPOTIFY now shows inside SHOW) opens page 24. Amber until done, blinking red from Saturday noon; not part of ALL. Tap keys for BOH mix, mics and stage reset every Monday. - Holds fix what can be fixed: re-sync the lineup, put the cross back up, write LTC into PCO, copy tracks to locations, look again. Hold READY fixes everything. - Settings page: a READY page tab (live keys, drag to move, why each key is amber), and Apply re-imports page 24. - Auto-fix: "while_muted" fixes keep running with ALARMS muted (Spotify playlist). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+16
-10
@@ -16,22 +16,24 @@ import make_page # noqa: E402
|
||||
import schema # noqa: E402
|
||||
import status_panel as sp # noqa: E402
|
||||
|
||||
WALKED = ["status_panel.py", "make_page.py", "push_page.py", "nav_keys.py", "netgear.py"]
|
||||
WALKED = ["status_panel.py", "make_page.py", "push_page.py", "nav_keys.py", "netgear.py", "readiness.py"]
|
||||
|
||||
# What a variable holds, by name, when nothing in the function says otherwise (parameters mostly).
|
||||
NAMES = {"cfg": "top", "config": "top", "chk": "check", "c": "check", "fix": "fix", "f": "fix", "t": "tile",
|
||||
"tile": "tile", "k": "restart_key", "key": "restart_key", "rp": "restart_page", "w": "window",
|
||||
"names": "variables", "host": "host", "h": "host", "windows": "windows", "site": "site"}
|
||||
"names": "variables", "host": "host", "h": "host", "windows": "windows", "site": "site", "rc": "ready"}
|
||||
ATTRS = {"self.cfg": "top", "engine.cfg": "top", "self.net": "network", "self.auto": "auto", "self.site": "site",
|
||||
"self.atem": "atem",
|
||||
"self.atem": "atem", "self.ready_cfg": "ready",
|
||||
"self.tiles": "tiles", "engine.tiles": "tiles", "self.restart_keys": "restart_keys",
|
||||
"engine.restart_keys": "restart_keys"}
|
||||
# A key of a top-level dict that holds a record of another kind.
|
||||
TOP = {"companion": "companion", "network": "network", "variables": "variables", "auto_fix": "auto", "site": "site",
|
||||
"atem": "atem", "spotify": "spotify", "timing": "timing", "flap": "flap", "hosts": "hosts", "fixes": "fixes",
|
||||
"tiles": "tiles", "restart_page": "restart_page", "gear": "gears", "service_windows": "windows"}
|
||||
"tiles": "tiles", "restart_page": "restart_page", "gear": "gears", "service_windows": "windows",
|
||||
"ready": "ready", "ready_page": "ready_page"}
|
||||
SUB = {("auto", "windows"): "windows", ("site", "live_services"): "windows", ("tile", "checks"): "checks",
|
||||
("restart_page", "keys"): "restart_keys", ("tile", "members"): "names"}
|
||||
("restart_page", "keys"): "restart_keys", ("tile", "members"): "names", ("ready", "due"): "windows",
|
||||
("ready_page", "keys"): "tiles"}
|
||||
ELEMENT = {"tiles": "tile", "checks": "check", "restart_keys": "restart_key", "windows": "window", "fixes": "fix",
|
||||
"hosts": "host", "gears": "gear"}
|
||||
# Keys the code reads that are the watchdog's own working data, not settings.
|
||||
@@ -67,6 +69,8 @@ def collect(path):
|
||||
return step(base, key)
|
||||
if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute) and node.func.attr in ("items", "values"):
|
||||
return kind_of(node.func.value, local)
|
||||
if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id in ("all_tiles", "ready_keys"):
|
||||
return "tiles" # the Status page's tiles and the READY page's keys
|
||||
if isinstance(node, ast.Call) and dotted(node.func) == "json.load":
|
||||
return "jsonfile" # a config file when it lands in cfg / config
|
||||
if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id in ("enumerate", "dict", "sorted", "list") and node.args:
|
||||
@@ -141,7 +145,7 @@ def path_of(kind, key):
|
||||
"restart_key": "restart_page.keys[].", "restart_page": "restart_page.", "auto": "auto_fix.",
|
||||
"network": "network.", "variables": "variables.", "site": "site.", "atem": "atem.", "spotify": "spotify.",
|
||||
"companion": "companion.", "timing": "timing.", "flap": "flap.", "gear": "gear.*.",
|
||||
"window": "auto_fix.windows[]."}.get(kind)
|
||||
"window": "auto_fix.windows[].", "ready": "ready.", "ready_page": "ready_page."}.get(kind)
|
||||
return None if prefix is None else prefix + key
|
||||
|
||||
|
||||
@@ -173,17 +177,18 @@ class TestSchemaMatchesCode(unittest.TestCase):
|
||||
ui_only = {"site.id", "site.name", "site.ingest_hostname", "site.ingest_ips", "site.contacts", "site.editing_code",
|
||||
"site.settings_port", "site.dvs_helper", "site.solo_dir", "hosts.*.name", "hosts.*.role",
|
||||
"hosts.*.notes", "hosts.*.pingable", "hosts.*.runs", "hosts.*.networks", "hosts.*.manual_done",
|
||||
"gear", "gear.*.location", "gear.*.notes", "atem.source_folder", "fixes.*.template", "fixes.*.params",
|
||||
"gear", "gear.*.location", "gear.*.notes", "gear.*.kind", "gear.*.address", "atem.source_folder", "fixes.*.template", "fixes.*.params",
|
||||
"tiles[].checks[].template", "tiles[].checks[].params", "spotify.name", "site", "timing",
|
||||
"fixes", "hosts", "tiles", "flap", "auto_fix", "network", "variables", "companion", "atem", "spotify",
|
||||
"restart_page", "service_windows", "restart_page.keys", "tiles[].checks", "auto_fix.windows",
|
||||
"site.live_services", "tiles[].checks[].type", "fixes.*.playlist", "tiles[].checks[].playlist"}
|
||||
"site.live_services", "tiles[].checks[].type", "fixes.*.playlist", "tiles[].checks[].playlist",
|
||||
"ready_page", "ready_page.keys", "ready"}
|
||||
read = {path_of(kind, key) for _, kind, key, _, _ in all_reads()}
|
||||
read |= {"service_windows[].days", "service_windows[].start", "service_windows[].end",
|
||||
"site.live_services[].days", "site.live_services[].start", "site.live_services[].end"}
|
||||
for w in ("days", "start", "end"):
|
||||
if "auto_fix.windows[]." + w in read:
|
||||
read |= {"service_windows[].%s" % w, "site.live_services[].%s" % w}
|
||||
read |= {"service_windows[].%s" % w, "site.live_services[].%s" % w, "ready.due[].%s" % w}
|
||||
dead = sorted(p for p in schema.F if p not in read and p not in ui_only)
|
||||
self.assertEqual(dead, [], "declared settings nothing reads")
|
||||
|
||||
@@ -230,7 +235,8 @@ class TestSchemaMatchesCode(unittest.TestCase):
|
||||
if ctl and "options" in ctl:
|
||||
ctl["options"].pop("notes", None)
|
||||
return export
|
||||
for build, name in ((make_page.build, "status-page.companionconfig"), (make_page.build_restart, "restart-page.companionconfig")):
|
||||
for build, name in ((make_page.build, "status-page.companionconfig"), (make_page.build_restart, "restart-page.companionconfig"),
|
||||
(make_page.build_ready, "ready-page.companionconfig")):
|
||||
on_disk = json.loads(gzip.open(os.path.join(ROOT, name)).read())
|
||||
self.assertEqual(strip(build(cfg)), strip(on_disk), name)
|
||||
self.assertNotIn("restart_page", {k for k in cfg if k == "nothing"})
|
||||
|
||||
Reference in New Issue
Block a user