Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simpler brightness and volume bar script examples #44

Open
freddylist opened this issue Sep 30, 2022 · 4 comments
Open

Simpler brightness and volume bar script examples #44

freddylist opened this issue Sep 30, 2022 · 4 comments

Comments

@freddylist
Copy link

freddylist commented Sep 30, 2022

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
Copy link
Author

freddylist commented Oct 5, 2022

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

#!/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. 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 to get the volume and mute status, if you need it for some reason by commenting and uncommenting the relevant bits below.

#!/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.

#!/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

#!/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
Copy link

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

@florentc
Copy link
Owner

florentc commented Oct 29, 2022

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.

@vxsl
Copy link

vxsl commented Dec 20, 2024

Just wanted to mention that I've always had issues with the volume example from the README. I would always have to manually restart xob after waking the computer from sleep.

@freddylist's seems not to have this issue and is indeed simpler!

Don't really have the time to make a PR right now but just thought I'd put it out there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants