SmartestHome/hosts/steam-tv-box/configs/session/session-watcher

61 lines
3.2 KiB
Bash
Executable File

#!/bin/sh
# Watches sway for the user leaving Big Picture. Installed to /usr/local/bin/session-watcher.
#
# THIS IS THE "MEDIA APPS ONLY START WHEN YOU LEAVE BIG PICTURE" MECHANISM, HALF TWO.
# Read steam-session's header first — it explains why there are two halves.
#
# The case this one covers: Steam is *still running*, but the user is no longer looking
# at it. "Exit Big Picture mode" (which drops to Steam's desktop client), the remote's
# channel keys, $mod+3, or Home Assistant's Screen select — all of those change the
# focused sway workspace and none of them make the Steam process exit, so steam-session
# never resumes and something else has to notice.
#
# WHY WORKSPACE EVENTS AND NOT WINDOW TITLES
# ------------------------------------------
# The obvious implementation is to poll for a window titled "Steam Big Picture Mode"
# and react when it goes away. That was rejected: the title, the window class and the
# very existence of a separate Big Picture window have all changed across Steam client
# rewrites, and a media session that silently stops appearing after a Steam update is a
# bad failure — it looks like the image is broken, not like a string moved. A sway
# workspace name is a contract this repo owns and can only change by editing the sway
# config and steamtv_agent/sway_control.py together.
#
# Cost: one blocked read on a socket, and a jq per workspace switch. It publishes
# nothing and listens on nothing — the session-mode sensor in Home Assistant is
# steamtv-agent asking sway, not this script pushing anywhere. (Adding an inbound
# listener here would breach the MQTT-is-the-only-control-surface rule; see
# steamtv_agent/mqtt_discovery.py.)
set -eu
WS_STEAM="1:steam"
if ! command -v jq >/dev/null 2>&1; then
echo "session-watcher: jq is missing; the media session will only start when Steam" >&2
echo " itself exits (steam-session's path). Install jq and reload sway." >&2
exit 1
fi
# `swaymsg -m` streams one JSON object per event line and blocks forever. If sway goes
# away the pipe closes and this exits — which is correct, since sway restarting means
# `exec_always` starts a fresh watcher.
swaymsg -t subscribe -m '["workspace"]' 2>/dev/null | while read -r event; do
# "focus" is the only change that means the user went somewhere; "init", "empty" and
# "rename" fire during ordinary window churn and must not trigger a launch.
change=$(printf '%s' "$event" | jq -r '.change // empty' 2>/dev/null) || continue
[ "$change" = "focus" ] || continue
current=$(printf '%s' "$event" | jq -r '.current.name // empty' 2>/dev/null) || continue
[ -n "$current" ] || continue
# An `if` rather than `[ … ] && continue`: the && form returns non-zero when the test
# is false, which under `set -e` would kill the watcher the first time somebody moved
# to a non-Steam workspace — i.e. exactly once, silently, on the first use.
if [ "$current" = "$WS_STEAM" ]; then
continue
fi
# No --focus: the user has already chosen where they want to be, and yanking them to
# the browser workspace because they pressed the channel key would be worse than
# doing nothing. This only makes sure the apps exist.
/usr/local/bin/media-session start >/dev/null 2>&1 || true
done