scripts/rofi-pulse-sink.sh

342 lines
9.9 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# Purpose {{{
# This script will allow to change default output sink for PulseAudio
# 1. Display the current default and all available outputs.
# 2. Set the selected output as default.
# 3. Ensure to unmute the new default output.
#
# 2021-11-27
# }}}
# Vars {{{
readonly PROGNAME=$(basename "${0}")
readonly PROGDIR=$(readlink -m $(dirname "${0}"))
readonly ARGS="${*}"
readonly NBARGS="${#}"
[ -z "${DEBUG}" ] && DEBUG=1
## Export DEBUG for sub-script
export DEBUG
## Colors
readonly PURPLE='\033[1;35m'
readonly RED='\033[0;31m'
readonly RESET='\033[0m'
readonly COLOR_DEBUG="${PURPLE}"
# }}}
usage() { # {{{
cat <<- EOF
usage: $PROGNAME [-d|-h]
Select a new default output sink for PulseAudio and unmute it.
EXAMPLES:
- Choose new default output.
${PROGNAME}
OPTIONS:
-d,--debug
Enable debug messages.
-h,--help
Print this help message.
EOF
}
# }}}
debug_message() { # {{{
local_message="${1}"
## Print message if DEBUG is enable (=0)
[ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG ${PROGNAME}: ${local_message}"
return 0
}
# }}}
error_message() { # {{{
local_error_message="${1}"
local_error_code="${2}"
## Print message if DEBUG is enable (=0)
[ "${DEBUG}" -eq "0" ] && printf '%b\n' "ERROR ${PROGNAME}: ${RED}${local_error_message}${RESET}"
exit "${local_error_code:=66}"
}
# }}}
define_vars() { # {{{
## Temp file vars {{{
readonly pa_sink_list_path="/tmp/${PROGNAME}.list"
## }}}
}
# }}}
is_command_absent() { # {{{
local_command_absent_cmd="${1}"
## A command is absent by default
return_command_absent="0"
if [ "$(command -v ${local_command_absent_cmd})" ]; then
debug_message "is_command_absent \
${RED}${local_command_absent_cmd}${COLOR_DEBUG} seems present on this host."
return_command_absent="1"
else
debug_message "is_command_absent \
${RED}${local_command_absent_cmd}${COLOR_DEBUG} is not available on this host."
return_command_absent="0"
fi
return "${return_command_absent}"
}
# }}}
get_pulseaudio_sink_list() { # {{{
## Return False by default
return_get_pulseaudio_sink_list="1"
debug_message "get_pulseaudio_sink_list \
Create or empty ${RED}${pa_sink_list_path}${COLOR_DEBUG} file to store pulseaudio sinks."
true > "${pa_sink_list_path}"
## Get sinks list with pactl (index and description)
## Merge every two lines
if pactl list sinks | \
grep --only-matching --perl-regexp '((?<=Sink #)[[:digit:].]*|(?<=Description: ).*)' | \
paste --delimiters=" " - - > "${pa_sink_list_path}"; then
if [ -s "${pa_sink_list_path}" ]; then
debug_message "get_pulseaudio_sink_list \
PulseAudio sinks list successfully created (see ${pa_sink_list_path} file)."
return_get_pulseaudio_sink_list="0"
else
debug_message "get_pulseaudio_sink_list \
Error, the PulseAudio sinks list is empty (${pa_sink_list_path} file)."
return_get_pulseaudio_sink_list="1"
fi
else
debug_message "get_pulseaudio_sink_list \
Error in ${RED}pacmd list-sinks${COLOR_DEBUG} command."
return_get_pulseaudio_sink_list="1"
fi
return "${return_get_pulseaudio_sink_list}"
}
# }}}
get_pulseaudio_current_sink() { # {{{
## Return False by default
return_get_pulseaudio_current_sink="1"
pa_current_sink_name=$(pactl info | awk '/Default Sink:/ { print $NF }')
## If variable for current default sink name contains something
if printf '%b' "${pa_current_sink_name}" | grep --silent -- "."; then
debug_message "get_pulseaudio_current_sink \
PulseAudio current default sink name: ${RED}${pa_current_sink_name}${COLOR_DEBUG}."
pa_current_sink_description=$(pactl list sinks \
| grep --after-context=1 -- "Name: ${pa_current_sink_name}" \
| sed --silent 's/^.*Description: \(.*\)/\1/p')
### If variable for current default sink description contains something
if printf '%b' "${pa_current_sink_description}" | grep --silent -- "."; then
debug_message "get_pulseaudio_current_sink \
PulseAudio current deault sink description: ${RED}${pa_current_sink_description}${COLOR_DEBUG}."
return_get_pulseaudio_current_sink="0"
else
debug_message "get_pulseaudio_current_sink \
Can't get PulseAudio current deault sink description (got: ${pa_current_sink_description})."
return_get_pulseaudio_current_sink="1"
fi
else
debug_message "get_pulseaudio_current_sink \
Can't get PulseAudio current sink name (got: ${pa_current_sink_name})."
return_get_pulseaudio_current_sink="1"
fi
return "${return_get_pulseaudio_current_sink}"
}
# }}}
choose_pulseaudio_sink() { # {{{
## Return False by default
return_choose_pulseaudio_sink="1"
debug_message "choose_pulseaudio_sink \
Display PulseAudio sinks list with rofi to select one."
choosen_sink=$(rofi -theme solarized_alternate -location 2 -l 4 -no-auto-select -i -dmenu -p "New output sink for PulseAudio (current: ${pa_current_sink_description:-Not available})" < "${pa_sink_list_path}")
choosen_sink_index=$(printf -- '%s' "${choosen_sink}" | cut --delimiter=" " --field=1)
choosen_sink_description=$(printf -- '%s' "${choosen_sink}" | cut --delimiter=" " --field=2-)
## If no sink was selected (empty var)
if [ -z "${choosen_sink_index}" ]; then
debug_message "choose_pulseaudio_sink \
Choosen sink var is ${RED}empty${COLOR_DEBUG}."
return_choose_pulseaudio_sink="1"
else
debug_message "choose_pulseaudio_sink \
PulseAudio choosen sink is ${RED}${choosen_sink_description}${COLOR_DEBUG} (index: ${RED}${choosen_sink_index}${COLOR_DEBUG})."
return_choose_pulseaudio_sink="0"
fi
return "${return_choose_pulseaudio_sink}"
}
# }}}
set_default_pulseaudio_sink() { # {{{
## Return False by default
return_set_default_pulseaudio_sink="1"
debug_message "set_default_pulseaudio_sink \
Try to set ${RED}${choosen_sink_description}${COLOR_DEBUG} (index: ${RED}${choosen_sink_index}${COLOR_DEBUG}) default PulseAudio sink."
if pactl set-default-sink "${choosen_sink_index}"; then
debug_message "set_default_pulseaudio_sink \
${RED}${choosen_sink_description}${COLOR_DEBUG} is now the default output device."
return_set_default_pulseaudio_sink="0"
else
debug_message "set_default_pulseaudio_sink \
Error with ${RED}pacmd set-default-sink${COLOR_DEBUG} command."
return_set_default_pulseaudio_sink="1"
fi
return "${return_set_default_pulseaudio_sink}"
}
# }}}
unmute_default_pulseaudio_sink() { # {{{
## Return False by default
return_unmute_default_pulseaudio_sink="1"
debug_message "unmute_default_pulseaudio_sink \
Try to unmute ${RED}@DEFAULT_SINK@${COLOR_DEBUG} for PulseAudio."
if pactl set-sink-mute @DEFAULT_SINK@ false; then
debug_message "unmute_default_pulseaudio_sink \
${RED}@DEFAULT_SINK@${COLOR_DEBUG} for PulseAudio is now unmute."
return_unmute_default_pulseaudio_sink="0"
else
debug_message "unmute_default_pulseaudio_sink \
Error with ${RED}pacmd set-sink-mute${COLOR_DEBUG} command."
return_unmute_default_pulseaudio_sink="1"
fi
return "${return_unmute_default_pulseaudio_sink}"
}
# }}}
main() { # {{{
## If rofi command is absent from the system {{{
### Exit
is_command_absent "rofi" \
&& exit 0
## }}}
## If pacmd command is absent from the system {{{
### Exit
is_command_absent "pacmd" \
&& exit 0
## }}}
## Define all vars
define_vars
## Try to get the sinks list {{{
### OR Exit with error message
get_pulseaudio_sink_list \
|| error_message "Can't get the PulseAudio sinks list. Please use --debug option." 1
## }}}
## Try to get current default sink {{{
### OR just display debug message
get_pulseaudio_current_sink \
|| debug_message "Can't get the PulseAudio current default sink."
## }}}
## Choose a sink with rofi {{{
### OR Exit with error message
choose_pulseaudio_sink \
|| error_message "Can't get the PulseAudio sinks list. Please use --debug option." 2
## }}}
## Set default output sink/device for PulseAudio {{{
### OR Exit with error message
set_default_pulseaudio_sink \
|| error_message "Can't set the selected sink (${choosen_sink_description}) as default output sink/device. Please use --debug option." 3
## }}}
## Try to unmute the default output sink {{{
### OR Exit with error message
unmute_default_pulseaudio_sink \
|| error_message "Can't unmute the selected sink (${choosen_sink_description}). Please use --debug option." 4
## }}}
}
# }}}
# Manage arguments # {{{
# This code can't be in a function due to argument management
if [ ! "${NBARGS}" -eq "0" ]; then
manage_arg="0"
## If the first argument is not an option
if ! printf -- '%s' "${1}" | grep -q -E -- "^-+";
then
## Print help message and exit
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
fi
# Parse all options (start with a "-") one by one
while printf -- '%s' "${1}" | grep -q -E -- "^-+"; do
case "${1}" in
-d|--debug ) ## debug
DEBUG=0
;;
-h|--help ) ## help
usage
## Exit after help informations
exit 0
;;
* ) ## unknow option
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
;;
esac
debug_message "Arguments management \
${RED}${1}${COLOR_DEBUG} option managed."
## Move to the next argument
shift
manage_arg=$((manage_arg+1))
done
debug_message "Arguments management \
${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed."
else
debug_message "Arguments management \
No arguments/options to manage."
fi
# }}}
main
exit 0