Dotfiles/desktopenvs/hyprdrive/station-bar/volume.py

50 lines
1.7 KiB
Python

"""Default-sink volume via pactl — same tool scripts/getvol already shells out
to. Simple synchronous subprocess calls on click/scroll, no continuous polling:
the bar only needs to reflect what IT changed, and hardware volume keys are rare
enough on a device that also runs Hyprland that a poll loop isn't worth the cost.
"""
from __future__ import annotations
import re
import subprocess
_STEP = 5 # percent per scroll tick, matches typical bar/WM conventions
_VOL_RE = re.compile(r"(\d+)%")
def get_percent() -> int:
try:
out = subprocess.run(["pactl", "get-sink-volume", "@DEFAULT_SINK@"],
capture_output=True, text=True, timeout=1.0, check=True).stdout
m = _VOL_RE.search(out)
return int(m.group(1)) if m else 0
except (subprocess.SubprocessError, OSError):
return 0
def is_muted() -> bool:
try:
out = subprocess.run(["pactl", "get-sink-mute", "@DEFAULT_SINK@"],
capture_output=True, text=True, timeout=1.0, check=True).stdout
return "yes" in out.lower()
except (subprocess.SubprocessError, OSError):
return False
def _set(percent: int) -> None:
percent = max(0, min(100, percent))
subprocess.Popen(["pactl", "set-sink-volume", "@DEFAULT_SINK@", f"{percent}%"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def adjust(delta_ticks: int) -> None:
"""delta_ticks > 0 raises, < 0 lowers, in _STEP-sized increments."""
_set(get_percent() + delta_ticks * _STEP)
def toggle_mute() -> None:
subprocess.Popen(["pactl", "set-sink-mute", "@DEFAULT_SINK@", "toggle"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)