Skip to content

Instantly share code, notes, and snippets.

@erincerys
Last active September 3, 2025 19:50
Show Gist options
  • Save erincerys/681bf686b5013a1aa2fb10477a0eabef to your computer and use it in GitHub Desktop.
Save erincerys/681bf686b5013a1aa2fb10477a0eabef to your computer and use it in GitHub Desktop.
Audio play/pause keybind for i3wm and pipewire, tested with Spotify, Strawberry, and Firefox
# usage: place in ~/.i3/config
bindsym XF86AudioPrev exec playerctl previous
bindsym XF86AudioNext exec playerctl next
bindsym XF86AudioPlay exec playerctl -p "$(~/.local/bin/get-player-name)" play-pause
bindsym XF86AudioStop exec playerctl -p "$(~/.local/bin/get-player-name)" pause
bindsym Mod4+F5 exec playerctl previous
bindsym Mod4+F6 exec playerctl next
bindsym Mod4+F7 exec playerctl -p "$(~/.local/bin/get-player-name)" play-pause
bindsym Mod4+F8 exec playerctl -p "$(~/.local/bin/get-player-name)" stop
bindsym Mod4+Home exec playerctl previous
bindsym Mod4+End exec playerctl next
bindsym Mod4+Next exec playerctl -p "$(~/.local/bin/get-player-name)" play-pause
#!/bin/bash
# purpose: query pipewire for application name that is actively playing audio
# usage: symlink file to ~/.local/share/bin/get-active-player
pw-dump | jq -r '
.[] |
select((.type//"") | test("Node")) |
( .info?.props // .props // {} ) as $p |
($p["media.class"] // "") as $mc |
select($mc | test("Stream/Output/Audio|Audio/Stream/Output|Output/Audio|Audio/Output")) |
.id
' | while read -r id; do
out=$(pw-cli info "$id" 2>/dev/null) || continue
state=$(printf '%s\n' "$out" | sed -n 's/.*state: *"\([^"]*\)".*/\1/p')
[ "$state" != "running" ] && continue
app=$(printf '%s\n' "$out" \
| sed -n -e 's/.*application.name = *"\([^"]*\)".*/\1/p' \
-e 's/.*application.process.binary = *"\([^"]*\)".*/\1/p' \
-e 's/.*media.name = *"\([^"]*\)".*/\1/p' \
| head -n1 \
)
printf '%s\n' "${app:-unknown}"
done
#!/bin/bash -a
# logic flow:
# 1. call other script
# 2. return active player name and cache it in a state file, if successful response
# 3. otherwise, return player name from cache/state file, if set
# 4. otherwise, return 'unknown'
# usage:
# - symlink file to ~/.local/share/bin/get-player
# - create ~/.local/state directory if needed
_STATE="$HOME/.local/state/player"
test -f "$_STATE" && read _CACHE < "$_STATE"
read -a _PLAYERS < <(
"$HOME/.local/bin/get-active-player-name" |
tr '[:upper:]' '[:lower:]'
)
_PLAYER="${_PLAYERS[0]}"
if [ -n "$_PLAYER" ]; then
if [[ "$_PLAYER" = 'unknown' && -z "$_CACHE" ]]; then
echo -n "$_PLAYER" >&2
elif [[ "$_PLAYER" != 'unknown' || -z "$_CACHE" ]]; then
[ "$_PLAYER" = 'firefox' ] &&
_PLAYER="$(playerctl -l | grep $_PLAYER)"
echo -n "$_PLAYER" | tee "$_STATE"
fi
elif [[ -z "$_PLAYER" || -n "$_CACHE" ]]; then
cat "$_STATE"
else
printf 'unknown' >&2
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment