summary refs log tree commit diff
path: root/.config/waybar
diff options
context:
space:
mode:
authorRobert Günzler <r@gnzler.io>2026-02-10 12:32:48 +0100
committerRobert Günzler <r@gnzler.io>2026-02-10 12:41:25 +0100
commit63feeb9f369fc6176e85c1c2d8fcc863caad1946 (patch)
tree41cd5d2d1ec36e74e464caab722cc9b460153f04 /.config/waybar
parent5bd0a4aca65ecb9818ef1285982d160b6b6ff665 (diff)
start new
Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to '.config/waybar')
-rw-r--r--.config/waybar/config.jsonc257
-rwxr-xr-x.config/waybar/modules/covid.sh85
-rwxr-xr-x.config/waybar/modules/gamma.go78
-rw-r--r--.config/waybar/modules/go.mod5
-rw-r--r--.config/waybar/modules/go.sum4
-rwxr-xr-x.config/waybar/modules/hotspots.sh21
-rwxr-xr-x.config/waybar/modules/mediaplayer.py171
-rw-r--r--.config/waybar/modules/mpris.awk54
-rwxr-xr-x.config/waybar/modules/mpris.sh6
-rwxr-xr-x.config/waybar/modules/timetracked.sh23
-rwxr-xr-x.config/waybar/modules/todo.go229
-rwxr-xr-x.config/waybar/modules/toggl.lua28
-rwxr-xr-x.config/waybar/modules/vpn.sh24
-rwxr-xr-x.config/waybar/modules/weather.sh42
-rw-r--r--.config/waybar/style.css390
15 files changed, 0 insertions, 1417 deletions
diff --git a/.config/waybar/config.jsonc b/.config/waybar/config.jsonc
deleted file mode 100644
index 70ab60f..0000000
--- a/.config/waybar/config.jsonc
+++ /dev/null
@@ -1,257 +0,0 @@
-{
-  "modules-left": ["sway/mode", "sway/workspaces", "mpris"],
-
-  "sway/workspaces": {
-    "format": "{icon}",
-    "format-icons": {
-      "1": "󰄰",
-      "2": "󰍥",
-      "3": "󰃖",
-      "m": "󰎇",
-      "v": "󰿏",
-      "g": "󰺵",
-      "__vnc": "󱒃"
-    }
-  },
-
-  "river/tags": {
-    "format": ":{}",
-    "num-tags": 9
-  },
-
-  "mpris": {
-    "max-width": 60,
-    "format": "{player_icon} {dynamic}",
-    "format-paused": "{status_icon} <i>{dynamic}</i>",
-    "player-icons": {
-      "default": "󰲸",
-      // "firefox": "X",
-      // "mpv": "XX",
-    },
-    "status-icons": {
-      "paused": "󰏤",
-      "playing": "",
-      "stopped": "",
-    }
-  },
-
-  // ------------------------------------------------------------------------ //
-
-  "modules-center": ["custom/weather", "clock#local", "clock#utc", "clock#extra", "custom/timetracked", "custom/hotspots"],
-
-  "custom/weather": {
-    "format": "{icon} {percentage}℃",
-    "format-icons": {
-      "sunny": "󰖙",
-      "partlycloudy": "󰖕",
-      "cloudy": "󰖐",
-      "verycloudy": "󰼯",
-      "fog": "󰖑",
-      "lightrain": "󰖗",
-      "heavyrain": "󰖖",
-      "hail": "󰖒",
-      "thunder": "󰖓",
-      "lightsnow": "󰖘",
-      "heavysnow": "󰼶",
-      "snowrain": "󰙿"
-    },
-    "exec": "$HOME/.config/waybar/modules/weather.sh",
-    "interval": 600,
-    "return-type": "json",
-    "tooltip": true,
-    "on-click": "swx -t env REPORT=1 $HOME/.config/waybar/modules/weather.sh"
-  },
-
-  "clock#local": {
-    "format": "{:<i>%a</i> %d %b <b>%H:%M</b>}",
-    "tooltip-format": "TZ: {:%Z %z}\n\n{calendar}",
-    // "locale": "ja_JP.utf-8"
-    // "locale": "en_US.utf-8"
-  },
-
-  "clock#utc": {
-    "timezone": "UTC",
-    "format": "{:<small>%Z</small> %H:%M}",
-    "tooltip-format": "{:%Z %z}"
-  },
-  "clock#extra": {
-    "timezone": "Asia/Kolkata",
-    "format": "{:<small>%Z</small> %H:%M}",
-    "tooltip-format": "{:%Z %z}"
-  },
-
-  "custom/todo": {
-    "format": "{icon} {}",
-    "format-icons": {
-      "off": "󰒲",
-      "on": "󰈻"
-    },
-    "exec": "env WAYBAR_TODO_FILE=$HOME/.zk/todo.md $HOME/.config/waybar/modules/waybar-todo",
-    "on-click": "pkill -x -USR1 waybar-todo",
-    "on-click-right": "pkill -x -USR2 waybar-todo",
-    "escape": true,
-    "return-type": "json"
-  },
-
-  "custom/timetracked": {
-    "format": "{}",
-    "exec": "$HOME/.config/waybar/modules/timetracked.sh",
-    "on-click": "$HOME/.config/waybar/modules/timetracked.sh on-click",
-    "escape": true,
-    "return-type": "json"
-  },
-
-  "custom/hotspots": {
-    "format": "{}",
-    "exec": "$HOME/.config/waybar/modules/hotspots.sh",
-    "on-click": "$HOME/.config/waybar/modules/hotspots.sh click",
-    "escape": true,
-    "interval": 600,
-    "return-type": "json"
-  },
-
-  // ------------------------------------------------------------------------ //
-  "modules-right": ["tray", "cpu", "memory", "disk#root", "disk#home", "temperature", "idle_inhibitor", "backlight", "pulseaudio", "custom/vpn", "network#tailscale", "network", "battery"],
-
-  "tray": {
-    "icon-size": 15,
-    "spacing": 5
-  },
-
-  "custom/covid": {
-    "format": "{icon} {}",
-    "format-icons": {
-      "": "x",
-      "gray": "󱅼",
-      "green": "󱎷",
-      "yellow": "󱎷",
-      "orange": "󱎷",
-      "red": "󱎷",
-      "darkred": "󱎷",
-      "darkdarkred": "󰯆"
-    },
-    "exec": "$HOME/.config/waybar/modules/covid.sh",
-    "interval": 86400,
-    "return-type": "json"
-  },
-
-  "disk#root": {
-    "path": "/",
-    "format": "󰋊 <small>/ </small>{percentage_used}%"
-  },
-
-  "disk#home": {
-    "path": "/home",
-    "format": "<small>/home </small>{percentage_used}%"
-  },
-
-  "cpu": {
-    "format": "{icon} {usage}%",
-    "format-icons": ["󰊚", "󰀦"],
-    "on-click": "$HOME/bin/swx -t -- btop"
-  },
-
-  "memory": {
-    "format": "{icon} {percentage}%",
-    "format-icons": ["󰘚", "󰀦"], // 󰍛
-    "on-click": "$HOME/bin/swx -t -- btop"
-  },
-
-  "temperature": {
-    "critical-threshold": 100,
-    "format": "{icon} {temperatureC}℃",
-    "format-icons": ["󱃃", "󰔏", "󰸁", "󱜜"]
-  },
-
-  "idle_inhibitor": {
-    "format": "{icon}",
-    "format-icons": {
-      "activated": "󰅶",
-      "deactivated": "󰾪"
-    }
-  },
-
-  "backlight": {
-    "device": "auto",
-    "format": "{icon}",
-    "format-icons": ["󰹐", "󰌶", "󰛩", "󰖧"],
-    "on-scroll-down": "light -A 5",
-    "on-scroll-up": "light -U 5",
-    // save current level
-    // then set to minimum brightness
-    "on-click-right": "light -O; light -S $(light -P)",
-    // revert to previously saved brightness
-    "on-click-middle": "light -I"
-  },
-
-  "custom/gamma": {
-    "format": "{icon}",
-    "format-icons": {
-      "dawn": "󰱌",
-      "day": "󰱌",
-      "dusk": "󰱊",
-      "night": "󰱊",
-    },
-    "exec": "env GAMMA_COMMAND='wlsunset -l $HOME_LAT -L $HOME_LON -p' YAEGI_SYSCALL=1 YAEGI_UNRESTRICTED=1 ${HOME}/.config/waybar/modules/gamma.go",
-    "return-type": "json"
-  },
-
-  "pulseaudio": {
-    "format": "{icon} {volume}%",
-    "format-bluetooth": "{icon}󰂯 {volume}%",
-    "format-muted": "󰝟 {volume}%",
-    "format-icons": {
-      "easyeffects_sink": "󰺢",
-      "headphones": "󰋋",
-      "handsfree": "󰜟",
-      "headset": "󰋎",
-      "phone": "󰏲",
-      "portable": "󰛵",
-      "car": "󰄋",
-      "default": ["󰕿", "󰖀", "󰕾"]
-    },
-    "on-click-right": "soundswitch -m",
-    "on-click-middle": "swx easyeffects",
-    "on-click": "swx -t -F '0.4' pulsemixer"
-  },
-
-  "custom/vpn": {
-    "exec": "${HOME}/.config/waybar/modules/vpn.sh",
-    "interval": 600,
-    "return-type": "json",
-    "on-click": "${HOME}/.config/waybar/modules/vpn.sh toggle",
-  },
-
-  "network#tailscale": {
-    "interface": "tailscale0",
-    "format": "󰌆",
-    "format-disconnected": "󰌊",
-    "tooltip-format": "{ifname}: {bandwidthUpBits} {bandwidthDownBits}",
-    "tooltip-format-disconnected": "disconnected",
-    "on-click": "${HOME}/.config/waybar/modules/tailscale.sh toggle",
-  },
-
-  "network": {
-    "format-wifi": "{icon} {signalStrength}%",
-    "format-icons": ["󰤫", "󰤟", "󰤢", "󰤥", "󰤨"],
-    "format-ethernet": "󰌗",
-    "format-linked": "󰈀 {ifname}",
-    "format-disconnected": "󰌙 ",
-    "tooltip-format": "{ifname}: {ipaddr}/{cidr}\ngateway: {gwaddr}\nssid: {essid}\nsignal: {signaldBm} dbm\ndown: {bandwidthDownBits}\nup: {bandwidthUpBits}",
-    "tooltip-format-disconnected": "disconnected",
-    // cycles through wifi/ethernet/off
-    // "on-click": "${HOME}/.config/waybar/modules/network.sh toggle",
-  },
-
-  "battery": {
-    "states": {
-      "good": 90,
-      "warning": 30,
-      "critical": 15
-    },
-    "format": "{icon} {capacity}%",
-    "format-charging": "󰗱 {capacity}%",
-    "format-full-charging": "󱊦",
-    "format-icons": ["󱃍", "󱊡", "󱊢", "󱊣"]
-  },
-}
diff --git a/.config/waybar/modules/covid.sh b/.config/waybar/modules/covid.sh
deleted file mode 100755
index 46727d7..0000000
--- a/.config/waybar/modules/covid.sh
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/bin/sh
-
-set -e
-[ -n "$DEBUG" ] && {
-	set -x
-	curl_args='-v'
-}
-
-# check requirements
-for tool in awk curl jq flock; do
-	if ! command -v "$tool" >/dev/null; then
-		printf "%s: %s not installed but required\n" "$(basename "$0")" "$tool" >&2
-		exit 1
-	fi
-done
-
-# incidence = (sumCasesLast7Days / EWZ) * 100000
-lat=${HOME_LAT:?}
-lon=${HOME_LON:?}
-# fields='GEN,RS,EWZ,EWZ_BL,BL_ID,cases,cases_per_100k,cases7_per_100k,cases7_bl_per_100k,last_update,BL,IBZ'
-fields='GEN,cases7_bl_per_100k'
-# see https://experience.arcgis.com/experience/478220a4c454480e823b17327b2bf1d4
-uri="https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/RKI_Landkreisdaten/FeatureServer/0/query?where=1%3D1&outFields=${fields}&geometry=${lon}%2C${lat}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelWithin&returnGeometry=false&outSR=4326&f=json"
-
-_data=$(curl -sSL -H 'Accept: application/json' ${curl_args} "${uri}" | jq -r '.features[0].attributes')
-if [ "${_data}" = "null" ]; then
-	printf "{}\n"
-	exit 0
-fi
-
-historical_data=${HOME}/covid-history.csv
-loc=$(printf "%s" "${_data}" | jq -r '.GEN')
-last_update=$(printf "%s" "${_data}" | jq -r '.last_update')
-# printf "${_data}" | jq -r '.'
-incidence_f=$(printf "%.1f" "$(printf "%s" "${_data}" | jq -r '.cases7_bl_per_100k')")
-incidence_i=$(printf "%.0f" "${incidence_f}")
-
-# store
-if [ -n "${last_update}" ] && [ -n "${incidence_f}" ]; then
-	tmp_HISTFILE=$(mktemp -u --tmpdir waybar-module-covid.XXXXX)
-	(
-		cat "${historical_data}"
-		ts=$(printf "%s" "${last_update}" | cut -d',' -f1 | tr '.' '-')
-		printf "%s,%s\n" "${ts}" "${incidence_f}"
-	) | uniq | tee "${tmp_HISTFILE}" >/dev/null
-	flock -x "${historical_data}" mv "${tmp_HISTFILE}" "${historical_data}"
-fi
-
-mxy=$(tail -n 7 "${historical_data}" | awk -F',' '{y=y+$2} END{print ((NR*(NR+1))/2)/NR, y/NR}')
-trend=$(awk -F',' --assign="mx=$(printf "%s" "$mxy" | cut -d' ' -f1)" --assign="my=$(printf "%s" "$mxy" | cut -d' ' -f2)" '{up= up+(NR-mx)*($2-my); down= down+(NR-mx)**2} END{if(down==0){print 0}else{print up/down};}' "${historical_data}")
-trend_arrow="󰔴"
-[ "$(printf "%.0f" "${trend}")" -gt 0 ] && trend_arrow="󰔵"
-[ "$(printf "%.0f" "${trend}")" -lt 0 ] && trend_arrow="󰔳"
-
-color='green'
-if [ "${incidence_i}" -eq "0" ]; then
-	color='gray'
-fi
-if [ "${incidence_i}" -gt "1" ]; then
-	color='green'
-fi
-if [ "${incidence_i}" -gt "25" ]; then
-	color='yellow'
-fi
-if [ "${incidence_i}" -gt "35" ]; then
-	color='orange'
-fi
-if [ "${incidence_i}" -gt "50" ]; then
-	color='red'
-fi
-if [ "${incidence_i}" -gt "100" ]; then
-	color='darkred'
-fi
-if [ "${incidence_i}" -gt "250" ]; then
-	color='darkdarkred'
-fi
-
-tooltip="7 Tage Inzidenz für ${loc}
-last update: ${last_update}
-
-history (${trend_arrow}):
-$(awk -F, '{print $1 " " $2}' "${historical_data}" | tail -n10 | tac)"
-
-jq -nr \
-	"{ text: \"${trend_arrow}${incidence_f}\", percentage: \"${incidence_i}\", class: \"${color}\", alt: \"${color}\", tooltip: \"${tooltip}\" } | @text"
diff --git a/.config/waybar/modules/gamma.go b/.config/waybar/modules/gamma.go
deleted file mode 100755
index 9813cc8..0000000
--- a/.config/waybar/modules/gamma.go
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env yaegi
-
-package main
-
-import (
-	"encoding/json"
-	"log"
-	"os"
-	"os/exec"
-	"os/signal"
-	"runtime"
-	"strings"
-	. "syscall"
-)
-
-func main() {
-	runtime.GOMAXPROCS(1)
-
-	var (
-		update = make(chan os.Signal, 1)
-		cancel = make(chan os.Signal, 1)
-	)
-	signal.Notify(update, SIGUSR1, SIGUSR2, SIGHUP)
-	signal.Notify(cancel, SIGTERM, SIGINT)
-
-	// could use golang.org/x/sys/unix.Prctl here
-	// but I want to avoid the dependency
-	if _, _, e := Syscall6(uintptr(SYS_PRCTL),
-		uintptr(PR_SET_PDEATHSIG),
-		uintptr(SIGTERM),
-		0, 0, 0, 0); e != 0 {
-		log.Fatalf("error: %v", e)
-	}
-
-	lookup()
-	for {
-		select {
-		case sig := <-update:
-			switch sig {
-			case SIGUSR1:
-				printJson("day")
-				// TODO(robert): toggle wlsunset off?
-			case SIGUSR2:
-				printJson("night")
-				// TODO(robert): toggle wlsunset on?
-			case SIGHUP:
-				lookup()
-			}
-		case <-cancel:
-			log.Printf("%v exiting\n", os.Args[0])
-			os.Exit(0)
-		}
-	}
-}
-
-func printJson(phase string) {
-	_ = json.NewEncoder(os.Stdout).Encode(map[string]interface{}{
-		"class":   phase,
-		"alt":     phase,
-		"tooltip": "gamma: " + phase,
-		"text":    phase,
-	})
-}
-
-func lookup() {
-	cmdEnv, ok := os.LookupEnv("GAMMA_COMMAND")
-	if !ok {
-		printJson("unknown")
-		return
-	}
-	b, err := exec.Command("bash", "-c", cmdEnv).Output()
-	if err != nil {
-		log.Fatalf("error: %v", err)
-		return
-	}
-	phase := strings.TrimSpace(string(b))
-	printJson(phase)
-}
diff --git a/.config/waybar/modules/go.mod b/.config/waybar/modules/go.mod
deleted file mode 100644
index fdeae95..0000000
--- a/.config/waybar/modules/go.mod
+++ /dev/null
@@ -1,5 +0,0 @@
-module git.sr.ht/~robertgzr/dotfiles/.config/waybar/modules
-
-go 1.15
-
-require github.com/fsnotify/fsnotify v1.4.9 // indirect
diff --git a/.config/waybar/modules/go.sum b/.config/waybar/modules/go.sum
deleted file mode 100644
index b12c1ed..0000000
--- a/.config/waybar/modules/go.sum
+++ /dev/null
@@ -1,4 +0,0 @@
-github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
-github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0=
-golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/.config/waybar/modules/hotspots.sh b/.config/waybar/modules/hotspots.sh
deleted file mode 100755
index fe2ff65..0000000
--- a/.config/waybar/modules/hotspots.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-set -e
-
-case "$1" in
-click)
-	uri=$(hspl -u)
-	xdg-open "http://$uri"
-	;;
-*)
-	output=$(hspl || echo "none")
-	if [ "$output" != "none" ]; then
-		jq -nc \
-			--arg text "󱛄 $(head -n1 <<<"$output")" \
-			--arg tooltip "$(tail -n+2 <<<"$output")" \
-			--arg class "$(if [ "$(hspl -d)" -lt 100 ]; then echo "soon"; else echo ""; fi)" \
-			'{text:$text,tooltip:$tooltip,class:$class}'
-	else
-		jq -nc '{}'
-	fi
-	;;
-esac
diff --git a/.config/waybar/modules/mediaplayer.py b/.config/waybar/modules/mediaplayer.py
deleted file mode 100755
index 8082825..0000000
--- a/.config/waybar/modules/mediaplayer.py
+++ /dev/null
@@ -1,171 +0,0 @@
-#!/usr/bin/env python3
-
-import argparse
-import json
-import logging
-import signal
-import sys
-from datetime import timedelta
-from math import floor
-import prctl
-
-# yapf: disable
-import gi
-gi.require_version('Playerctl', '2.0')
-from gi.repository import GLib, Playerctl
-# yapf: enable
-
-logger = logging.getLogger(__name__)
-loop = GLib.MainLoop()
-
-def write_output(text, player):
-    logger.info('Writing output')
-
-    output = {
-        'text': text,
-        'class': 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'
-
-    if player.get_title() and player.get_title() != '':
-        track_info = f"{player.get_title()}"
-    if player.get_artist() and player.get_artist() != '':
-        track_info = f"{player.get_artist()} - {track_info}"
-
-    if 'mpris:length' in player.props.metadata.keys():
-        dur_td = timedelta(microseconds=player.props.metadata['mpris:length'])
-        dur_h, remainder = divmod(dur_td.total_seconds(), 3600)
-        dur_m, dur_s = divmod(remainder, 60)
-        dur = f"{floor(dur_m)}:{floor(dur_s):02}"
-        if dur_h > 0:
-            dur = f"{floor(dur_h)}:{dur}"
-        track_info = '{} ({})'.format(track_info, str(dur))
-
-    if player.props.status == 'Paused' and track_info:
-        track_info = '<i>'+track_info+'</i>'
-
-    if player.props.status == 'Stopped':
-        return
-
-    if track_info == '':
-        logger.warning('TrackInfo was empty after parsing')
-        return
-
-    write_output(track_info, player)
-
-
-def on_player_appeared(manager, player, selected_player=None, ignored_players=None):
-    if player is not None \
-            and (selected_player is None or player.name == selected_player) \
-            and not (player.name in ignored_players):
-        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.warning('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 occurance of -v
-    parser.add_argument('-v', '--verbose', action='count', default=0)
-
-    # Define for which player we're listening
-    parser.add_argument('--player',
-                        help='player to listen for')
-
-    # Define which players to ignore entirely
-    parser.add_argument('-I', '--ignore',
-                        action='append',
-                        help='players to ignore')
-
-    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()
-    manager.connect('name-appeared',
-                    lambda *args: on_player_appeared(*args, arguments.player, arguments.ignore))
-    manager.connect('player-vanished', on_player_vanished)
-
-    # set the process up to die when the parent exits
-    prctl.set_pdeathsig(signal.SIGTERM)
-
-    signal.signal(signal.SIGINT, signal_handler)
-    signal.signal(signal.SIGTERM, signal_handler)
-    signal.signal(signal.SIGHUP, signal_handler)
-
-    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
-
-        if arguments.ignore is not None and player.name in arguments.ignore:
-            logger.debug(
-                '{player} is ignored, skipping it'.format(
-                    player=player.name))
-            continue
-
-        init_player(manager, player)
-
-    loop.run()
-
-
-if __name__ == '__main__':
-    main()
diff --git a/.config/waybar/modules/mpris.awk b/.config/waybar/modules/mpris.awk
deleted file mode 100644
index 194aa73..0000000
--- a/.config/waybar/modules/mpris.awk
+++ /dev/null
@@ -1,54 +0,0 @@
-{
-  gsub(/"/,"")
-  gsub(/'/,"\047")
-  # print "DEBUG: " $0
-
-  artist=$1
-  album=$2
-  title=$3
-  position=$4
-  player=$5
-  status=$6
-}
-
-($0 == "") || (status ~ /stopped/) {
-  system("jq -Mnc {}")
-  next
-}
-
-(status ~ /playing/) {
-  icon="󰲸"
-}
-(status ~ /paused/) {
-  icon="󰏤"
-}
-(artist != "") && (album != "") {
-  text=sprintf("%s - %s - %s (%s)", artist, album, title, position)
-  tooltip=sprintf("%s\nby %s\nfrom %s\n(%s)", title, artist, album, player)
-}
-(artist == "") {
-  text=sprintf("%s - %s (%s)", album, title, position)
-  tooltip=sprintf("%s\nfrom %s\n(%s)", title, album, player)
-}
-(album == "") {
-  text=sprintf("%s - %s (%s)", artist, title, position)
-  tooltip=sprintf("%s\nby %s\n(%s)", title, artist, player)
-}
-(artist == "") && (album == "") {
-  text=sprintf("%s (%s)", title, position)
-  tooltip=sprintf("%s\n(%s)", title, player)
-}
-# edge cases to beautify the output
-(player == "tdesktop") && (title ~ /Unknown Track/) {
-  text="telegram voice message"
-}
-
-{
-  system(sprintf("jq -rMnc --arg class \"%s\" --arg text \"%s %s\" --arg tt \"%s\" '{ class: $class, text: $text|@html, tooltip: $tt|@html }'", \
-         status,
-         icon,
-         text,
-         tooltip))
-}
-
-END {}
diff --git a/.config/waybar/modules/mpris.sh b/.config/waybar/modules/mpris.sh
deleted file mode 100755
index 5f5d5c6..0000000
--- a/.config/waybar/modules/mpris.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-set -e
-[ -n "$DEBUG" ] && set -x
-
-playerctl -sF metadata -f '"{{artist}}","{{album}}","{{title}}","{{duration(position)}}","{{playerName}}","{{lc(status)}}"' | awk -F',' -f "${HOME}/.config/waybar/modules/mpris.awk"
diff --git a/.config/waybar/modules/timetracked.sh b/.config/waybar/modules/timetracked.sh
deleted file mode 100755
index 4e384bf..0000000
--- a/.config/waybar/modules/timetracked.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/sh
-
-set -e
-[ -n "$DEBUG" ] && set -x
-
-if ! command -v timetrace >/dev/null 2>&1; then
-	exit 0
-fi
-
-case "$1" in
-on-click)
-	timetrace status >/dev/null && timetrace stop
-	exit 0
-	;;
-
-*) ;;
-esac
-
-while true; do
-	timetrace status -o json |
-		jq -c 'if .project == "---" then {} else { text: (["▶", .trackedTimeToday] | join(" ")), class: "timetracked", alt: "timetracked" } end' 2>/dev/null
-	sleep 30
-done
diff --git a/.config/waybar/modules/todo.go b/.config/waybar/modules/todo.go
deleted file mode 100755
index 2692ec9..0000000
--- a/.config/waybar/modules/todo.go
+++ /dev/null
@@ -1,229 +0,0 @@
-#!/usr/bin/env yaegi
-
-// # Documentation
-// we try to read a file pointed to by WAYBAR_TODO_FILE.
-// While no particular format is assumed, we recommend
-// Markdown.
-// We extract the todos from the top-level list items
-// (listings start with a `*` character).
-//
-// # Usage:
-// go build -o waybar-todo todo.go
-package main
-
-import (
-	"bufio"
-	"encoding/json"
-	"log"
-	"os"
-	"os/signal"
-	"regexp"
-  "runtime"
-	"strings"
-	"time"
-
-	"github.com/fsnotify/fsnotify"
-	"golang.org/x/sys/unix"
-)
-
-const (
-	TODO_INACTIVE_STRING string = ""
-	TODO_LABEL_REGEX     string = `\[\[!(.*)\]\]`
-)
-
-var (
-	active      = true
-	todofile    = os.Getenv("WAYBAR_TODO_FILE")
-	cookiefile  = os.ExpandEnv("${XDG_RUNTIME_DIR}/waybar-todo.cookie")
-	labelFilter = os.Getenv("WAYBAR_TODO_FILTER")
-)
-
-func printJson(text, tooltip string, class []string, alt string, percentage int) error {
-	return json.NewEncoder(os.Stdout).Encode(map[string]interface{}{
-		"text":       text,
-		"tooltip":    tooltip,
-		"class":      class,
-		"alt":        alt,
-		"percentage": percentage,
-	})
-}
-
-type todoItem struct {
-	text  string
-	label string
-}
-
-func readTodofile2(path string) ([]todoItem, error) {
-	f, err := os.Open(path)
-	if err != nil {
-		return nil, err
-	}
-	var todos []todoItem
-	for lr := bufio.NewScanner(f); lr.Scan(); {
-		skip := 0
-		switch {
-		case strings.HasPrefix(lr.Text(), "*"):
-			skip = 2
-		case strings.HasPrefix(lr.Text(), "- [ ]"):
-			skip = 6
-		case strings.HasPrefix(lr.Text(), "- [x]"):
-			fallthrough
-		default:
-			continue
-		}
-		ti := todoItem{text: lr.Text()[skip:]}
-		matches := labelre.FindAllStringSubmatch(ti.text, -1)
-		if matches != nil && len(matches) > 0 {
-			ti.label = matches[0][1]
-			ti.text = strings.TrimSpace(
-				strings.Replace(ti.text, matches[0][0], "", 1))
-		}
-		todos = append(todos, ti)
-	}
-	return todos, nil
-}
-
-func setCookie(active bool) error {
-	if !active {
-		_, err := os.Create(cookiefile)
-		return err
-	}
-	return os.Remove(cookiefile)
-}
-
-func update() error {
-	if _, err := os.Stat(cookiefile); err == nil {
-		log.Printf("cookie set, we're inactive")
-		active = false
-	}
-	if !active {
-		return printJson(TODO_INACTIVE_STRING, "* inactive *", []string{"off"}, "off", 0)
-	}
-	todos, err := readTodofile2(todofile)
-	if err != nil {
-		return err
-	}
-	var (
-		text       string
-		tooltip    []string
-		extraClass string
-	)
-	for _, item := range todos {
-		if labelFilter != "" && strings.Contains(labelFilter, item.label) {
-			continue
-		}
-		if text == "" {
-			text = item.text
-			extraClass = item.label
-			continue
-		}
-		// render out the rest of the todos into the tooltip
-		tooltip = append(tooltip, item.text)
-	}
-	return printJson(text, strings.Join(tooltip, "\n"), []string{"on", extraClass}, "on", 1)
-}
-
-var labelre *regexp.Regexp
-
-func init() {
-	labelre = regexp.MustCompile(TODO_LABEL_REGEX)
-}
-
-func main() {
-  runtime.GOMAXPROCS(1)
-
-	var (
-		updateC = make(chan os.Signal, 1)
-		cancelC = make(chan os.Signal, 1)
-	)
-	signal.Notify(updateC, unix.SIGUSR1, unix.SIGUSR2, unix.SIGHUP)
-	signal.Notify(cancelC, unix.SIGTERM, unix.SIGINT)
-
-	var err error
-	// we will receive a SIGTERM if our parent dies
-	err = unix.Prctl(unix.PR_SET_PDEATHSIG, uintptr(unix.SIGTERM), 0, 0, 0)
-	if err != nil {
-		log.Fatalf("error: setting prctl: %v", err)
-	}
-
-	if todofile == "" {
-		panic("missing TODO file")
-		// // get from nb(1)
-		// nb := exec.Command("sh", "-c", "nb show --no-color --path todo")
-		// nb_output, err := nb.Output()
-		// if err != nil {
-		// 	e := err.(*exec.ExitError)
-		// 	log.Fatalf("error: finding todofile via nb: %s", e.Stderr)
-		// }
-		// todofile = strings.TrimSpace(string(nb_output))
-	}
-
-	log.Printf("watching %q", todofile)
-
-	w, err := fsnotify.NewWatcher()
-	if err != nil {
-		log.Fatalf("error: creating watcher: %v", err)
-	}
-	defer w.Close()
-
-	if err := w.Add(todofile); err != nil {
-		log.Fatalf("error: adding watch: %v", err)
-	}
-
-	if err := update(); err != nil {
-		// fail here because it's the first time we
-		// try to read the todofile.
-		log.Fatalf("error: %v", err)
-	}
-	for {
-		select {
-		case evt, ok := <-w.Events:
-			if !ok {
-				return
-			}
-			// see https://github.com/fsnotify/fsnotify/issues/94
-			//     https://github.com/gohugoio/hugo/pull/4720
-			if evt.Op&fsnotify.Remove == fsnotify.Remove {
-				counter := 0
-				for w.Add(todofile) != nil {
-					counter++
-					if counter >= 1000 {
-						log.Panic("error: unable to add file watcher")
-					}
-					time.Sleep(100 * time.Millisecond)
-				}
-			}
-			goto force_update
-		case err, ok := <-w.Errors:
-			if !ok {
-				return
-			}
-			log.Printf("error: from watcher: %v", err)
-
-		case sig := <-updateC:
-			switch sig {
-			case unix.SIGUSR1: // on
-				active = !active
-				if err := setCookie(active); err != nil {
-					log.Printf("err: %v", err)
-				}
-				goto force_update
-			case unix.SIGUSR2: //
-				if strings.Contains(labelFilter, "work") {
-					labelFilter = strings.Trim(strings.ReplaceAll(labelFilter, "work", ""), ",")
-				} else {
-					labelFilter = strings.Join([]string{labelFilter, "work"}, ",")
-				}
-				continue
-			case unix.SIGHUP: // force update
-				log.Println("force update")
-				goto force_update
-			}
-		case <-cancelC:
-			log.Printf("%s exiting", os.Args[0])
-			os.Exit(0)
-		}
-	force_update:
-		_ = update()
-	}
-}
diff --git a/.config/waybar/modules/toggl.lua b/.config/waybar/modules/toggl.lua
deleted file mode 100755
index 7c9f0b9..0000000
--- a/.config/waybar/modules/toggl.lua
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env luajit
-
-TOKEN = os.getenv("TOGGL_TOKEN")
-if not TOKEN then
-    io.stderr:write("need TOGGL_TOKEN\n")
-    os.exit(1)
-end
-
-function timer_duration()
-    cmd = string.format('toggl -t %s -j timer ls | jq -r ".[0].duration"', TOKEN)
-    local f = assert(io.popen(cmd, 'r'))
-    local s = assert(f:read('*a'))
-    f:close()
-    if not (s == '') then
-        return tonumber(s)
-    end
-end
-
-unix_time = os.time()
-
-diff = timer_duration()
-if not diff then
-    os.exit(0)
-end
-
-d = unix_time + diff
-
-print(string.format('%dh %.2dm', d/(60*60), d/60%60))
diff --git a/.config/waybar/modules/vpn.sh b/.config/waybar/modules/vpn.sh
deleted file mode 100755
index c4d50fa..0000000
--- a/.config/waybar/modules/vpn.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-
-set -e
-[ -n "$DEBUG" ] && set -x
-
-case "$1" in
-toggle) exit 1 ;;
-esac
-
-extern_ip=$(curl -SsfL http://api.ipify.org/?format=text)
-
-vpn_is_up() {
-	case "$extern_ip" in
-	138.201.245.159) return 0 ;; # hetzner node
-	esac
-	return 1
-}
-
-if vpn_is_up; then
-	printf '{"text": "󰒃", "tooltip": "external ip is %s"}\n' "$extern_ip"
-else
-	# printf '{"text": "󰦜", "tooltip": "disconnected"}\n'
-	printf '{}\n'
-fi
diff --git a/.config/waybar/modules/weather.sh b/.config/waybar/modules/weather.sh
deleted file mode 100755
index 929732b..0000000
--- a/.config/waybar/modules/weather.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/sh
-set -e
-[ -n "$DEBUG" ] && set -x
-
-loc=$1
-if [ -z "${loc}" ]; then
-	# use /etc/localtime
-	# loc=$(basename "$(readlink -f /etc/localtime)")
-	loc="${HOME_LAT},${HOME_LON}"
-fi
-
-if [ -n "$REPORT" ]; then
-	curl -s v2.wttr.in/"${loc}"?F | less
-	exit 0
-fi
-
-data="$(curl -s wttr.in/"${loc}"?format=j1)"
-
-class=
-case "$(echo "${data}" | jq -r '.current_condition[].weatherCode')" in
-113) class="sunny" ;;
-116) class="partlycloudy" ;;
-119) class="cloudy" ;;
-122) class="verycloudy" ;;
-143|248|260) class="fog" ;;
-176|263|266|293|296|353) class="lightrain" ;;
-179|182|185|281|284|311|314|317|350|362|365|374|377) class="hail" ;;
-200|386|389|392) class="thunder" ;;
-227|320) class="lightsnow" ;;
-230|329|332|335|338|371|395) class="heavysnow" ;;
-299|302|305|308|356|359): class="heavyrain" ;;
-323|326|368) class="snowrain" ;;
-esac
-
-echo "${data}" | jq \
-	--raw-output \
-	--unbuffered \
-	--compact-output \
-	--arg class "${class}" \
-	--arg tooltip "$(curl -s v2.wttr.in/"${loc}"?ATFQ | tail -n5)" \
-	'.current_condition[] | { text: .weatherDesc[0].value, percentage: (.temp_C | tonumber), class: $class, alt: $class, tooltip: ($tooltip) }'
-	
diff --git a/.config/waybar/style.css b/.config/waybar/style.css
deleted file mode 100644
index 01a0084..0000000
--- a/.config/waybar/style.css
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * vim: fdm=marker fdl=1
- * */
-
-/* start flavours */
-@define-color base00 #0c0c0c;
-@define-color base01 #db4d6d;
-@define-color base02 #5dac81;
-@define-color base03 #fad689;
-@define-color base04 #58b2dc;
-@define-color base05 #69b0ac;
-@define-color base06 #70649a;
-@define-color base07 #bdc0ba;
-@define-color base08 #1c1c1c;
-@define-color base09 #cb1b45;
-@define-color base0A #86c166;
-@define-color base0B #f7d94c;
-@define-color base0C #2ea9df;
-@define-color base0D #81c7d4;
-@define-color base0E #8a6bbe;
-@define-color base0F #fffffb;
-
-* {
-    font-family: Iosevka Etoile, Sarasa Fixed J, Material Design Icons;
-    font-size: 9pt;
-}
-/* end flavours */
-
-@define-color accent @base06;
-@define-color accentdarker @base0E;
-@define-color foreground @base07;
-@define-color background @base00;
-/* @define-color background rgba(12, 12, 12, 0.96); */
-@define-color dimmed #5e5e5e;
-@define-color dimmeddarker #434343;
-@define-color urgent @base09;
-
-* {
-    border: none;
-    border-radius: 0;
-}
-
-window#waybar {
-    background: @background;
-    color: @foreground;
-    /* padding: 0 0.3rem; */
-}
-
-window#waybar.hidden {
-    opacity: 0;
-}
-
-
-#window,
-#mode,
-#clock,
-#battery,
-#cpu,
-#memory,
-#disk,
-#temperature,
-#backlight,
-#idle_inhibitor,
-#network,
-#pulseaudio,
-#wireplumber,
-#custom-toggl,
-#custom-gammastep,
-#custom-weather,
-#custom-mpris,
-#custom-todo,
-#custom-covid,
-#custom-timetracked,
-#tray {
-    /* border-top: 1px solid @dimmeddarker; */
-    padding: 0 0.1rem;
-    margin: 0 0.2rem;
-    color: @dimmed;
-}
-
-#cpu:hover,
-#memory:hover,
-#backlight:hover,
-#idle_inhibitor:hover,
-#network:hover,
-#network.tailscale:hover,
-#pulseaudio:hover,
-#wireplumber:hover,
-#custom-mpris:hover,
-#custom-gammastep:hover,
-#custom-todo:hover {
-    color: @foreground;
-    transition-property: background;
-    transition-duration: 0.1s;
-}
-
-#tags button,
-#workspaces button {
-    padding: 0 5px;
-    background: transparent;
-    color: @dimmed;
-    /* border-bottom: 3px solid transparent; */
-}
-
-#tags button {
-    color: @dimmeddarker;
-}
-
-#tags button.occupied {
-    color: @dimmed;
-}
-
-#workspaces button.visible {
-    color: @dimmeddarker;
-    background: @accentdarker;
-}
-
-#tags button.focused,
-#workspaces button.focused {
-    font-weight: bold;
-    color: @foreground;
-    background: @accent;
-    transition-property: background;
-    transition-duration: 0.01s;
-}
-
-#tags button.urgent,
-#workspaces button.urgent {
-    color: @background;
-    background: @urgent;
-}
-
-#tags button:hover,
-#tags button.focused:hover,
-#workspaces button:hover,
-#workspaces button.focused:hover {
-    background: @accent;
-    color: @foreground;
-    transition-property: background, color;
-    transition-duration: 0.01s;
-
-    /* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
-    box-shadow: inherit;
-    text-shadow: inherit;
-}
-
-#tags button.urgent:hover,
-#workspaces button.urgent:hover {
-    background: @foreground;
-    transition-property: background;
-    transition-duration: 0.01s;
-}
-
-#mode {
-    /* font-style: italic; */
-    color: @background;
-    background: @base03;
-    margin: 3px 6px;
-    border-radius: 2px;
-}
-
-#clock {}
-
-#clock.local {
-    color: @foreground;
-}
-
-#clock.utc {}
-
-#disk.root {}
-
-#disk.home {
-    /* margin-left: 0; */
-    /* padding-left: 0; */
-}
-
-#battery {}
-
-#battery.charging {
-    color: @background;
-    background: @base0A;
-}
-
-@keyframes blink {
-    to {
-        background: @foreground;
-        color: @background;
-    }
-}
-
-#battery.critical:not(.charging) {
-    color: @foreground;
-    background: @urgent;
-    animation-name: blink;
-    animation-duration: 0.5s;
-    animation-timing-function: linear;
-    animation-iteration-count: infinite;
-    animation-direction: alternate;
-}
-
-label:focus {
-    background: @background;
-}
-
-#cpu {}
-
-#memory {}
-
-#backlight {}
-
-#backlight.off {
-    color: @dimmed;
-}
-
-#network {}
-
-#network.disconnected {
-    border-top: 1px solid @urgent;
-    color: @dimmed;
-}
-
-#network.tailscale.disabled,
-#network.tailscale.disconnected,
-#network.mullvad.disabled,
-#network.mullvad.disconnected {
-    border-top: 1px solid @dimmeddarker;
-}
-
-#network.tailscale.ethernet,
-#network.tailscale.linked,
-#network.mullvad.ethernet,
-#network.mullvad.linked {
-    color: @foreground;
-    border-top: 1px solid @base0E;
-}
-
-#pulseaudio {}
-
-#pulseaudio.muted {
-    border-top: 1px solid @urgent;
-    color: @dimmed;
-}
-
-#pulseaudio.bluetooth {
-    border-top: 1px solid @base04;
-}
-
-#wireplumber {}
-
-#wireplumber.muted {
-    border-top: 1px solid @urgent;
-    color: @dimmed;
-}
-
-#wireplumber.bluetooth {
-    border-top: 1px solid @base04;
-}
-
-#temperature {}
-
-#temperature.critical {
-    color: @foreground;
-    background: @urgent;
-    border-top: none;
-}
-
-#tray {}
-
-#idle_inhibitor {}
-
-#idle_inhibitor.activated {
-    color: @foreground;
-    border-top: 1px solid @base02;
-}
-
-#mpris {
-    color: @foreground;
-}
-
-#mpris.playing,
-#mpris.paused {
-    border-top: 1px solid @base04;
-}
-
-#mpris.paused {
-    font-style: italic;
-}
-
-#mpris.spotify {
-    border-top: 1px solid #1db954;
-}
-
-#mpris.mpv {
-    border-top: 1px solid #8f008f;
-}
-
-#custom-toggl {
-    color: @foreground;
-    border-top: 1px solid @urgent;
-}
-
-#custom-todo.off {
-    color: @dimmed;
-    border-top: 1px solid @dimmeddarker;
-    padding: 0 0 0 0.4rem;
-}
-
-#custom-todo.on {
-    color: @foreground;
-    border-top: 1px solid @urgent;
-    font-weight: bold;
-    padding: 0 0.6rem 0 0.4rem;
-}
-
-#custom-todo.work {
-    background: @urgent;
-}
-
-#custom-timetracked {
-    color: @urgent;
-    border-top: 1px solid @urgent;
-}
-
-@keyframes flash {
-    50% {
-        background: rgba(255, 174, 66, 0.7);
-        color: @background;
-    }
-}
-
-#custom-gamma.night {
-    border-top: 1px solid @base0C;
-    color: @foreground;
-    animation-name: flash;
-    animation-duration: 0.3s;
-    animation-timing-function: linear;
-    animation-iteration-count: 1;
-}
-
-#custom-gamma.day {
-    color: @dimmed;
-}
-
-#custom-gamma.off {
-    border-top: 1px solid @urgent;
-    color: @dimmed;
-}
-
-#custom-weather {
-    color: @dimmed;
-}
-
-#custom-covid.green {
-    /* border-top: 1px solid #00cc00; */
-    /* color: #00cc00; */
-}
-
-#custom-covid.yellow {
-    /* border-top: 1px solid #f7dd31; */
-    /* color: #f7dd31; */
-}
-
-#custom-covid.orange {
-    /* border-top: 1px solid #faa31b; */
-    /* color: #faa31b; */
-}
-
-#custom-covid.red {
-    /* border-top: 1px solid #f92206; */
-    /* color: #f92206; */
-}
-
-#custom-covid.darkred {
-    /* border-top: 1px solid #c01a00; */
-    /* color: #c01a00; */
-}
-
-#custom-covid.darkdarkred {
-    /* border-top: 1px solid #941100; */
-    /* color: #941100; */
-}
-
-#custom-hotspots {
-    border-top: 1px solid @urgent;
-    color: @dimmed;
-}
-
-#custom-hotspots.soon {
-    color: @urgent;
-}