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
|
import subprocess, re
from collections import namedtuple
class PacmdSection:
def __init__(self, name, items):
self.name = name # string
self.items = items # [PacmdItem]
class PacmdItem:
def __init__(self, index, children):
self.index = index # int
self.children = children # {key: PacmdNode}
class PacmdNode:
def __init__(self, value, children):
self.value = value # None | string | [string]
self.children = children # {key: PacmdNode}
class Pacmd:
def __init__(self, full_output):
lines = full_output.decode("utf-8").split("\n")
self.infos = [] # [string]
self.sections = [] # [PacmdSection]
currsect = None
curritem = None
currpath = []
def close_curritem():
nonlocal curritem, currsect, currpath
if curritem:
currsect.items.append(curritem)
curritem = None
currpath = []
def close_currsect():
nonlocal self, currsect
if currsect:
close_curritem()
self.sections.append(currsect)
def q_is_key_value(ln):
return ln.find("=") != -1 or ln.find(": ") != -1
def q_get_key_value(ln):
if ln.find("=") != -1:
m = re.search(r"^\s*([^=]*?)\s*=\s*(.*)$", ln)
else:
m = re.search(r"^\s*([^:]*):\s*(.*)$", ln)
return m.group(1), m.group(2)
for line in lines:
line = line.rstrip()
if len(line) == 0:
continue
line = line.replace("\t", " ")
m = re.match(r"^( *(\* )?)([^ ].*)", line)
is_default = m.group(2) is not None # TODO use is_default
indent = len(m.group(1))
line = m.group(3)
# print(currpath)
# print(indent, line)
if indent == 0:
if line[0].isdigit():
close_currsect()
name = re.search(r" ([^ ]*)\(s\)", line).group(1)
currsect = PacmdSection(name, [])
else:
self.infos.append(line)
elif indent == 4:
close_curritem()
index = re.search(r"index: ([0-9]*)$", line).group(1)
curritem = PacmdItem(int(index), {})
elif indent >= 8:
assert curritem != None
is_aligned = indent % 8 == 0
indent_depth = (indent + 7) // 8 - 1
if is_aligned and indent_depth < len(currpath):
currpath = currpath[:indent_depth]
parentval, thisval = None, curritem
for k in currpath:
parentval, thisval = thisval, thisval.children[k]
if q_is_key_value(line):
key, value = q_get_key_value(line)
thisval.children[key] = PacmdNode(value, {})
currpath.append(key)
elif re.search(r":$", line) is not None:
key = line[:-1]
thisval.children[key] = PacmdNode(None, {})
currpath.append(key)
elif indent_depth >= len(currpath):
if type(thisval.value) != list:
thisval.value = [thisval.value]
thisval.value.append(line)
else:
print("line = " + line)
assert False
else:
print("indent = " + str(indent))
assert False
close_currsect()
def pacmd(*args):
return Pacmd(subprocess.check_output(["pacmd"] + list(args)))
def list_all():
return pacmd("list")
def list_sinks():
return pacmd("list-sinks")
def list_sink_inputs():
return pacmd("list-sink-inputs")
def _make_indent(n):
return " " * n
def dump_section(sect):
print("Section " + sect.name + ":")
for item in sect.items:
print(_make_indent(1) + "Item " + str(item.index) + ":")
for key, node in item.children.items():
dump_node(node, key, 2);
def dump_node(node, key, indent):
print(_make_indent(indent) + key + ":" +
("" if node.value is None else " " + str(node.value)))
for k2, n2 in node.children.items():
dump_node(n2, k2, indent + 1)
|