forked from ultrabug/py3status
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
129 additions
and
125 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,143 +1,147 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
""" | ||
Display current sound volume using amixer. | ||
Expands on the standard i3status volume module by adding color and percentage threshold settings. | ||
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 | ||
Dependencies: | ||
alsa-utils (tested with alsa-utils 1.0.29-1) | ||
Expands on the standard i3status volume module by adding color | ||
and percentage threshold settings. | ||
Configuration parameters: | ||
- format : format the output, available variables: {percentage} | ||
- format_mute : format the output when the volume is muted | ||
- cache_timeout : 0 by default, you usually want continuous monitoring | ||
- threshold_degraded : 50 by default, percentage to change color to color_degraded | ||
- threshold_bad : 20 by default, percentage to change color to color_bad | ||
- color_good : #00FF00 by default, good volume color | ||
- color_degraded : #FFFF00 by default, degraded volume color | ||
- color_bad : #FF0000 by default, bad volume color | ||
- channel : "Master" by default, alsamixer channel to track | ||
- device : "default" by default, alsamixer device to use | ||
- 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> <[email protected]> | ||
@license BSD | ||
""" | ||
|
||
from time import time | ||
import re | ||
from subprocess import check_output | ||
import shlex | ||
|
||
from subprocess import check_output | ||
from time import time | ||
|
||
|
||
class Py3status: | ||
format = "♪: {percentage}%" | ||
format_muted = "♪: muted" | ||
cache_timeout = 0 | ||
|
||
threshold_degraded = 50 | ||
threshold_bad = 20 | ||
|
||
color_good = "#00FF00" | ||
color_degraded = "#FFFF00" | ||
color_bad = "#FF0000" | ||
|
||
device = "default" | ||
channel = "Master" | ||
|
||
# constructor | ||
def __init__(self): | ||
self.text = "" | ||
|
||
# compares current volume to the thresholds, returns a color code | ||
def _perc_to_color(self, string): | ||
try: | ||
value = int(string) | ||
except ValueError: | ||
return self.color_bad | ||
|
||
if value < self.threshold_bad: | ||
return self.color_bad | ||
elif value < self.threshold_degraded: | ||
return self.color_degraded | ||
else: | ||
return self.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(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, | ||
'full_text': text, | ||
'transformed': transformed, | ||
'color': color | ||
} | ||
return response | ||
""" | ||
""" | ||
# 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 = {} | ||
|
||
while True: | ||
print(x.current_volume([], config)) | ||
sleep(1) | ||
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) |