-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsystem_volume.py
More file actions
63 lines (41 loc) · 1.88 KB
/
Copy pathsystem_volume.py
File metadata and controls
63 lines (41 loc) · 1.88 KB
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
"""Helpers for PipeWire/PulseAudio output volume control via wpctl."""
from __future__ import annotations
import re
import subprocess
class SystemVolumeError(RuntimeError):
"""Raised when output volume cannot be read or changed."""
TARGET_SINK = "@DEFAULT_AUDIO_SINK@"
def _get_target_volume(target: str) -> int:
output = _run_command(["wpctl", "get-volume", target])
return _parse_wpctl_volume(output)
def _set_target_volume(target: str, percent: int | float) -> int:
clamped = max(0, min(100, round(float(percent))))
_run_command(["wpctl", "set-volume", target, f"{clamped}%"])
return _get_target_volume(target)
def _run_command(args: list[str]) -> str:
result = subprocess.run(args, capture_output=True, text=True, check=False)
if result.returncode != 0:
stderr = (result.stderr or "").strip()
raise SystemVolumeError(stderr or f"Command failed: {' '.join(args)}")
return result.stdout.strip()
def _parse_wpctl_volume(output: str) -> int:
match = re.search(r"Volume:\s*([0-9]*\.?[0-9]+)", output)
if not match:
raise SystemVolumeError(f"Unable to parse volume from wpctl output: {output!r}")
normalized = float(match.group(1))
percent = round(normalized * 100)
return max(0, min(100, percent))
def get_output_volume() -> int:
return _get_target_volume(TARGET_SINK)
def set_output_volume(percent: int | float) -> int:
return _set_target_volume(TARGET_SINK, percent)
def get_node_volume(target: str) -> int:
normalized = str(target or "").strip()
if not normalized:
raise SystemVolumeError("Node target is required")
return _get_target_volume(normalized)
def set_node_volume(target: str, percent: int | float) -> int:
normalized = str(target or "").strip()
if not normalized:
raise SystemVolumeError("Node target is required")
return _set_target_volume(normalized, percent)