From ae76fa8e9acb12ca1fcb23ba56333a6756feb27b Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Wed, 22 Feb 2023 22:18:20 +0200 Subject: [PATCH] Added `waybar` scripts --- .config/waybar/scripts/dunst.sh | 7 + .config/waybar/scripts/github.sh | 11 ++ .config/waybar/scripts/mediaplayer.py | 128 ++++++++++++++++++ .config/waybar/scripts/pipewire.sh | 41 ++++++ .config/waybar/scripts/wireguard-rofi.sh | 54 ++++++++ .config/waybar/scripts/wireguard.sh | 165 +++++++++++++++++++++++ 6 files changed, 406 insertions(+) create mode 100644 .config/waybar/scripts/dunst.sh create mode 100644 .config/waybar/scripts/github.sh create mode 100644 .config/waybar/scripts/mediaplayer.py create mode 100644 .config/waybar/scripts/pipewire.sh create mode 100644 .config/waybar/scripts/wireguard-rofi.sh create mode 100644 .config/waybar/scripts/wireguard.sh diff --git a/.config/waybar/scripts/dunst.sh b/.config/waybar/scripts/dunst.sh new file mode 100644 index 00000000..579b5ef0 --- /dev/null +++ b/.config/waybar/scripts/dunst.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +COUNT=$(dunstctl count waiting) +ENABLED= +DISABLED= +if [ "$COUNT" != 0 ]; then DISABLED=" $COUNT"; fi +if dunstctl is-paused | grep -q "false" ; then echo $ENABLED; else echo "$DISABLED"; fi diff --git a/.config/waybar/scripts/github.sh b/.config/waybar/scripts/github.sh new file mode 100644 index 00000000..c7b102ac --- /dev/null +++ b/.config/waybar/scripts/github.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +token=$(cat "${HOME}"/.config/github/notifications.token) +count=$(curl -u kristoferssolo:"${token}" https://api.github.com/notifications | jq '. | length') + +# if [[ "$count" != "0" ]]; then +# echo "{'text':$(count),'tooltip':$(tooltip),'class':$(class)}" +# fi +if [[ "$count" != "0" ]]; then + echo '{"text":'$count',"tooltip":"$tooltip","class":"$class"}' +fi diff --git a/.config/waybar/scripts/mediaplayer.py b/.config/waybar/scripts/mediaplayer.py new file mode 100644 index 00000000..1630d97c --- /dev/null +++ b/.config/waybar/scripts/mediaplayer.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +import argparse +import logging +import sys +import signal +import gi +import json +gi.require_version('Playerctl', '2.0') +from gi.repository import Playerctl, GLib + +logger = logging.getLogger(__name__) + + +def write_output(text, player): + logger.info('Writing output') + + output = {'text': text, + 'class': 'custom-' + player.props.player_name, + 'alt': player.props.player_name} + + sys.stdout.write(json.dumps(output) + '\n') + sys.stdout.flush() + + +def on_play(player, status, manager): + logger.info('Received new playback status') + on_metadata(player, player.props.metadata, manager) + + +def on_metadata(player, metadata, manager): + logger.info('Received new metadata') + track_info = '' + + if player.props.player_name == 'spotify' and \ + 'mpris:trackid' in metadata.keys() and \ + ':ad:' in player.props.metadata['mpris:trackid']: + track_info = 'AD PLAYING' + elif player.get_artist() != '' and player.get_title() != '': + track_info = '{artist} - {title}'.format(artist=player.get_artist(), + title=player.get_title()) + else: + track_info = player.get_title() + + if player.props.status != 'Playing' and track_info: + track_info = ' ' + track_info + write_output(track_info, player) + + +def on_player_appeared(manager, player, selected_player=None): + if player is not None and (selected_player is None or player.name == selected_player): + init_player(manager, player) + else: + logger.debug("New player appeared, but it's not the selected player, skipping") + + +def on_player_vanished(manager, player): + logger.info('Player has vanished') + sys.stdout.write('\n') + sys.stdout.flush() + + +def init_player(manager, name): + logger.debug('Initialize player: {player}'.format(player=name.name)) + player = Playerctl.Player.new_from_name(name) + player.connect('playback-status', on_play, manager) + player.connect('metadata', on_metadata, manager) + manager.manage_player(player) + on_metadata(player, player.props.metadata, manager) + + +def signal_handler(sig, frame): + logger.debug('Received signal to stop, exiting') + sys.stdout.write('\n') + sys.stdout.flush() + # loop.quit() + sys.exit(0) + + +def parse_arguments(): + parser = argparse.ArgumentParser() + + # Increase verbosity with every occurrence of -v + parser.add_argument('-v', '--verbose', action='count', default=0) + + # Define for which player we're listening + parser.add_argument('--player') + + return parser.parse_args() + + +def main(): + arguments = parse_arguments() + + # Initialize logging + logging.basicConfig(stream=sys.stderr, level=logging.DEBUG, + format='%(name)s %(levelname)s %(message)s') + + # Logging is set by default to WARN and higher. + # With every occurrence of -v it's lowered by one + logger.setLevel(max((3 - arguments.verbose) * 10, 0)) + + # Log the sent command line arguments + logger.debug('Arguments received {}'.format(vars(arguments))) + + manager = Playerctl.PlayerManager() + loop = GLib.MainLoop() + + manager.connect('name-appeared', lambda *args: on_player_appeared(*args, arguments.player)) + manager.connect('player-vanished', on_player_vanished) + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + for player in manager.props.player_names: + if arguments.player is not None and arguments.player != player.name: + logger.debug('{player} is not the filtered player, skipping it' + .format(player=player.name) + ) + continue + + init_player(manager, player) + + loop.run() + + +if __name__ == '__main__': + main() diff --git a/.config/waybar/scripts/pipewire.sh b/.config/waybar/scripts/pipewire.sh new file mode 100644 index 00000000..a484509c --- /dev/null +++ b/.config/waybar/scripts/pipewire.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +set -e + +# https://blog.dhampir.no/content/sleeping-without-a-subprocess-in-bash-and-how-to-sleep-forever +snore() { + local IFS + [[ -n "${_snore_fd:-}" ]] || exec {_snore_fd}<> <(:) + read -r ${1:+-t "$1"} -u $_snore_fd || : +} + +DELAY=0.2 + +while snore $DELAY; do + WP_OUTPUT=$(wpctl get-volume @DEFAULT_AUDIO_SINK@) + + if [[ $WP_OUTPUT =~ ^Volume:[[:blank:]]([0-9]+)\.([0-9]{2})([[:blank:]].MUTED.)?$ ]]; then + if [[ -n ${BASH_REMATCH[3]} ]]; then + printf "MUTED\n" + else + VOLUME=$((10#${BASH_REMATCH[1]}${BASH_REMATCH[2]})) + ICON=( + "" + "" + "" + ) + + if [[ $VOLUME -gt 50 ]]; then + printf "%s" "${ICON[0]} " + elif [[ $VOLUME -gt 25 ]]; then + printf "%s" "${ICON[1]} " + elif [[ $VOLUME -ge 0 ]]; then + printf "%s" "${ICON[2]} " + fi + + printf "$VOLUME%%\n" + fi + fi +done + +exit 0 diff --git a/.config/waybar/scripts/wireguard-rofi.sh b/.config/waybar/scripts/wireguard-rofi.sh new file mode 100644 index 00000000..f61da54f --- /dev/null +++ b/.config/waybar/scripts/wireguard-rofi.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# WireGuard custom menu script to manage NetworkManager WireGuard connections using rofi +# install to the same directory as wireguard.sh +# example usage with rofi: rofi -modi 'WireGuard:~/.config/rofi/wireguard-rofi.sh' -show WireGuard + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + +if [[ $# != 0 ]] +then + if [[ "$@" == "quit" ]] + then + exit 0 + elif [[ "$1" != "reload" ]] + then + connection=$(echo $1 | cut -d: -f1) + message="$($SCRIPT_DIR/wireguard.sh toggle $connection)" + if command -v notify-send >/dev/null 2>&1; then + notify-send "wireguard" "$message" + fi + exit 0 + fi +fi + +active=-1 +urgent=-1 + +while read -r state connection IP +do + if [[ "$state" == "connected:" ]] + then + active=$(($active+1)) + elif [[ "$state" == "available:" ]] + then + urgent=$(($urgent+1)) + fi + if [[ "$IP" != "" ]] + then + connection="$connection [$IP]" + fi + echo -en "$connection\0icon\x1fwireguard\n" +done < <($SCRIPT_DIR/wireguard.sh menu) + +if [[ $active -ge 0 ]] +then + echo -en "\0active\x1f0-$active\n" +fi +if [[ $urgent -ge 0 ]] +then + echo -en "\0urgent\x1f$(($active+1))-$(($active+1+$urgent))\n" +fi + +echo "reload" +echo "quit" diff --git a/.config/waybar/scripts/wireguard.sh b/.config/waybar/scripts/wireguard.sh new file mode 100644 index 00000000..be197504 --- /dev/null +++ b/.config/waybar/scripts/wireguard.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env bash + +# nmcli WireGuard abstraction layer for use with my waybar module and rofi custom menu script +# +# requires nmcli on your path +# install to the same directory as wireguard-rofi.sh +# +# usage: ./wireguard.sh [short|menu|toggle NAME] +# no argument: print current connections +# short: print current connections in short format +# menu: print all connections +# toggle NAME: toggle connection NAME + +if ! command -v nmcli >/dev/null 2>&1; then + echo "ERROR: 'nmcli' not found" + echo "This tool is a 'nmcli' frontend, hence you should install NetworkManager before trying to use it." + exit 1 +fi + +nargs=$# +get="no" +showmenu="no" +short="no" +dotoggle="no" +if [[ $nargs == 0 ]] +then + get="yes" +elif [[ $nargs == 1 ]] +then + if [[ $1 == "menu" ]] + then + showmenu="yes" + elif [[ $1 == "short" ]] + then + if ! command -v sed >/dev/null 2>&1; then + echo "ERROR: 'sed' not found" + echo "Please install 'sed' to enable the 'short' option." + exit 1 + fi + get="yes" + short="short" + fi +elif [[ $nargs == 2 ]] +then + if [[ $1 == "toggle" ]] + then + dotoggle="yes" + conn="$2" + fi +fi + +nmclicmd="nmcli connection" +wgconns="$nmclicmd show" +wgactive="$wgconns --active" + +connected=() +available=() + +function get_conns { + while read -r name uuid type device + do + if [[ $type != "wireguard" ]] + then + continue + fi + + if [[ $device != "--" ]] + then + while read -r key value + do + if [[ $key != "ipv4.addresses:" ]] + then + continue + fi + connected+=("$name: $value") + done < <($wgconns $name) + else + available+=("$name") + fi + done < <($1) +} + +function print_conns { + local first="yes" + local array_print="$1[@]" + local array_print=("${!array_print}") + local text="" + local tooltip="" + if [ "${#array_print[@]}" -le 0 ] + then + return + fi + if [[ "$2" == "list" ]] + then + for c in "${array_print[@]}" + do + echo "$1: $c" + done + else + for c in "${array_print[@]}" + do + if [[ "$first" != "yes" ]] + then + text="$text | " + tooltip="$tooltip\n" + fi + if [[ "$2" == "short" ]] + then + text="$text$(echo -n $c | sed -E 's/^(.+): ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]+)$/\1/')" + else + text="$text$c" + fi + tooltip="$tooltip$c" + first="no" + done + echo "{\"text\": \"$text\", \"tooltip\": \"$tooltip\"}" + fi +} + +function array_contains { + local array_has="$1[@]" + local array_has=("${!array_has}") + local element="$2" + for e in "${array_has[@]}" + do + if [[ "$e" == *"$element"* ]] + then + echo "yes" + return + fi + done + echo "no" +} + +if [[ $get == "yes" ]] +then + get_conns "$wgactive" + print_conns connected "$short" + +elif [[ $showmenu == "yes" ]] +then + get_conns "$wgconns" + print_conns connected "list" + print_conns available "list" + + +elif [[ $dotoggle == "yes" ]] +then + get_conns "$wgconns" + + if [[ "$(array_contains connected $conn)" == "yes" ]] + then + $nmclicmd down "$conn" + elif [[ "$(array_contains available $conn)" == "yes" ]] + then + $nmclicmd up "$conn" + else + echo "err: connection not found" + exit 1 + fi + +else + echo "err: wrong args" + exit 1 +fi