florentc / xob

A lightweight overlay volume (or anything) bar for the X Window System.
GNU General Public License v3.0
444 stars 13 forks source link

Simpler brightness and volume bar script examples #44

Open freddylist opened 2 years ago

freddylist commented 2 years ago

The current brightness and volume bar scripts require a Python installation as well as some Python libraries. I propose we also suggest some simpler shell scripts with minimal dependencies.

Here are some implementations I've come up with, they work for me but I'm new to shell scripting so there is probably room for improvement:

Brightness bar requires only inotify-tools

#!/bin/sh

# Change below to suit your system
BACKLIGHT="/sys/class/backlight/amdgpu_bl0"
BRIGHTNESS="$BACKLIGHT/brightness"
MAX_BRIGHTNESS=$(cat "$BACKLIGHT/max_brightness")

inotifywait -m -e modify "$BRIGHTNESS" \
  | while IFS= read -r line; do cat $BRIGHTNESS; done \
  | xob -m "$MAX_BRIGHTNESS"

Volume bar requires only alsa-utils (and optionally Wireplumber with Pipewire)

#!/bin/sh

# Wait for amixer to become available
until [ "$(amixer)" ]; do sleep 0.1; done

# `amixer events` always emits 1 event from the start, so we must skip it
skip=1
stdbuf -oL amixer events |
  while IFS= read -r line; do
    case ${line%%,*} in
      ('event value: numid='[34])
        if [ "$skip" -eq 0 ]; then
          # The `0+$2` below is to remove the '%' sign
          amixer sget Master |
            awk -F'[][]' '/Left:/ {print 0+$2 ($4 == "off" ? "!" : "")}'

          # Using Pipewire/Wireplumber:
          #wpctl get-volume @DEFAULT_AUDIO_SINK@ |
          #  awk '{ gsub(/\./, "", $2); print $2 ($3 == "[MUTED]" ? "!" : "")}'
        else
          skip=$(( skip - 1 ))
        fi
    esac
  done | xob
freddylist commented 2 years ago

If you want, I can do a pull request, maybe similar to #40?

Alternatively we can start listing examples by language, something like the following:


Ready to use volume bars

These scripts listen to volume and mute events. No matter how the volume changes (keybindings, pulse control panel, headphones plugged-in*), it will instantly show up the volume bar.

*I'm not yet sure how to get the "headphones plugged-in" part with shell scripting...

Python If you are using pulseaudio, save the following Python script (depends on the `pulsectl` python library) and simply pipe it in `xob`! `./pulse-volume-watcher.py | xob` ```python #!/usr/bin/env python3 from pulsectl import Pulse, PulseLoopStop import sys with Pulse() as pulse: def callback(ev): if ev.index == sink_index: raise PulseLoopStop def current_status(sink): return round(sink.volume.value_flat * 100), sink.mute == 1 try: sinks = {s.index:s for s in pulse.sink_list()} if len(sys.argv) > 1: # Sink index from command line argument if provided sink_index = int(sys.argv[1]) if not sink_index in sinks: raise KeyError(f"Sink index {sink_index} not found in list of sinks.") else: # Automatic determination of default sink otherwise default_sink_name = pulse.server_info().default_sink_name try: sink_index = next(index for index, sink in sinks.items() if sink.name == default_sink_name) except StopIteration: raise StopIteration("No default sink was found.") pulse.event_mask_set('sink') pulse.event_callback_set(callback) last_value, last_mute = current_status(sinks[sink_index]) while True: pulse.event_listen() sinks = {s.index:s for s in pulse.sink_list()} value, mute = current_status(sinks[sink_index]) if value != last_value or mute != last_mute: print(str(value) + ('!' if mute else '')) last_value, last_mute = value, mute sys.stdout.flush() except Exception as e: print(f"ERROR: {e}", file=sys.stderr) ```
Shell This shell script only requires `amixer` from [`alsa-utils`](https://github.com/alsa-project/alsa-utils). Simply copy the script (in, say, `~/watch-volume.sh`), make it executable (`chmod u+x ~/volume-bar.sh`) and then autostart it with your X session (by adding, for example, `~/volume-bar.sh | xob &` to your `.xinitrc`. You can optionally use the `pwctl` utility from [`Wireplumber`](https://gitlab.freedesktop.org/pipewire/wireplumber) to get the volume and mute status, if you need it for some reason by commenting and uncommenting the relevant bits below. ```sh #!/bin/sh # Wait for amixer to become available until [ "$(amixer)" ]; do sleep 0.1; done # `amixer events` always emits 1 event from the start, so we must skip it skip=1 stdbuf -oL amixer events | while IFS= read -r line; do case ${line%%,*} in ('event value: numid='[34]) if [ "$skip" -eq 0 ]; then # The `0+$2` below is to remove the '%' sign amixer sget Master | awk -F'[][]' '/Left:/ {print 0+$2 ($4 == "off" ? "!" : "")}' # Using Pipewire/Wireplumber: #wpctl get-volume @DEFAULT_AUDIO_SINK@ | # awk '{ gsub(/\./, "", $2); print $2 ($3 == "[MUTED]" ? "!" : "")}' else skip=$(( skip - 1 )) fi esac done ```

Ready to use brightness bars

One can access the brightness value from /sys/class/backlight/video_backlight/brightness (where video is your video device). The following scripts watch for modifications on that file. No matter how the brightness changes, these scripts will return the new brightness value. You may have to finagle with the path to brightness if you are not using an Intel device. Simply pipe one of these in xob and you are ready to go.

Python This Python script will watch for changes to your brightness file with the watchdog library. ```python #!/usr/bin/env python3 from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler, FileModifiedEvent import sys import time brightness_file = '/sys/class/backlight/intel_backlight/brightness' max_brightness_file ='/sys/class/backlight/intel_backlight/max_brightness' with open(max_brightness_file, 'r') as f: maxvalue = int(f.read()) def notify(file_path): with open(file_path, 'r') as f: value = int(int(f.read())/maxvalue*100) print(value) class Handler(FileSystemEventHandler): def on_modified(self, event): if isinstance(event, FileModifiedEvent): notify(event.src_path) handler = Handler() observer = Observer() observer.schedule(handler, path=brightness_file) observer.start() try: while True: sys.stdout.flush() time.sleep(1) except KeyboardInterrupt: observer.stop() observer.join() ```
Shell This script watches for changes to your brightness file with [`inotify-tools`](https://github.com/inotify-tools/inotify-tools) ```sh #!/bin/sh # Change below to suit your system BACKLIGHT="/sys/class/backlight/amdgpu_bl0" BRIGHTNESS="$BACKLIGHT/brightness" MAX_BRIGHTNESS=$(cat "$BACKLIGHT/max_brightness") inotifywait -m -e modify "$BRIGHTNESS" \ | while IFS= read -r line; do cat $BRIGHTNESS; done \ | xob -m "$MAX_BRIGHTNESS" ```

Just tell me what else you would like to have included and I will have the pull request ready.

juster-0 commented 2 years ago

I think it will be better just to make a list with urls to repos with different scripts for xob with description.

florentc commented 1 year ago

Thank you very much for your suggestions.

On the one hand I would be very happy to get rid of python in the examples provided in the README, but on the other hand, after years of users opening issues about those scripts, we have finally reached a point where nobody ever complains again. In particular, the pulse audio listener has become very reliable and works out of the box for everybody (according to the fact no issues are opened about it anymore). Both your suggestions @freddylist and @juster-0 make sense. Just note that, for the time being at least, I wish to keep suggesting the python scripts first because time has proven they are reliable.

I plan to review and merge #43 and the new color config feature branch into a new major xob release when I get enough free time. Feel free to open your PR and I will eventually get it merged too.