dotfiles/mixer
2021-01-31 22:18:35 +01:00

189 lines
5.1 KiB
Bash
Executable file

#!/usr/bin/env sh
###########################################
# Displays audio sinks and control volume #
###########################################
sink="$HOME/.cache/mixer/sink"
save="$HOME/.cache/mixer/save"
# list options
help() {
echo "Usage:
 listen [monitor events and display current sink volume]
 update {+,-}1% [update current sink volume]
 switch [switch to the next sink]
 restore [restore saved configuration]
 help, --help [this help page]
懶 toggle [toggle between play and pause]
玲 prev [play previous song]
怜 next [play next song]
栗 stop [stop playing]
"
}
# return selected color generated by pywal
get_color() {
grep -o "$1.*" "$HOME/.cache/wal/colors.sh" | sed "s/$1='\(.*\)'.*/\1/"
}
# display volume icon
# @param: volume between 1 and 100, normalized_volume otherwise
volume_icon() {
volume=${1:-$(normalized_volume)}
len_icons=$(echo "$volume_icons" | wc -l)
for i in $(seq 1 "$len_icons"); do
if [ "$(echo "$i * (100/$len_icons) + 1" | bc -l | xargs printf "%0.f\n" )" -ge "${volume}" ]; then
echo "$volume_icons" | sed "$i!d"
break
fi
done
}
# return current volume associated with current sink
current_volume() {
sndioctl "$(current_sink).level" | sed '/device/d' | cut -f 2 -d '='
}
# print current sink
current_sink() {
cat "$sink"
}
# return volume between 0 and 100%
# @param: volume between 0 and 1.0, current_volume otherwise
normalized_volume() {
volume=${1:-$(current_volume)}
echo "${volume} * 100" | bc | xargs printf "%0.f\n"
}
# save sinks with volumes
save() {
aucatctl | tr '\n' ' ' > "$save"
}
# update volume with increment of value
# value between 0..100
# increment +n or -n
update() {
operand=$(echo "$1" | grep -o '+\|-')
value=$(echo "$1" | grep -o '[[:digit:]]*')
volume=$(normalized_volume)
{ [ "$volume" -eq 0 ] && [ "$operand" = "-" ]; } || { [ "$volume" -eq 100 ] && [ "$operand" = "+" ]; } && return
sndioctl "$(current_sink).level=$operand$(echo "scale=2;$value/100" | bc -l)"
save
}
# automatically set current sink to last modified
auto_switch_sink() {
new_sink="$(echo "$1" | sed '/device/d' | cut -f 1 -d '.')"
[ "$new_sink" = '' ] && return
[ "$new_sink" = "$(current_sink)" ] || echo "$new_sink" > "$sink"
}
mpris() {
while true; do
player_status=$(playerctl status 2> /dev/null)
if [ "$player_status" = "Playing" ]; then
volume=$(playerctl status --format '{{volume}}')
player=$(playerctl status --format '{{playerName}}')
normalized_volume=$(normalized_volume "$volume")
echo "$player %{F$color}$(volume_icon "$normalized_volume")%{F-} ${normalized_volume}%"
sleep 1
fi
done
}
# listen on sndiod new events and sink change
listen() {
# on separated thread listen to sndiod events
{
sndioctl -m | while read -r MSG; do
auto_switch_sink "$MSG"
display
save
done
} &
# watch for current sink value stored in file change
while inotifywait -q -q -e close_write "$sink"; do
display
done
}
# display sink and associated volume in polybar
display() {
echo "$(current_sink) %{F$color}$(volume_icon)%{F-} $(normalized_volume)%"
}
# switch to the next available sink
switch() {
sinks=$(sndioctl | sed '/device/d')
max_index=$(echo "$sinks" | wc -l)
current_index=$(echo "$sinks" | grep -n "$(current_sink)" | cut -f 1 -d ':')
next_index=$(echo "$current_index%$max_index + 1" | bc)
echo "$sinks" | sed "$next_index!d" | cut -f 1 -d '=' | sed 's/.level//' > "$sink"
}
# restore last saved volume per sink
restore() {
[ -f "$save" ] && aucatctl "$(cat "$save")"
}
is_mpd_sink() {
[ "$(current_sink | grep -o 'mpd')" = "mpd" ] && echo "true" || echo "false"
}
toggle() {
[ "$(is_mpd_sink)" = "true" ] && mpc toggle || playerctl play-pause
}
prev() {
[ "$(is_mpd_sink)" = "true" ] && mpc prev || playerctl previous
}
next() {
[ "$(is_mpd_sink)" = "true" ] && mpc next || playerctl next
}
stop() {
[ "$(is_mpd_sink)" = "true" ] && mpc stop || playerctl stop
}
main() {
[ ! -f "$sink" ] && mkdir -p "$HOME/.cache/mixer" && echo "output" > "$sink"
color=$(get_color 'color2')
volume_icons="奄\n奔\n墳\n"
case "$1" in
listen)
case "$2" in
--color=?*)
case "$3" in
--volume-icons=?*)
volume_icons=$(echo "${3#*=}" | tr ',' '\n')
esac
color=$(get_color "${2#*=}");;
esac
listen;;
mpris)
mpris;;
update)
shift;
update "$@";;
switch)
switch;;
restore)
restore;;
prev)
prev;;
next)
next;;
toggle)
toggle;;
stop)
stop;;
--help|-h|*)
help;;
esac
}
main "$@"