189 lines
5.1 KiB
Bash
Executable file
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 "$@"
|