aboutsummaryrefslogtreecommitdiff
path: root/extras/HOME/.local/bin/set-app-volume.sh
blob: cc161852458415054a252ffc64c7f21f446779ae (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env bash

set -e

# Best-effort script to control volume of the focused application,
# falling back to the default sink.
#
# MODIFIED: Now checks for Spotify and uses 'playerctl' if found.
# MODIFIED: Pactl branch now matches on process binary name, not PID.

USAGE="Usage: $(basename "$0") WINDOW_ID [--up | --down | --set <0-100>]"
CHANGE_PCT="5" # Percent to change

# Get the focused window ID
FOCUSED_WIN_ID="$1"
shift;

ACTION=$1
ARGUMENT=$2

# --- Check if the window is Spotify ---
IS_SPOTIFY=0
if [ -n "$FOCUSED_WIN_ID" ] && [ "$FOCUSED_WIN_ID" != "0" ]; then
    # xprop output is: WM_CLASS(STRING) = "spotify", "Spotify"
    # We check for "spotify" case-insensitive
    if xprop -id "$FOCUSED_WIN_ID" WM_CLASS | grep -q -i "spotify"; then
        IS_SPOTIFY=1
    fi
fi


# --- BRANCH 1: SPOTIFY LOGIC (use playerctl) ---
if [ "$IS_SPOTIFY" -eq 1 ]; then
    echo "Spotify window detected. Using playerctl." >&2

    # playerctl volume is a float from 0.0 to 1.0
    # We use awk to convert our 5% to 0.05
    CHANGE_FLOAT=$(awk "BEGIN {print $CHANGE_PCT / 100}")

    case $ACTION in
        --up)
            playerctl --player=spotify volume "${CHANGE_FLOAT}+"
            ;;
        --down)
            playerctl --player=spotify volume "${CHANGE_FLOAT}-"
            ;;
        --set)
            # Convert 0-100 input to 0.0-1.0 float
            TARGET_VOL=$(awk "BEGIN {print $ARGUMENT / 100}")
            playerctl --player=spotify volume "$TARGET_VOL"
            ;;
        *)
            echo "$USAGE" >&2
            exit 1
            ;;
    esac

    # We are done. Exit successfully.
    exit 0
fi


# --- BRANCH 2: DEFAULT PACTL LOGIC (if not Spotify) ---
echo "Non-Spotify window. Using pactl." >&2

SINK_INPUT_INDEX=""
if [ -n "$FOCUSED_WIN_ID" ] && [ "$FOCUSED_WIN_ID" != "0" ]; then
    # Get the PID of the focused window
    PID=$(xprop -id "$FOCUSED_WIN_ID" _NET_WM_PID | awk '{print $NF}')

    if [ -n "$PID" ]; then
        # NEW: Get the binary name from the PID
        BINARY_NAME=$(ps -p "$PID" -o comm= | tr -d '[:space:]')
        echo "Looking for binary $BINARY_NAME"

        if [ -n "$BINARY_NAME" ]; then
            # Find PulseAudio sink input index for this BINARY_NAME
            # This is more robust than PID for apps like browsers
            SINK_INPUT_INDEX=$(pactl list sink-inputs | perl -ne '
      BEGIN {
        our $sink_id = -1;
        our $maybe_sink_id = -1;
      }
      if (/Sink Input #(\d+)/) {
        $maybe_sink_id = $1;
      }
      # Match the binary name, e.g., application.process.binary = "firefox"
      if (/application\.process\.binary = "'"$BINARY_NAME"'"/) {
        $sink_id = $maybe_sink_id;
      }
      END { print "$sink_id\n"; }
    ')
        fi
    fi
fi

CHANGE="${CHANGE_PCT}%"

set_volume() {
    local target=$1
    local diff=$2
    if [[ "$target" == *#* ]]; then
        echo "Setting volume for Sink Input $target ($diff)" >&2
        pactl set-sink-input-volume "${target#SINK INPUT #}" "$diff"
    else
        echo "Setting default sink volume ($diff)" >&2
        pactl set-sink-volume "$target" "$diff"
    fi
}

TARGET="@DEFAULT_SINK@"
if [ -n "$SINK_INPUT_INDEX" ] && [ "$SINK_INPUT_INDEX" -ne -1 ]; then
    TARGET="SINK INPUT #$SINK_INPUT_INDEX"
fi

case $ACTION in
    --up)
        set_volume "$TARGET" "+$CHANGE"
        ;;
    --down)
        set_volume "$TARGET" "-$CHANGE"
        ;;
    --set)
        # pactl can take a percentage directly
        set_volume "$TARGET" "${ARGUMENT}%"
        ;;
    *)
        echo "$USAGE" >&2
        exit 1
        ;;
esac