109 lines
4.3 KiB
Bash
109 lines
4.3 KiB
Bash
#!/bin/zsh
|
|||
|
|
# install_bridge.sh — install the Resi -> ProPresenter bridge as a login service on THIS Mac.
|
||
|
|
#
|
||
|
|
# Put this folder on the Mac that should run the bridge (one that stays on and logged in),
|
||
|
|
# then run: zsh install_bridge.sh
|
||
|
|
#
|
||
|
|
# First run asks for the Resi login, the decoder, ProPresenter's address and the timer.
|
||
|
|
# Safe to run again: it keeps those answers, replaces the script and restarts the service.
|
||
|
|
# zsh install_bridge.sh --setup ask the questions again
|
||
|
|
# zsh install_bridge.sh --uninstall stop it and remove it from this Mac
|
||
|
|
set -e
|
||
|
|
|
||
|
|
HERE="${0:A:h}"
|
||
|
|
DEST="$HOME/Library/Application Support/resi-propresenter"
|
||
|
|
LABEL="org.waterschurch.resi-propresenter"
|
||
|
|
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
|
||
|
|
LOG="$HOME/Library/Logs/resi-propresenter.log"
|
||
|
|
|
||
|
|
if [[ "$1" == "--uninstall" ]]; then
|
||
|
|
launchctl bootout "gui/$(id -u)/$LABEL" 2>/dev/null || true
|
||
|
|
rm -f "$PLIST"
|
||
|
|
echo "Stopped and removed the service. Settings are kept in $DEST (delete it to forget them)."
|
||
|
|
exit 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
# python3 ships with the Command Line Tools; /usr/bin/python3 is only a stub without them
|
||
|
|
if ! /usr/bin/python3 -c 'import sys' 2>/dev/null; then
|
||
|
|
echo "python3 isn't usable yet. Run: xcode-select --install then run this again."
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Outside ~/Documents: macOS blocks background services from reading it.
|
||
|
|
mkdir -p "$DEST" "$HOME/Library/LaunchAgents" "$HOME/Library/Logs"
|
||
|
|
if [[ ! "$HERE/resi_to_propresenter.py" -ef "$DEST/resi_to_propresenter.py" ]]; then
|
||
|
|
cat "$HERE/resi_to_propresenter.py" > "$DEST/resi_to_propresenter.py.new"
|
||
|
|
mv "$DEST/resi_to_propresenter.py.new" "$DEST/resi_to_propresenter.py"
|
||
|
|
fi
|
||
|
|
# A config shipped alongside (re-installing a known site) seeds a fresh install only.
|
||
|
|
if [[ -f "$HERE/resi_pp_config.json" && ! -f "$DEST/resi_pp_config.json" ]]; then
|
||
|
|
cp "$HERE/resi_pp_config.json" "$DEST/resi_pp_config.json"
|
||
|
|
fi
|
||
|
|
|
||
|
|
complete=$(/usr/bin/python3 - "$DEST/resi_pp_config.json" <<'EOF'
|
||
|
|
import json, subprocess, sys
|
||
|
|
try:
|
||
|
|
c = json.load(open(sys.argv[1]))
|
||
|
|
except Exception:
|
||
|
|
print("no"); sys.exit()
|
||
|
|
ok = c.get("resi_user") and c.get("player") and c.get("propresenter") and c.get("timer_name")
|
||
|
|
ok = ok and subprocess.run(["security", "find-generic-password", "-a", c["resi_user"],
|
||
|
|
"-s", "resi-propresenter"], capture_output=True).returncode == 0
|
||
|
|
print("yes" if ok else "no")
|
||
|
|
EOF
|
||
|
|
)
|
||
|
|
|
||
|
|
if [[ "$complete" != "yes" || "$1" == "--setup" ]]; then
|
||
|
|
# Over SSH the login keychain is locked, and saving the Resi password into it fails
|
||
|
|
# with "User interaction is not allowed" until it is unlocked here.
|
||
|
|
if [[ -n "$SSH_CONNECTION" ]]; then
|
||
|
|
echo "Unlock $(scutil --get ComputerName)'s Keychain: enter the Mac login password for $(whoami)."
|
||
|
|
security unlock-keychain "$HOME/Library/Keychains/login.keychain-db"
|
||
|
|
fi
|
||
|
|
/usr/bin/python3 "$DEST/resi_to_propresenter.py" --setup
|
||
|
|
fi
|
||
|
|
|
||
|
|
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/resi_to_propresenter.py</string>
|
||
|
|
</array>
|
||
|
|
<key>RunAtLoad</key>
|
||
|
|
<true/>
|
||
|
|
<!-- restart if it exits: no network yet at login, Resi/ProPresenter down, a crash -->
|
||
|
|
<key>KeepAlive</key>
|
||
|
|
<true/>
|
||
|
|
<key>ThrottleInterval</key>
|
||
|
|
<integer>30</integer>
|
||
|
|
<key>StandardOutPath</key>
|
||
|
|
<string>$LOG</string>
|
||
|
|
<key>StandardErrorPath</key>
|
||
|
|
<string>$LOG</string>
|
||
|
|
</dict>
|
||
|
|
</plist>
|
||
|
|
EOF
|
||
|
|
|
||
|
|
launchctl bootout "gui/$(id -u)/$LABEL" 2>/dev/null || true
|
||
|
|
launchctl bootstrap "gui/$(id -u)" "$PLIST"
|
||
|
|
echo "Installed. Waiting for the first lines of the log..."
|
||
|
|
sleep 10
|
||
|
|
tail -n 8 "$LOG"
|
||
|
|
echo
|
||
|
|
echo "Running on $(scutil --get ComputerName). Log: $LOG"
|
||
|
|
|
||
|
|
# After a reboot the service only starts once someone is logged in.
|
||
|
|
autologin=$(defaults read /Library/Preferences/com.apple.loginwindow autoLoginUser 2>/dev/null || true)
|
||
|
|
if [[ "$autologin" != "$(whoami)" ]]; then
|
||
|
|
echo
|
||
|
|
echo "NOTE: this Mac doesn't log in to '$(whoami)' automatically, so after a reboot the"
|
||
|
|
echo "countdown won't start until someone logs in. To make it fully hands-off, turn on"
|
||
|
|
echo "System Settings -> Users & Groups -> Automatically log in as $(whoami) (needs FileVault off)."
|
||
|
|
fi
|