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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
# -*- coding: utf-8 -*-
"""
Display current sound volume using amixer.
Expands on the standard i3status volume module by adding color
and percentage threshold settings.
Configuration parameters:
- cache_timeout : how often we refresh this module in seconds (10s default)
- channel : "Master" by default, alsamixer channel to track
- device : "default" by default, alsamixer device to use
- format : format the output, available variables: {percentage}
- format_muted : format the output when the volume is muted
- threshold_bad : 20 by default
- threshold_degraded : 50 by default
Requires:
alsa-utils (tested with alsa-utils 1.0.29-1)
NOTE:
If you want to refresh the module quicker than the i3status interval,
send a USR1 signal to py3status in the keybinding.
Example: killall -s USR1 py3status
@author <Jan T> <jans.tuomi@gmail.com>
@license BSD
"""
import re
import shlex
from subprocess import check_output
from time import time
class Py3status:
"""
"""
# available configuration parameters
cache_timeout = 10
channel = 'Master'
device = 'default'
format = u'♪: {percentage}%'
format_muted = u'♪: muted'
threshold_bad = 20
threshold_degraded = 50
# constructor
def __init__(self):
self.text = ''
# compares current volume to the thresholds, returns a color code
def _perc_to_color(self, i3s_config, string):
try:
value = int(string)
except ValueError:
return i3s_config['color_bad']
if value < self.threshold_bad:
return i3s_config['color_bad']
elif value < self.threshold_degraded:
return i3s_config['color_degraded']
else:
return i3s_config['color_good']
# return the format string formatted with available variables
def _format_output(self, format, percentage):
text = format.format(percentage=percentage)
return text
# return the current channel volume value as a string
def _get_percentage(self, output):
# attempt to find a percentage value in square brackets
p = re.compile(r'(?<=\[)\d{1,3}(?=%\])')
text = p.search(output).group()
# check if the parsed value is sane by checking if it's an integer
try:
int(text)
return text
# if not, show an error message in output
except ValueError:
return "error: can't parse amixer output."
# returns True if the channel is muted
def _get_muted(self, output):
p = re.compile(r'(?<=\[)\w{2,3}(?=\])')
text = p.search(output).group()
# check if the parsed string is either "off" or "on"
if text in ['on', 'off']:
return text == 'off'
# if not, return False
else:
return False
# this method is ran by py3status
# returns a response dict
def current_volume(self, i3s_output_list, i3s_config):
# call amixer
output = check_output(shlex.split('amixer -D {} sget {}'.format(
self.device, self.channel))).decode('utf-8')
# get the current percentage value
perc = self._get_percentage(output)
# get info about channel mute status
muted = self._get_muted(output)
# determine the color based on the current volume level
color = self._perc_to_color(i3s_config, perc)
# format the output
text = self._format_output(self.format_muted
if muted else self.format, perc)
# if the text has been changed, update the cached text and
# set transformed to True
transformed = text != self.text
self.text = text
# create response dict
response = {
'cached_until': time() + self.cache_timeout,
'color': color,
'full_text': text,
'transformed': transformed
}
return response
# test if run directly
if __name__ == "__main__":
from time import sleep
x = Py3status()
config = {
'color_bad': '#FF0000',
'color_degraded': '#FFFF00',
'color_good': '#00FF00'
}
while True:
print(x.current_volume([], config))
sleep(1)
|