2020-02-23 13:45:42 +01:00
# pylint: disable=C0111,R0903
2020-05-03 11:15:52 +02:00
""" Displays volume and mute status and controls for PulseAudio devices. Use wheel up and down to change volume, left click mutes, right click opens pavucontrol.
2020-02-23 13:45:42 +01:00
Aliases : pasink ( use this to control output instead of input ) , pasource
Parameters :
* pulseaudio . autostart : If set to ' true ' ( default is ' false ' ) , automatically starts the pulseaudio daemon if it is not running
* pulseaudio . percent_change : How much to change volume by when scrolling on the module ( default is 2 % )
* pulseaudio . limit : Upper limit for setting the volume ( default is 0 % , which means ' no limit ' )
Note : If the left and right channels have different volumes , the limit might not be reached exactly .
* pulseaudio . showbars : 1 for showing volume bars , requires - - markup = pango ;
0 for not showing volume bars ( default )
Requires the following executable :
* pulseaudio
* pactl
* pavucontrol
2020-05-03 11:15:52 +02:00
"""
2020-02-23 13:45:42 +01:00
import re
import logging
import core . module
import core . widget
import core . input
import util . cli
2020-02-23 13:59:47 +01:00
import util . graph
import util . format
2020-02-23 13:45:42 +01:00
2020-05-03 11:15:52 +02:00
2020-02-23 13:45:42 +01:00
class Module ( core . module . Module ) :
2020-04-26 16:39:24 +02:00
def __init__ ( self , config , theme , channel ) :
super ( ) . __init__ ( config , theme , core . widget . Widget ( self . volume ) )
2020-02-23 13:45:42 +01:00
2020-05-03 11:15:52 +02:00
if util . format . asbool ( self . parameter ( " autostart " , False ) ) :
util . cli . execute ( " pulseaudio --start " , ignore_errors = True )
2020-02-23 13:45:42 +01:00
2020-05-03 11:15:52 +02:00
self . _change = util . format . asint (
self . parameter ( " percent_change " , " 2 % " ) . strip ( " % " ) , 0 , 100
)
self . _limit = util . format . asint ( self . parameter ( " limit " , " 0 % " ) . strip ( " % " ) , 0 )
2020-02-23 13:45:42 +01:00
self . _left = 0
self . _right = 0
self . _mono = 0
self . _mute = False
self . _failed = False
self . _channel = channel
2020-05-03 11:15:52 +02:00
self . _showbars = util . format . asbool ( self . parameter ( " showbars " , 0 ) )
2020-02-23 13:45:42 +01:00
self . _patterns = [
2020-05-03 11:15:52 +02:00
{ " expr " : " Name: " , " callback " : ( lambda line : False ) } ,
{
" expr " : " Mute: " ,
" callback " : (
lambda line : self . mute ( False if " no " in line . lower ( ) else True )
) ,
} ,
{ " expr " : " Volume: " , " callback " : self . getvolume } ,
2020-02-23 13:45:42 +01:00
]
2020-05-03 11:15:52 +02:00
core . input . register ( self , button = core . input . RIGHT_MOUSE , cmd = " pavucontrol " )
2020-02-23 13:45:42 +01:00
events = [
2020-05-03 11:15:52 +02:00
{ " type " : " mute " , " action " : self . toggle , " button " : core . input . LEFT_MOUSE } ,
{
" type " : " volume " ,
" action " : self . increase_volume ,
" button " : core . input . WHEEL_UP ,
} ,
{
" type " : " volume " ,
" action " : self . decrease_volume ,
" button " : core . input . WHEEL_DOWN ,
} ,
2020-02-23 13:45:42 +01:00
]
for event in events :
2020-05-03 11:15:52 +02:00
core . input . register ( self , button = event [ " button " ] , cmd = event [ " action " ] )
2020-02-23 13:45:42 +01:00
def set_volume ( self , amount ) :
2020-05-03 11:15:52 +02:00
util . cli . execute (
" pactl set- {} - {} @DEFAULT_ {} @ {} " . format (
self . _channel , " volume " , self . _channel . upper ( ) , amount
)
)
2020-02-23 13:45:42 +01:00
def increase_volume ( self , event ) :
2020-05-03 11:15:52 +02:00
if self . _limit > 0 : # we need to check the limit
2020-02-23 13:45:42 +01:00
left = int ( self . _left )
right = int ( self . _right )
2020-05-03 11:15:52 +02:00
if (
left + self . _change > = self . _limit
or right + self . _change > = self . _limit
) :
2020-02-23 13:45:42 +01:00
if left == right :
# easy case, just set to limit
2020-05-03 11:15:52 +02:00
self . set_volume ( " {} % " . format ( self . _limit ) )
2020-02-23 13:45:42 +01:00
return
else :
# don't adjust anymore, since i don't know how to update only one channel
return
2020-05-03 11:15:52 +02:00
self . set_volume ( " + {} % " . format ( self . _change ) )
2020-02-23 13:45:42 +01:00
def decrease_volume ( self , event ) :
2020-05-03 11:15:52 +02:00
self . set_volume ( " - {} % " . format ( self . _change ) )
2020-02-23 13:45:42 +01:00
def toggle ( self , event ) :
2020-05-03 11:15:52 +02:00
util . cli . execute (
" pactl set- {} -mute @DEFAULT_ {} @ toggle " . format (
self . _channel , self . _channel . upper ( )
)
)
2020-02-23 13:45:42 +01:00
def mute ( self , value ) :
self . _mute = value
def getvolume ( self , line ) :
2020-05-03 11:15:52 +02:00
if " mono " in line :
m = re . search ( r " mono:.* \ s* \ / \ s*( \ d+) % " , line )
2020-02-23 13:45:42 +01:00
if m :
self . _mono = m . group ( 1 )
else :
2020-05-03 11:15:52 +02:00
m = re . search ( r " left:.* \ s* \ / \ s*( \ d+) %.*r ight:.* \ s* \ / \ s*( \ d+) % " , line )
2020-02-23 13:45:42 +01:00
if m :
self . _left = m . group ( 1 )
self . _right = m . group ( 2 )
def _default_device ( self ) :
2020-05-03 11:15:52 +02:00
output = util . cli . execute ( " pactl info " )
pattern = " Default {} : " . format ( " Sink " if self . _channel == " sink " else " Source " )
for line in output . split ( " \n " ) :
2020-02-23 13:45:42 +01:00
if line . startswith ( pattern ) :
2020-05-03 11:15:52 +02:00
return line . replace ( pattern , " " )
logging . error ( " no pulseaudio device found " )
return " n/a "
2020-02-23 13:45:42 +01:00
2020-02-23 14:47:47 +01:00
def volume ( self , widget ) :
2020-02-23 13:45:42 +01:00
if self . _failed == True :
2020-05-03 11:15:52 +02:00
return " n/a "
2020-02-23 13:45:42 +01:00
if int ( self . _mono ) > 0 :
2020-05-03 11:15:52 +02:00
vol = " {} % " . format ( self . _mono )
2020-02-23 13:59:47 +01:00
if self . _showbars :
2020-05-03 11:15:52 +02:00
vol = " {} {} " . format ( vol , util . graph . hbar ( float ( self . _mono ) ) )
2020-02-23 13:45:42 +01:00
return vol
elif self . _left == self . _right :
2020-05-03 11:15:52 +02:00
vol = " {} % " . format ( self . _left )
2020-02-23 13:59:47 +01:00
if self . _showbars :
2020-05-03 11:15:52 +02:00
vol = " {} {} " . format ( vol , util . graph . hbar ( float ( self . _left ) ) )
2020-02-23 13:45:42 +01:00
return vol
else :
2020-05-03 11:15:52 +02:00
vol = " {} % / {} % " . format ( self . _left , self . _right )
2020-02-23 13:59:47 +01:00
if self . _showbars :
2020-05-03 11:15:52 +02:00
vol = " {} {} {} " . format (
2020-02-23 13:59:47 +01:00
vol ,
util . graph . hbar ( float ( self . _left ) ) ,
2020-05-03 11:15:52 +02:00
util . graph . hbar ( float ( self . _right ) ) ,
)
2020-02-23 13:45:42 +01:00
return vol
def update ( self ) :
try :
self . _failed = False
2020-05-03 11:15:52 +02:00
channel = " sinks " if self . _channel == " sink " else " sources "
2020-02-23 13:45:42 +01:00
device = self . _default_device ( )
2020-05-03 11:15:52 +02:00
result = util . cli . execute ( " pactl list {} " . format ( channel ) )
2020-02-23 13:45:42 +01:00
found = False
2020-05-03 11:15:52 +02:00
for line in result . split ( " \n " ) :
if " Name: {} " . format ( device ) in line :
2020-02-23 13:45:42 +01:00
found = True
continue
if found is False :
continue
for pattern in self . _patterns :
2020-05-03 11:15:52 +02:00
if not pattern [ " expr " ] in line :
2020-02-23 13:45:42 +01:00
continue
2020-05-03 11:15:52 +02:00
if pattern [ " callback " ] ( line ) is False and found == True :
2020-02-23 13:45:42 +01:00
return
except Exception as e :
self . _failed = True
logging . exception ( e )
2020-05-03 11:15:52 +02:00
if util . format . asbool ( self . parameter ( " autostart " , False ) ) :
util . cli . execute ( " pulseaudio --start " , ignore_errors = True )
2020-03-01 14:09:45 +01:00
else :
raise e
2020-02-23 13:45:42 +01:00
def state ( self , widget ) :
if self . _mute :
2020-05-03 11:15:52 +02:00
return [ " warning " , " muted " ]
2020-02-23 13:45:42 +01:00
if int ( self . _left ) > int ( 100 ) :
2020-05-03 11:15:52 +02:00
return [ " critical " , " unmuted " ]
return [ " unmuted " ]
2020-02-23 13:45:42 +01:00
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4