added volume manager for pipewire and i3blocks

This commit is contained in:
simon 2021-03-26 13:55:28 +07:00
parent b9b4fd6ddc
commit c49dd68b2f
2 changed files with 154 additions and 0 deletions

View File

@ -34,6 +34,11 @@ A collection of standalone python scripts for the slightly more complicated thin
* call `cpu.py 1` to get the avg from last min
* call `cpu.py 5` to get the avg from last 5 min
* call `cpu.py 15` to get the avg from last 15 min
* **volume.py**: Now compatible with *pipewire*, parses output of `pactl` to output activ sink and current volume to i3blocks and manages music volume hotkeys.
* call `volume.py` without args to output status for i3blocks
* call `volume.py vol_up` to increase volume by 5%
* call `volume.py vol_down` to decrease volume by 5%
* call `volume.py mute` to toggle mute
## i3block_shell

149
i3block_py/volume.py Executable file
View File

@ -0,0 +1,149 @@
#!/usr/bin/env python3
"""
handler for media keys
integrated with pipewire by parsing pactl
"""
import subprocess
import sys
from time import sleep
# signal id to update i3blocks
I3BLOCKS_SIGNAL_ID = 10
def get_status():
""" returns the activ sink pased in a dict """
# get list of sinks
state = subprocess.run(["pactl", "list", "sinks"], capture_output=True)
state_str = state.stdout.decode()
sinks = state_str.split('\n\n')
# loop through sinks
sinks_dict_list = []
for sink in sinks:
sink_lines = sink.split('\n')
# build sink dict
sink_dict = {}
for i in sink_lines:
if ':' in i:
key, value = i.split(':', maxsplit=1)
elif '=' in i:
key, value = i.split('=')
else:
continue
key = key.strip().lower()
value = value.strip().strip('"')
if value:
sink_dict[key] = value
# append to list
sinks_dict_list.append(sink_dict)
# find active
if len(sinks_dict_list) == 1:
activ_sink = sinks_dict_list[0]
else:
for sink_dict in sinks_dict_list:
sink_name = sink_dict['name']
if 'bluez' in sink_name:
activ_sink = sink_dict
break
# return activ
return activ_sink
def get_vol(activ_sink):
""" get the current volume level of activ sink """
vol_string = activ_sink['volume']
vol_list = [i for i in vol_string.split(' / ') if '%' in i]
vol = int(vol_list[0].strip().strip('%'))
return vol
def print_status(activ_sink):
""" print status for i3 blocks """
mute = activ_sink['mute']
# based on sink
if 'bluez' in activ_sink['name']:
# bluetooth
icon = ''
elif activ_sink['active port'] == 'analog-output-headphones':
# headphones
icon = ''
elif activ_sink['active port'] == 'analog-output-speaker':
# speaker
if mute == 'no':
icon = ''
else:
icon = ''
# color
if mute == 'no':
color = "#ffffff"
vol = str(get_vol(activ_sink)) + '%'
else:
color = "#404040"
vol = "MUTE"
# print three lines
print(f'{icon} {vol}')
print(f'{icon}')
print(color)
def mute(activ_sink):
""" toggle mute of activ sink """
sink_id = activ_sink['object.id']
subprocess.call(['pactl', 'set-sink-mute', sink_id, 'toggle'])
def vol_up(activ_sink):
""" increase vol in 5% increments """
sink_id = activ_sink['object.id']
vol = get_vol(activ_sink)
# if uneven vol level
if vol % 5 == 0:
target_vol = vol + 5
else:
target_vol = vol + 5 - (vol % 5)
# how many times to loop
iterations = target_vol - vol
for _ in range(iterations):
subprocess.call(['pactl', 'set-sink-volume', sink_id, '+1%'])
sleep(0.1)
def vol_down(activ_sink):
""" decrese vol in 5% increments """
sink_id = activ_sink['object.id']
vol = get_vol(activ_sink)
# if uneven vol level
if vol % 5 == 0:
target_vol = vol - 5
else:
target_vol = vol - (vol % 5)
# how many times to loop
iterations = vol - target_vol
for _ in range(iterations):
subprocess.call(['pactl', 'set-sink-volume', sink_id, '-1%'])
sleep(0.1)
def main():
""" main to run """
# parse args
args = sys.argv
activ_sink = get_status()
# if args
if len(args) > 1:
arg = args[1]
if arg == 'vol_up':
vol_up(activ_sink)
elif arg == 'vol_down':
vol_down(activ_sink)
elif arg == 'mute':
mute(activ_sink)
activ_sink = get_status()
subprocess.call(['pkill', '-RTMIN+' + str(I3BLOCKS_SIGNAL_ID), 'i3blocks'])
# status
print_status(activ_sink)
if __name__ == '__main__':
main()