flatten directory structure, remove system/ nesting
This commit is contained in:
Executable
+136
@@ -0,0 +1,136 @@
|
||||
#!/bin/bash
|
||||
# Description: Switch PulseAudio/PipeWire audio output sinks
|
||||
|
||||
STATE_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/audio-toggle-prev-sink"
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [OPTION]
|
||||
|
||||
Toggle or switch PulseAudio/PipeWire audio output sinks.
|
||||
|
||||
Options:
|
||||
--to <pattern> Switch to a sink whose name matches <pattern>
|
||||
--prev, --previous Switch back to the previously active sink
|
||||
--list List available sinks
|
||||
--current Show the current default sink
|
||||
--move-streams Also move existing audio streams to the new sink
|
||||
--help, -h Show this help message
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
get_current_sink() {
|
||||
pactl info | sed -En 's/Default Sink: (.*)/\1/p'
|
||||
}
|
||||
|
||||
get_sink_description() {
|
||||
local sink="$1"
|
||||
pactl list sinks | awk -v s="$sink" '
|
||||
/^[[:space:]]*Sink #[0-9]+/ { in_block=""; name="" }
|
||||
$1 == "Name:" { name = $2 }
|
||||
name == s && /Description:/ { $1=""; sub(/^[[:space:]]+/, ""); print; exit }
|
||||
'
|
||||
}
|
||||
|
||||
MOVE_STREAMS=0
|
||||
MODE="toggle"
|
||||
TARGET_SINK=""
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--help|-h) usage ;;
|
||||
--list)
|
||||
pactl list short sinks | grep -v easyeffects | while read -r line; do
|
||||
name=$(echo "$line" | awk '{print $2}')
|
||||
desc=$(get_sink_description "$name")
|
||||
echo "$name ($desc)"
|
||||
done
|
||||
exit 0
|
||||
;;
|
||||
--current)
|
||||
sink=$(get_current_sink)
|
||||
desc=$(get_sink_description "$sink")
|
||||
echo "$sink ($desc)"
|
||||
exit 0
|
||||
;;
|
||||
--prev|--previous)
|
||||
if [ ! -f "$STATE_FILE" ]; then
|
||||
notify-send "Audio Toggle" "No previous sink saved"
|
||||
exit 1
|
||||
fi
|
||||
prev=$(cat "$STATE_FILE")
|
||||
if ! pactl list short sinks | awk '{print $2}' | grep -qxF "$prev"; then
|
||||
notify-send "Audio Toggle" "Previous sink no longer available"
|
||||
exit 1
|
||||
fi
|
||||
current=$(get_current_sink)
|
||||
echo "$current" > "$STATE_FILE"
|
||||
TARGET_SINK="$prev"
|
||||
MODE="switch"
|
||||
;;
|
||||
--to)
|
||||
shift
|
||||
[ $# -eq 0 ] && echo "Error: --to requires a pattern" >&2 && exit 1
|
||||
matched=$(pactl list short sinks | grep -v easyeffects | awk '{print $2}' | grep -i "$1" | head -1)
|
||||
[ -z "$matched" ] && echo "Error: no sink matching '$1'" >&2 && exit 1
|
||||
current=$(get_current_sink)
|
||||
echo "$current" > "$STATE_FILE"
|
||||
TARGET_SINK="$matched"
|
||||
MODE="switch"
|
||||
;;
|
||||
--move-streams) MOVE_STREAMS=1 ;;
|
||||
*)
|
||||
echo "Unknown option: $1" >&2
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
SINKS=$(pactl list short sinks | grep -v easyeffects)
|
||||
SINK_COUNT=$(echo "$SINKS" | wc -l)
|
||||
|
||||
if [ "$SINK_COUNT" -eq 0 ]; then
|
||||
notify-send -u critical "Audio Toggle" "No audio sinks available"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CURRENT_SINK=$(get_current_sink)
|
||||
|
||||
if [ "$MODE" = "switch" ] && [ -n "$TARGET_SINK" ]; then
|
||||
NEW_SINK="$TARGET_SINK"
|
||||
else
|
||||
SINK_INDEX=$(echo "$SINKS" | awk -v s="$CURRENT_SINK" '$2 == s { print NR; exit }')
|
||||
SINK_INDEX=${SINK_INDEX:-0}
|
||||
NEXT_INDEX=$((SINK_INDEX % SINK_COUNT + 1))
|
||||
NEW_SINK=$(echo "$SINKS" | awk "NR == $NEXT_INDEX { print \$2; exit }")
|
||||
echo "$CURRENT_SINK" > "$STATE_FILE"
|
||||
fi
|
||||
|
||||
NEW_DESC=$(get_sink_description "$NEW_SINK")
|
||||
notify-send "Audio Output" "Switched to $NEW_DESC" --icon=audio-speakers
|
||||
|
||||
MAX_RETRIES=6
|
||||
RETRIES=0
|
||||
|
||||
while true; do
|
||||
[ "$RETRIES" -ge "$MAX_RETRIES" ] && notify-send -u critical "Audio Toggle" "Failed after $MAX_RETRIES attempts" && break
|
||||
|
||||
pactl set-default-sink "$NEW_SINK"
|
||||
|
||||
[ "$(get_current_sink)" = "$NEW_SINK" ] && break
|
||||
|
||||
RETRIES=$((RETRIES + 1))
|
||||
NEXT_INDEX=$(((SINK_INDEX + RETRIES) % SINK_COUNT + 1))
|
||||
NEW_SINK=$(echo "$SINKS" | awk "NR == $NEXT_INDEX { print \$2; exit }")
|
||||
NEW_DESC=$(get_sink_description "$NEW_SINK")
|
||||
notify-send "Audio Toggle" "Sink unavailable, trying $NEW_DESC..."
|
||||
done
|
||||
|
||||
if [ "$MOVE_STREAMS" = 1 ]; then
|
||||
pactl list short sink-inputs | grep -Eo '^[0-9]+' | while read -r id; do
|
||||
pactl move-sink-input "$id" "$NEW_SINK"
|
||||
done
|
||||
fi
|
||||
Reference in New Issue
Block a user