dotfiles/bin/rice-media
Sarthak 7f41cf7a82 replace the old dotfiles with the sakura line rice
The bare $HOME repo is gone. This is now the rice: install.sh, rice-*
scripts in bin/, configs in home/ linked into $HOME, theme templates, st
and the particle wallpaper. Clone to ~/rice and run install.sh.
2026-09-14 19:44:44 +05:30

75 lines
2.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# rice-media - now-playing state for the eww panel and bar.
#
# rice-media watch JSON on every track or play-state change (eww deflisten)
# rice-media position JSON {pos, text} for the seek bar (polled while the panel is open)
# rice-media seek <seconds>
#
# Album art is copied into ~/.cache/rice/art under a hash of its URL, so the
# panel only ever points at a file name it created itself.
set -uo pipefail
art_dir="${XDG_CACHE_HOME:-$HOME/.cache}/rice/art"
mkdir -p "$art_dir"
clock() { local s=$1; printf '%d:%02d' $((s / 60)) $((s % 60)); }
art_path() {
local url="$1" key file path=""
[[ -n $url ]] || return 0
key="$url"
if [[ $url == file://* ]]; then
path="${url#file://}"
path=$(printf '%b' "${path//%/\\x}")
# Browsers reuse one temp file for every track, so local art is keyed by mtime too.
key+=":$(stat -c %Y -- "$path" 2>/dev/null)"
fi
file="$art_dir/$(printf '%s' "$key" | sha1sum | cut -c1-16)"
if [[ ! -s $file ]]; then
if [[ -n $path ]]; then
cp -- "$path" "$file" 2>/dev/null
elif [[ $url == http*://* ]]; then
curl -fsSL --max-time 5 -o "$file" -- "$url" 2>/dev/null
fi
fi
[[ -s $file ]] && printf '%s' "$file"
}
emit() {
local status="$1" player="$2" title="$3" artist="$4" album="$5" url="$6" length="$7"
local secs=$(( ${length:-0} / 1000000 ))
jq -cn --arg status "$status" --arg player "$player" --arg title "$title" \
--arg artist "$artist" --arg album "$album" --arg art "$(art_path "$url")" \
--argjson length "$secs" --arg lengthText "$( (( secs > 0 )) && clock "$secs")" \
'{status: $status, player: $player, title: $title, artist: $artist, album: $album,
art: $art, length: $length, lengthText: $lengthText}'
}
watch() {
# Unit separator, not tab: read collapses runs of whitespace separators, so an
# empty field (browsers often send no album) would shift every later field.
local sep=$'\x1f'
while :; do
emit "Stopped" "" "" "" "" "" 0
playerctl --follow metadata --format \
"{{status}}${sep}{{playerName}}${sep}{{title}}${sep}{{artist}}${sep}{{album}}${sep}{{mpris:artUrl}}${sep}{{mpris:length}}" 2>/dev/null |
while IFS="$sep" read -r status player title artist album url length; do
emit "${status:-Stopped}" "$player" "$title" "$artist" "$album" "$url" "${length:-0}"
done
sleep 2
done
}
case "${1:-}" in
watch) watch ;;
position)
pos=$(playerctl position 2>/dev/null | cut -d. -f1)
pos=${pos:-0}
jq -cn --argjson pos "$pos" --arg text "$(clock "$pos")" '{pos: $pos, text: $text}'
;;
seek)
[[ ${2:-} =~ ^[0-9]+$ ]] || { echo "rice-media: seek takes seconds" >&2; exit 2; }
playerctl position "$2"
;;
*) sed -n '2,10p' "$0" | sed 's/^# \{0,1\}//'; exit 2 ;;
esac