Add random Hyprland screensaver rotation

This commit is contained in:
2026-04-28 15:48:35 -07:00
parent 8e2128b8d4
commit 3e05939ce3
3 changed files with 168 additions and 43 deletions

View File

@@ -5,7 +5,13 @@ general {
} }
listener { listener {
timeout = 900 timeout = 300
on-timeout = hypr-screensaver stop && hyprctl dispatch dpms off on-timeout = /home/imalison/dotfiles/dotfiles/lib/bin/hypr-screensaver start
on-resume = hyprctl dispatch dpms on on-resume = /home/imalison/dotfiles/dotfiles/lib/bin/hypr-screensaver stop
}
listener {
timeout = 900
on-timeout = /home/imalison/dotfiles/dotfiles/lib/bin/hypr-screensaver stop && hyprctl dispatch dpms off
on-resume = hyprctl dispatch dpms on && /home/imalison/dotfiles/dotfiles/lib/bin/hypr-screensaver stop
} }

View File

@@ -7,6 +7,8 @@ state_dir="${XDG_RUNTIME_DIR:-/tmp}/hypr-screensaver"
mkdir -p "$state_dir" mkdir -p "$state_dir"
title_prefix="hypr-screensaver:" title_prefix="hypr-screensaver:"
screensaver_dir="${HYPR_SCREENSAVER_DIR:-/var/lib/syncthing/sync/Screensaver}"
screensaver_use_dir="${HYPR_SCREENSAVER_USE_DIR:-$screensaver_dir/use}"
usage() { usage() {
cat <<'EOF' cat <<'EOF'
@@ -19,10 +21,24 @@ Commands:
status Exit 0 if any screensaver window is running, otherwise exit 1. status Exit 0 if any screensaver window is running, otherwise exit 1.
session Run the configured screensaver payload for one monitor. session Run the configured screensaver payload for one monitor.
The default payload is an mpv-rendered lavfi animation. You can override the By default, start chooses a random media file from:
source with HYPR_SCREENSAVER_SOURCE, for example: /var/lib/syncthing/sync/Screensaver/use
Populate that directory with symlinks to generated screensaver loops you want
in rotation. You can override the source with HYPR_SCREENSAVER_SOURCE, for
example:
HYPR_SCREENSAVER_SOURCE='/path/to/video.mp4' HYPR_SCREENSAVER_SOURCE='/path/to/video.mp4'
HYPR_SCREENSAVER_SOURCE='av://lavfi:mandelbrot=s=2560x1440:r=60' HYPR_SCREENSAVER_SOURCE='av://lavfi:mandelbrot=s=2560x1440:r=60'
You can also override the rotation directory:
HYPR_SCREENSAVER_USE_DIR='/path/to/use'
HDR handling defaults to matching Hyprland's monitor color-management preset.
Only monitors with preset "hdr" or "hdredid" get HDR colorspace hints. Override
with:
HYPR_SCREENSAVER_HDR_MODE=auto
HYPR_SCREENSAVER_HDR_MODE=sdr
HYPR_SCREENSAVER_HDR_MODE=hdr
EOF EOF
} }
@@ -42,6 +58,15 @@ focused_monitor() {
monitors_json | jq -r '.[] | select(.focused) | .name' monitors_json | jq -r '.[] | select(.focused) | .name'
} }
monitor_color_management_preset() {
local monitor="$1"
monitors_json | jq -r --arg monitor "$monitor" '
.[]
| select(.name == $monitor)
| .colorManagementPreset // "srgb"
'
}
screensaver_window_pids() { screensaver_window_pids() {
hyprctl -j clients 2>/dev/null | jq -r --arg prefix "$title_prefix" ' hyprctl -j clients 2>/dev/null | jq -r --arg prefix "$title_prefix" '
.[] .[]
@@ -77,14 +102,93 @@ default_source() {
"$width" "$height" "$width" "$height"
} }
random_source() {
[ -d "$screensaver_use_dir" ] || return 1
local -a candidates=()
local candidate
while IFS= read -r -d '' candidate; do
candidates+=("$candidate")
done < <(
find -L "$screensaver_use_dir" -maxdepth 1 -type f \
\( \
-iname '*.mp4' -o \
-iname '*.mkv' -o \
-iname '*.mov' -o \
-iname '*.webm' -o \
-iname '*.gif' -o \
-iname '*.png' -o \
-iname '*.jpg' -o \
-iname '*.jpeg' \
\) \
-print0
)
[ "${#candidates[@]}" -gt 0 ] || return 1
printf '%s\n' "${candidates[$((RANDOM % ${#candidates[@]}))]}"
}
monitor_uses_hdr() {
local monitor="$1"
local mode="${HYPR_SCREENSAVER_HDR_MODE:-auto}"
local preset
case "$mode" in
hdr)
return 0
;;
sdr)
return 1
;;
auto)
preset="$(monitor_color_management_preset "$monitor" 2>/dev/null || true)"
case "$preset" in
hdr|hdredid)
return 0
;;
*)
return 1
;;
esac
;;
*)
printf 'Invalid HYPR_SCREENSAVER_HDR_MODE=%s; expected auto, sdr, or hdr\n' "$mode" >&2
return 1
;;
esac
}
mpv_color_args() {
local monitor="$1"
if monitor_uses_hdr "$monitor"; then
printf '%s\0' \
--target-colorspace-hint=yes \
--target-colorspace-hint-mode=source
return
fi
printf '%s\0' \
--target-colorspace-hint=no \
--target-prim=bt.709 \
--target-trc=srgb \
--target-gamut=bt.709 \
--target-peak=80 \
--inverse-tone-mapping=no
}
start() { start() {
local current_monitor spec monitor width height pid local current_monitor spec monitor width height pid source
if is_running; then if is_running; then
exit 0 exit 0
fi fi
current_monitor="$(focused_monitor || true)" current_monitor="$(focused_monitor || true)"
source="${HYPR_SCREENSAVER_SOURCE:-}"
if [ -z "$source" ]; then
source="$(random_source || true)"
fi
while IFS= read -r spec; do while IFS= read -r spec; do
monitor="$(jq -r '.name' <<<"$spec")" monitor="$(jq -r '.name' <<<"$spec")"
@@ -94,6 +198,7 @@ start() {
HYPR_SCREENSAVER_MONITOR="$monitor" \ HYPR_SCREENSAVER_MONITOR="$monitor" \
HYPR_SCREENSAVER_WIDTH="$width" \ HYPR_SCREENSAVER_WIDTH="$width" \
HYPR_SCREENSAVER_HEIGHT="$height" \ HYPR_SCREENSAVER_HEIGHT="$height" \
HYPR_SCREENSAVER_SOURCE="$source" \
"$script_path" session >/dev/null 2>&1 & "$script_path" session >/dev/null 2>&1 &
pid=$! pid=$!
printf '%s\n' "$pid" > "$state_dir/${monitor}.pid" printf '%s\n' "$pid" > "$state_dir/${monitor}.pid"
@@ -124,7 +229,18 @@ session() {
local monitor="${HYPR_SCREENSAVER_MONITOR:?missing HYPR_SCREENSAVER_MONITOR}" local monitor="${HYPR_SCREENSAVER_MONITOR:?missing HYPR_SCREENSAVER_MONITOR}"
local width="${HYPR_SCREENSAVER_WIDTH:-1920}" local width="${HYPR_SCREENSAVER_WIDTH:-1920}"
local height="${HYPR_SCREENSAVER_HEIGHT:-1080}" local height="${HYPR_SCREENSAVER_HEIGHT:-1080}"
local source="${HYPR_SCREENSAVER_SOURCE:-$(default_source "$width" "$height")}" local source="${HYPR_SCREENSAVER_SOURCE:-}"
local -a color_args=()
if [ -z "$source" ]; then
source="$(random_source || true)"
fi
if [ -z "$source" ]; then
source="$(default_source "$width" "$height")"
fi
while IFS= read -r -d '' arg; do
color_args+=("$arg")
done < <(mpv_color_args "$monitor")
local -a mpv_args=( local -a mpv_args=(
--no-config --no-config
--really-quiet --really-quiet
@@ -144,6 +260,7 @@ session() {
--wayland-app-id=hypr-screensaver --wayland-app-id=hypr-screensaver
--title="${title_prefix}${monitor}" --title="${title_prefix}${monitor}"
--image-display-duration=inf --image-display-duration=inf
"${color_args[@]}"
"$source" "$source"
) )

View File

@@ -2,17 +2,19 @@
makeEnable, makeEnable,
config, config,
... ...
}: let }:
let
shared = import ../nix-shared/syncthing.nix; shared = import ../nix-shared/syncthing.nix;
inherit (shared) devices allDevices; inherit (shared) devices allDevices;
in in
makeEnable config "myModules.syncthing" true { makeEnable config "myModules.syncthing" true {
system.activationScripts.syncthingPermissions = { system.activationScripts.syncthingPermissions = {
text = '' text = ''
mkdir -p /var/lib/syncthing/sync
mkdir -p /var/lib/syncthing/sync/Screensaver/use
mkdir -p /var/lib/syncthing/railbird
chown -R syncthing:syncthing /var/lib/syncthing chown -R syncthing:syncthing /var/lib/syncthing
chmod -R 2770 /var/lib/syncthing chmod -R 2770 /var/lib/syncthing
mkdir -p /var/lib/syncthing/sync
mkdir -p /var/lib/syncthing/railbird
''; '';
}; };
systemd.services.syncthing = { systemd.services.syncthing = {
@@ -45,4 +47,4 @@ in
}; };
}; };
}; };
} }