summaryrefslogtreecommitdiffstats
path: root/py3status/modules/volume_status.py
blob: cddc76341dc2a05953fbda6db780fcf91949dcce (plain)
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)