atem_watch.js (run with Companion's node + its atem-connection) keeps one connection to the switcher and compares, every second, every Fairlight source's mix option and fader and every camera's settings with atem-reference.xml (the 2026-10-07 14:59:55 restore file). ATEM shows ATEM AUDIO WRONG / ATEM CAMERA WRONG; the hold and Sunday auto-fix send back only what differs. ATEM SW MIDI ON is fixed by quitting ATEM Software Control, switching midiEnabled off and reopening it. Live check: switcher matches the file (0 differences, 1440 camera values). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
2.3 KiB
Bash
61 lines
2.3 KiB
Bash
#!/bin/zsh
|
|
# Install or update the status panel watchdog on this Mac (NA Ingest) as a LaunchAgent.
|
|
# Re-run after changing status_panel.py, coremidi.py or config.json in this folder.
|
|
#
|
|
# zsh install.sh install / update and (re)start
|
|
# zsh install.sh --remove stop it and remove the LaunchAgent (files stay)
|
|
set -e
|
|
SRC=${0:A:h}
|
|
LABEL=org.waterschurch.status-panel
|
|
# App Support, not ~/Documents: launchd-run python3 cannot read ~/Documents.
|
|
DEST="$HOME/Library/Application Support/status-panel"
|
|
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
|
|
DOMAIN="gui/$(id -u)"
|
|
|
|
if [[ "$1" == "--remove" ]]; then
|
|
launchctl bootout "$DOMAIN/$LABEL" 2>/dev/null || true
|
|
rm -f "$PLIST"
|
|
echo "removed $LABEL (files left in $DEST)"
|
|
exit 0
|
|
fi
|
|
|
|
/usr/bin/python3 -c "import json,sys; json.load(open(sys.argv[1]))" "$SRC/config.json"
|
|
mkdir -p "$DEST"
|
|
if [[ -f "$DEST/config.json" ]] && ! cmp -s "$SRC/config.json" "$DEST/config.json"; then
|
|
cp "$DEST/config.json" "$DEST/config.json.bak-$(date +%Y%m%d-%H%M%S)"
|
|
fi
|
|
cp "$SRC/status_panel.py" "$SRC/coremidi.py" "$SRC/netgear.py" "$SRC/config.json" "$SRC/atem_watch.js" "$DEST/"
|
|
[[ -f "$SRC/atem-reference.xml" ]] && cp "$SRC/atem-reference.xml" "$DEST/"
|
|
|
|
cat > "$PLIST" <<EOF
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>Label</key><string>$LABEL</string>
|
|
<key>ProgramArguments</key>
|
|
<array>
|
|
<string>/usr/bin/python3</string>
|
|
<string>$DEST/status_panel.py</string>
|
|
<string>--data-dir</string>
|
|
<string>$DEST</string>
|
|
</array>
|
|
<key>RunAtLoad</key><true/>
|
|
<key>KeepAlive</key><true/>
|
|
<key>ThrottleInterval</key><integer>10</integer>
|
|
<key>StandardErrorPath</key><string>$HOME/Library/Logs/status-panel.err.log</string>
|
|
</dict>
|
|
</plist>
|
|
EOF
|
|
|
|
launchctl bootout "$DOMAIN/$LABEL" 2>/dev/null || true
|
|
# bootout returns before the old job is gone; bootstrapping too early fails with "5: Input/output error".
|
|
for i in {1..50}; do launchctl print "$DOMAIN/$LABEL" >/dev/null 2>&1 || break; sleep 0.2; done
|
|
for attempt in 1 2 3; do
|
|
launchctl bootstrap "$DOMAIN" "$PLIST" && break
|
|
[[ $attempt == 3 ]] && { echo "launchctl bootstrap failed" >&2; exit 1; }
|
|
sleep 1
|
|
done
|
|
echo "installed $LABEL -> $DEST"
|
|
echo "log: ~/Library/Logs/status-panel.log"
|