Last active
August 28, 2023 09:32
-
-
Save Atrate/e65027fdde2aa962a11a3f4a94f6fb08 to your computer and use it in GitHub Desktop.
Bash script to adjust the volume of the currently focused window
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash --posix | |
# Copyright (C) 2020-2023 Atrate <[email protected]> | |
# | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <https://www.gnu.org/licenses/> | |
# $1 is the variable passed to this script. It should be in the format: | |
# '-x%' or '+x%'. For example: '-2%' will lower the volume by 2%. with each | |
# execution of the script. | |
# Perform [[ comparisons in a case-insensitive way | |
# ------------------------------------------------ | |
shopt -s nocasematch | |
# descendent_pids() courtesy of https://unix.stackexchange.com/a/299198 | |
# descendent_pids() function lists all descendant process IDs of a given PID | |
# -------------------------------------------------------------------------- | |
descendent_pids() | |
{ | |
# Get the child process IDs of the given process ID | |
# ------------------------------------------------- | |
pids=$(pgrep -P "$1") | |
echo "$pids" | |
# For each child process, get its descendant process IDs | |
# ------------------------------------------------------ | |
for pid in $pids; | |
do | |
descendent_pids "$pid" | |
done | |
} | |
# For space-delimited strings, check whether they contain an exact word match | |
# --------------------------------------------------------------------------- | |
word_match() | |
{ | |
for word in $2 | |
do | |
if [ "$word" = "$1" ] | |
then | |
return 0 | |
fi | |
done | |
return 1 | |
} | |
# TODO: Make this nicer, maybe with an associative array? | |
# ------------------------------------------------------- | |
process_paout() | |
{ | |
while read -r word | |
do | |
if [ -z "$papid" ]; then | |
local papid=$word | |
elif [ -z "$paname" ]; then | |
local paname=$word | |
elif [ -z "$index" ]; then | |
local index=$word | |
fi | |
if [ -n "$index" ]; then | |
if [[ "$wclass" == *"$paname"* ]] \ | |
|| word_match "$papid" "$2" | |
then | |
pactl set-sink-input-volume "$index" "$1" & | |
return 0 | |
fi | |
unset index papid paname | |
fi | |
done <<< "$paout" | |
# Return 1 if nothing has been found | |
# ---------------------------------- | |
return 1 | |
} | |
# Main program functionality | |
# -------------------------- | |
main() | |
{ | |
# Get the process ID of the window that has focus and the process IDs of its | |
# descendants | |
# -------------------------------------------------------------------------- | |
wpid=$(xdotool getwindowfocus getwindowpid) | |
wclass=$(xdotool getwindowfocus getwindowclassname) | |
# Exit if no window is focused | |
# ---------------------------- | |
if [ -z "$wpid" ] || [ -z "$wclass" ] | |
then | |
exit 1 | |
fi | |
# Get the list of sink inputs, including their process IDs, and process names | |
# and indices (serials) | |
# --------------------------------------------------------------------------- | |
paout=$(pactl list sink-inputs \ | |
| grep -e "object.serial" -e "process.id" -e "process.binary" \ | |
| cut -d "\"" -f2) | |
# For each sink input, check if its process ID or process name is associated | |
# with the focused window or its descendants if we *really* need to | |
# -------------------------------------------------------------------------- | |
process_paout "$1" "$wpid" && exit 0 | |
pstree=$(echo "$wpid"; descendent_pids "$wpid") | |
process_paout "$1" "$pstree" || exit 2 | |
} | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment