119 lines
4.9 KiB
Bash
119 lines
4.9 KiB
Bash
#!/bin/sh
|
|
# Idle-timeout photo slideshow. Installed to /usr/local/bin/idle-gallery, invoked
|
|
# directly by swayidle's `timeout`/`resume` commands in configs/sway/config — not a
|
|
# sway `exec_always`, so the PID-lock-guard idiom in fullscreen-watcher.sh and
|
|
# gesture-control.sh (needed there to survive repeated `swaymsg reload`) does not
|
|
# apply here; swayidle only ever calls this on its own timeout/resume edges, so plain
|
|
# idempotent checks (`mountpoint -q`, `pgrep -f`) are enough.
|
|
#
|
|
# Two-tier fallback, both ways: no gallery credentials configured, an unreachable
|
|
# share, or an empty share must all fall back to the plain output-blank that this
|
|
# script's caller (configs/sway/config) previously did unconditionally — a half-lit
|
|
# fullscreen error is worse than blanking, and this is the ONLY thing standing between
|
|
# an idle kiosk and screen burn-in, so it must never just silently do nothing.
|
|
set -eu
|
|
|
|
CONFIG_ENV=/etc/thinclient-agent/config.env
|
|
CREDENTIALS=/etc/thinclient-agent/gallery-credentials
|
|
MOUNTPOINT=/mnt/gallery
|
|
PLAYLIST="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/idle-gallery-playlist.m3u"
|
|
# Distinguishes this mpv instance from one a person (or thinclient-agent) launched
|
|
# deliberately, so `stop` can pkill exactly it and nothing else — see mpv.conf's own
|
|
# --input-ipc-server for why a marker in argv, not a socket, is the simpler match here.
|
|
MARKER="--playlist=$PLAYLIST"
|
|
DISPLAY_SECONDS=10
|
|
|
|
blank() {
|
|
swaymsg "output * power off" >/dev/null 2>&1 || true
|
|
}
|
|
|
|
# Weather/clock overlay (configs/eww/eww.yuck's weather-overlay window) — this
|
|
# script is the sole owner of its visibility, the same way fullscreen-watcher.sh
|
|
# owns the now-playing widget's. Best-effort throughout: an image built without
|
|
# eww (0800-eww-widget.hook.chroot's documented placeholder path) or a session
|
|
# where the daemon has not started yet must never turn a slideshow failure into a
|
|
# script failure, so every step here is allowed to silently no-op.
|
|
show_weather_overlay() {
|
|
command -v eww >/dev/null 2>&1 || return 0
|
|
eww daemon >/dev/null 2>&1 || true
|
|
eww open weather-overlay >/dev/null 2>&1 || true
|
|
}
|
|
|
|
hide_weather_overlay() {
|
|
command -v eww >/dev/null 2>&1 || return 0
|
|
eww close weather-overlay >/dev/null 2>&1 || true
|
|
}
|
|
|
|
stop_slideshow() {
|
|
pkill -u "$(id -u)" -f "mpv .*${MARKER}" 2>/dev/null || true
|
|
hide_weather_overlay
|
|
}
|
|
|
|
if [ "${1:-start}" = "stop" ]; then
|
|
stop_slideshow
|
|
exit 0
|
|
fi
|
|
|
|
# Already running (e.g. a second timeout fired before the first resume) — nothing to do.
|
|
if pgrep -u "$(id -u)" -f "mpv .*${MARKER}" >/dev/null 2>&1; then
|
|
exit 0
|
|
fi
|
|
|
|
if [ ! -r "$CREDENTIALS" ]; then
|
|
echo "idle-gallery: $CREDENTIALS not set up yet — see hosts/thin-client/README.md. Blanking instead." >&2
|
|
blank
|
|
exit 0
|
|
fi
|
|
|
|
# shellcheck disable=SC1090
|
|
. "$CONFIG_ENV" 2>/dev/null || true
|
|
if [ -z "${GALLERY_SMB_HOST:-}" ]; then
|
|
echo "idle-gallery: GALLERY_SMB_HOST is unset in $CONFIG_ENV. Blanking instead." >&2
|
|
blank
|
|
exit 0
|
|
fi
|
|
|
|
if ! mountpoint -q "$MOUNTPOINT" 2>/dev/null; then
|
|
sudo mkdir -p "$MOUNTPOINT"
|
|
# soft + a short connect timeout: a share that is merely unreachable right now (the
|
|
# container host is off, the network hiccuped) must fail in a few seconds, not hang
|
|
# the whole idle-transition — same "never block on a remote service" rule Phase
|
|
# 11.10 already applies to thinclient-agent's own MQTT connection.
|
|
if ! sudo mount -t cifs "//${GALLERY_SMB_HOST}/gallery" "$MOUNTPOINT" \
|
|
-o "credentials=${CREDENTIALS},ro,vers=3.0,soft,retry=0,echo_interval=5,uid=$(id -u),gid=$(id -g)" \
|
|
2>/tmp/idle-gallery-mount.err
|
|
then
|
|
echo "idle-gallery: mount failed — $(cat /tmp/idle-gallery-mount.err 2>/dev/null). Blanking instead." >&2
|
|
blank
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
find "$MOUNTPOINT" -type f \( \
|
|
-iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.webp' \
|
|
\) 2>/dev/null | shuf > "$PLAYLIST"
|
|
|
|
if [ ! -s "$PLAYLIST" ]; then
|
|
echo "idle-gallery: $MOUNTPOINT has no images. Blanking instead." >&2
|
|
rm -f "$PLAYLIST"
|
|
blank
|
|
exit 0
|
|
fi
|
|
|
|
# Backgrounded, not exec'd: swayidle expects its timeout command to return, not to
|
|
# become the slideshow for as long as it runs. --fs, not --fullscreen: sway's own
|
|
# `for_window [app_id="mpv"] fullscreen enable` already applies, this just tells mpv
|
|
# not to draw window decorations in the instant before that rule lands. app_id stays
|
|
# the plain mpv one on purpose — fullscreen-watcher.sh's now-playing widget already
|
|
# treats any fullscreen mpv window as "visual content on screen" and hides itself,
|
|
# which is exactly the right behaviour here too.
|
|
mpv --fs --no-osc --idle=no --image-display-duration="$DISPLAY_SECONDS" \
|
|
--loop-playlist=inf --shuffle "--playlist=$PLAYLIST" \
|
|
>/tmp/idle-gallery-mpv.log 2>&1 &
|
|
disown
|
|
|
|
# After mpv is actually launched, not before — a failed launch above (this whole
|
|
# block is under `set -e`, so mpv itself failing to start would already have exited
|
|
# the script) must never leave the overlay showing over a blank/off panel.
|
|
show_weather_overlay
|