diff options
| author | Robert Günzler <r@gnzler.io> | 2020-01-26 17:16:07 +0100 |
|---|---|---|
| committer | Robert Günzler <r@gnzler.io> | 2020-01-26 18:00:59 +0100 |
| commit | f5d56602df70950de6b7d40966b00c9939c81763 (patch) | |
| tree | b50ffeb5496fe3525cc1bab2629389ced95435b7 /.config/waybar | |
Intial commit of v2
See https://drewdevault.com/2019/12/30/dotfiles.html
Diffstat (limited to '.config/waybar')
| -rw-r--r-- | .config/waybar/config | 168 | ||||
| -rwxr-xr-x | .config/waybar/mediaplayer.py | 168 | ||||
| -rw-r--r-- | .config/waybar/style.css | 194 | ||||
| -rwxr-xr-x | .config/waybar/toggl.lua | 28 |
4 files changed, 558 insertions, 0 deletions
diff --git a/.config/waybar/config b/.config/waybar/config new file mode 100644 index 0000000..6f29e7e --- /dev/null +++ b/.config/waybar/config @@ -0,0 +1,168 @@ +// vim: commentstring=//\ %s +{ + "layer": "top", + "position": "top", + "height": 30, + + "modules-left": ["sway/mode", "sway/workspaces", "sway/window", "custom/media", "custom/toggl"], + // "modules-center": ["sway/window"], + "modules-right": ["cpu", "memory", "temperature", "idle_inhibitor", "backlight", "pulseaudio", "network", "battery", "clock#local", "clock#utc", "tray"], + "sway/workspaces": { + "disable-scroll": true, + "all-outputs": false, + "format": "{icon}", + "format-icons": { + // "urgent": "", + // "focused": "", + // "default": "", + // "1": "", + // "2": "", + // "3": "", + // "4": "", + // "5": "", + // "6": "", + // "7": "", + // "8": "", + // "9": "", + "m": "", + "v": "", + "g": "" + } + }, + "sway/window": { + "format": "{}", + "max-length": 50, + "tooltip": false + }, + "sway/mode": { + "format": "{}", + "tooltip": false + }, + "idle_inhibitor": { + "format": "{icon}", + "format-icons": { + "activated": "", + "deactivated": "" + } + }, + "tray": { + "spacing": 10 + }, + "clock#local": { + "tooltip": false, + "format": "{:<i>%a</i> %d %b %H:%M}", + "timezone": "Europe/Berlin" + }, + "clock#utc": { + "tooltip": false, + "format": "(UTC {:%H:%M})", + "timezone": "UTC" + }, + "cpu": { + "format": "{usage}% ", + "tooltip": true + }, + "memory": { + "format": "{}% " + }, + "temperature": { + "critical-threshold": 90, + "format": "{temperatureC}℃ {icon}", + "format-icons": ["", "", ""] + }, + "backlight": { + "format": "{percent}% {icon}", + "format-icons": [""] + }, + "battery": { + "states": { + // "good": 95, + "warning": 30, + "critical": 15 + }, + "format": "{capacity}% {icon}", + "format-charging": "{capacity}% ", + "format-plugged": "{capacity}% ", + "format-alt": "{time} {icon}", + "format-full": "{icon}", + "format-icons": ["", "", "", "", ""], + "tooltip": false + }, + "network": { + "format-wifi": "{essid} ({signalStrength}%) ", + "format-ethernet": "{ifname}: {ipaddr}/{cidr} ", + "format-linked": "{ifname} (No IP) ", + "format-disconnected": "Disconnected ", + "format-alt": "{ifname}: {ipaddr}/{cidr}", + "tooltip": false + }, + "network#vpn": { + "interface": "tun0", + "format-wifi": " {ifname}", + "format-ethernet": " {ifname}", + "format-disconnected": "", + "tooltip": false + }, + "pulseaudio": { + "format": "{volume}% {icon}", + "format-bluetooth": "{volume}% {icon}", + "format-muted": "{volume}% ", + "format-source": "{volume}% ", + "format-source-muted": "{volume}% ", + "format-icons": { + "headphones": "", + "handsfree": "", + "headset": "", + "phone": "", + "portable": "", + "car": "", + "default": ["", "", ""] + }, + "tooltip": false, + "on-click-right": "pactl set-sink-mute @DEFAULT_SINK@ toggle", + "on-click": "pavucontrol" + }, + "custom/media": { + "format": "{icon} {}", + "return-type": "json", + "max-length": 80, + "format-icons": { + "spotify": "", + "mpv": "", + "default": "" + }, + "on-click": "sway [workspace=$wsMusic] focus", + "escape": false, + "exec": "$HOME/.config/waybar/mediaplayer.py -I chromium 2> /dev/null" + }, + "custom/toggl": { + "exec": "$HOME/.config/waybar/toggl.lua 2>/dev/null", + "interval": 30 + }, + "mpd": { + "format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ", + "format-disconnected": "Disconnected", + "format-stopped": "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped", + "unknown-tag": "N/A", + "interval": 2, + "consume-icons": { + "on": " " + }, + "random-icons": { + "off": "", + "on": " " + }, + "repeat-icons": { + "on": " " + }, + "single-icons": { + "on": "1 " + }, + "state-icons": { + "paused": "", + "playing": "" + }, + "tooltip-format": "MPD (connected)", + "tooltip-format-disconnected": "MPD (disconnected)" + } +} diff --git a/.config/waybar/mediaplayer.py b/.config/waybar/mediaplayer.py new file mode 100755 index 0000000..ce2314d --- /dev/null +++ b/.config/waybar/mediaplayer.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 + +import argparse +import json +import logging +import signal +import sys +from datetime import timedelta +from math import floor + +# yapf: disable +import gi +gi.require_version('Playerctl', '2.0') +from gi.repository import GLib, Playerctl +# yapf: enable + +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' + + 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 = ' ' + track_info + + 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): + 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 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() + 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) + + 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/style.css b/.config/waybar/style.css new file mode 100644 index 0000000..f832fd6 --- /dev/null +++ b/.config/waybar/style.css @@ -0,0 +1,194 @@ +@define-color foreground #fffefe; +@define-color background #221e1d; +@define-color accent #005CAF; +@define-color accentdarker #0B346F; +@define-color dimmed #777777; +@define-color dimmeddarker #302a29; +@define-color urgent #db4d6d; + +* { + border: none; + border-radius: 0; + font-family: Iosevka Medium, Noto Sans, Font Awesome, monospace; + font-size: 12pt; + min-height: 0; +} + +window#waybar { + background: @background; + /* opacity: 0.98; */ + /* border-bottom: 3px solid rgba(100, 114, 125, 0.5); */ + color: @foreground; + transition-property: background-color; + transition-duration: 0.1s; +} + +window#waybar.hidden { + opacity: 0.2; +} +/* window#waybar.empty {} */ +/* window#waybar.solo {} */ +/* window#waybar.<appid> {} */ + +#workspaces button { + padding: 0 5px; + /* background-color: transparent; */ + background: transparent; + color: @dimmed; + /* border-bottom: 3px solid transparent; */ +} + +/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ +#workspaces button:hover { + background: @dimmeddarker; + box-shadow: inherit; + text-shadow: inherit; +} + +#workspaces button.focused { + color: @foreground; + background: @accentdarker; +} +#workspaces button.focused:hover { + background: @accent; +} + +#workspaces button.urgent { + color: @background; + background-color: @urgent; +} + +#window { + color: @foreground; + border-top: 2px solid @accent; +} + +#mode { + font-style: italic; + background-color: #64727d; + border-top: 2px solid @foreground; +} + +#clock, +#battery, +#cpu, +#memory, +#temperature, +#backlight, +#network, +#pulseaudio, +#custom-media, +#custom-toggl, +#tray, +#mode, +#window, +#idle_inhibitor { + padding: 0 0.3rem; + margin: 0 0.25rem; + color: @foreground; + border-top: 2px solid @dimmeddarker; +} + +#clock { + /* background-color: #64727d; */ +} +#clock.local { + margin-right: 0; + padding-right: 0; +} +#clock.utc { + margin: 0; + padding: 0; + padding-left: 0.3rem; + color: @dimmed; +} + +#battery { +} +#battery.charging { + color: @foreground; + background-color: #26a65b; +} + +@keyframes blink { + to { + background-color: @foreground; + color: @background; + } +} + +#battery.critical:not(.charging) { + background-color: #f53c3c; + color: @foreground; + animation-name: blink; + animation-duration: 0.5s; + animation-timing-function: linear; + animation-iteration-count: infinite; + animation-direction: alternate; +} + +label:focus { + background-color: @background; +} + +#cpu { +} +#memory { +} +#backlight { +} +#network { +} +#network.disconnected { + color: @dimmed; +} +#pulseaudio { +} +#pulseaudio.muted { + color: @dimmed; +} + +#custom-media { + min-width: 100px; + color: @foreground; + border-top: 2px solid #628aaa; +} +#custom-media.custom-spotify, +#custom-media.custom-spotifyd { + border-top: 2px solid #1DB954; +} +#custom-media.custom-mpv { + border-top: 2px solid #520053; +} + +#custom-toggl { + color: @foreground; + /* background-color: #DB4D6D; */ + border-top: 2px solid #DB4D60; +} + +#temperature { +} + +#temperature.critical { + background-color: #eb4d4b; +} + +#tray { +} + +#idle_inhibitor { + color: @dimmed; +} +#idle_inhibitor.activated { + color: unset; +} + +#mpd { +} +#mpd.disconnected { +} +#mpd.stopped { +} +#mpd.paused { +} diff --git a/.config/waybar/toggl.lua b/.config/waybar/toggl.lua new file mode 100755 index 0000000..e44fce2 --- /dev/null +++ b/.config/waybar/toggl.lua @@ -0,0 +1,28 @@ +#!/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)) |