From c2ae3d05be4b456669c828168e55faffb8e63119 Mon Sep 17 00:00:00 2001 From: pyrschtjag Date: Tue, 7 Apr 2026 22:04:55 +0400 Subject: [PATCH] feat: update volume widget and visual --- eww/eww.scss | 14 +++++++++++-- eww/eww.yuck | 22 ++++++++++++------- eww/scripts/volume.py | 49 +++++++++++++++++++------------------------ 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/eww/eww.scss b/eww/eww.scss index 69a7735..0df8d05 100644 --- a/eww/eww.scss +++ b/eww/eww.scss @@ -187,14 +187,24 @@ separator { .volume-pill { @extend .capsule; + .icon, .stat-label { transition: color $t-norm ease-in-out; } .icon { margin-right: 14px; } .slide-wrapper { transition: all $t-fast ease-in-out; } &.muted { border-color: #444; .icon, .stat-label { color: $muted-gray; } - scale slider { background-color: $muted-gray; } - scale trough highlight { background-color: #444; } + + scale slider { + background-color: $muted-gray; + transition: background-color $t-norm ease-in-out; + } + + scale trough highlight { + background-color: #444; + transition: background-color $t-norm ease-in-out; + } + .slide-wrapper { border-color: #444; transition: all $t-slow ease-in-out; diff --git a/eww/eww.yuck b/eww/eww.yuck index d42d120..edfd092 100644 --- a/eww/eww.yuck +++ b/eww/eww.yuck @@ -13,7 +13,7 @@ ;; слушатели (deflisten ws_data :initial "{}" "python3 $HOME/.config/eww/scripts/workspaces.py") -(deflisten volume :initial "0" "python3 $HOME/.config/eww/scripts/volume.py") +(deflisten volume :initial '{"volume": 0, "muted": false}' "python3 -u $HOME/.config/eww/scripts/volume.py") (deflisten layout :initial "EN" "socat -u UNIX-CONNECT:$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock - | stdbuf -oL awk -F'>>' '/activelayout/ {split(\$2, a, \",\"); print toupper(substr(a[2], 1, 2))}'") (deflisten tray_count :initial "0" "python3 $HOME/.config/eww/scripts/tray_monitor.py") (deflisten kb_leds :initial '{"caps":"0","num":"0"}' "python3 $HOME/.config/eww/scripts/kb_leds.py") @@ -73,15 +73,21 @@ ;; звук (defwidget volumewidget [reveal_state reveal_var] - (eventbox :cursor "pointer" :onclick "eww update ${reveal_var}=${!reveal_state}" - (box :class "capsule volume-pill ${reveal_state ? 'active' : ''} ${volume == 0 || volume == '' ? 'muted' : ''}" + (eventbox :cursor "pointer" + :onclick "eww update ${reveal_var}=${!reveal_state}" + :onrightclick "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle" + :onscroll "echo {} | sed -e 's/up/5%+/g' -e 's/down/5%-/g' | xargs wpctl set-volume -l 1.35 @DEFAULT_AUDIO_SINK@" + (box :class "capsule volume-pill ${reveal_state ? 'active' : ''} ${volume.muted || volume.volume == 0 || volume.volume == '0' ? 'muted' : ''}" :space-evenly false - (label :class "icon" :text {volume == 0 || volume == "" ? "" : (volume < 50 ? "" : "")}) - (label :class "stat-label" :text "${volume}%" :width 38) - (revealer :reveal reveal_state :transition "slideleft" + (label :class "icon" + :text {volume.muted || volume.volume == 0 || volume.volume == "0" ? "" : (volume.volume < 50 ? "" : "")}) + (label :class "stat-label" + :text "${volume.volume}%" :width 38) + (revealer :reveal reveal_state + :transition "slideleft" (box :class "slide-wrapper" - (scale :class "vol-bar" :min 0 :max 101 :value {volume ?: 0} - :onchange "pactl set-sink-volume @DEFAULT_SINK@ {}%")))))) + (scale :class "vol-bar" :min 0 :max 101 :value {volume.volume} + :onchange "wpctl set-volume @DEFAULT_AUDIO_SINK@ {}%")))))) ;; часы (defwidget timewidget [reveal_state reveal_var] diff --git a/eww/scripts/volume.py b/eww/scripts/volume.py index 2ab2004..59fd5c1 100755 --- a/eww/scripts/volume.py +++ b/eww/scripts/volume.py @@ -1,42 +1,37 @@ import subprocess import sys -import os -import signal +import json +import re class VolumeMonitor: - def __init__(self): - # отдаём текущую громкость при старте - self.push_update() - - def get_vol(self): - # достаём цифры из pactl + def get_vol_info(self): try: - raw = subprocess.check_output(["pactl", "get-sink-volume", "@DEFAULT_SINK@"], stderr=subprocess.DEVNULL).decode() - if "/" in raw: - # забираем канал и чистим от процентов - return raw.split("/")[1].strip().replace("%", "") - except: - return "0" - return "0" + # Получаем громкость + состояние + raw = subprocess.check_output(["wpctl", "get-volume", "@DEFAULT_AUDIO_SINK@"]).decode().strip() + + # Получаем громкость + match = re.search(r"(\d\.\d+)", raw) + vol_val = float(match.group(1)) if match else 0.0 + percent = int(vol_val * 100) + + # Проверяем наличие метки muted + is_muted = "[MUTED]" in raw + + return json.dumps({"volume": percent, "muted": is_muted}) + except Exception: + return json.dumps({"volume": 0, "muted": False}) def push_update(self): - # отдаём данные в stdout для eww - vol = self.get_vol() - sys.stdout.write(f"{vol}\n") + sys.stdout.write(f"{self.get_vol_info()}\n") sys.stdout.flush() def run(self): - # подписываемся на события аудио-сервера + self.push_update() proc = subprocess.Popen(["pactl", "subscribe"], stdout=subprocess.PIPE, text=True) - try: - for line in proc.stdout: - # если изменился основной выход - if "sink" in line: - self.push_update() - except KeyboardInterrupt: - proc.terminate() - sys.exit(0) + for line in proc.stdout: + if "sink" in line or "server" in line: + self.push_update() if __name__ == "__main__": VolumeMonitor().run() \ No newline at end of file