diff --git a/dot-config/waybar/bin/spotify-info b/dot-config/waybar/bin/spotify-info new file mode 100755 index 0000000..d7e7076 --- /dev/null +++ b/dot-config/waybar/bin/spotify-info @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +import gi +gi.require_version('Playerctl', '2.0') +from gi.repository import Playerctl, GLib +from typing import List, Self +from argparse import ArgumentParser +import json +import sys + +parser = ArgumentParser() +parser.add_argument("-l", "--main-loop", action="store_true") +parser.add_argument("-p", "--play-pause", action="store_true") +parser.add_argument("-N", "--next", action="store_true") +parser.add_argument("-P", "--previous", action="store_true") +args = parser.parse_args() + + +PLAY_ICON = " " +PAUSE_ICON = " " + +manager = Playerctl.PlayerManager() + + +class json_data(dict): + def __init__(self) -> None: + super().__init__() + self["text"] = "" + self["alt"] = "" + self["tooltip"] = "" + self["icon"] = "" + def print(self, data=(), **kwargs) -> Self: + super().update(data, **kwargs) + out = { + "text": str(self.get("icon")) + str(self.get("text")), + "alt": self["alt"], + "tooltip": self["tooltip"] + } + sys.stdout.write(json.dumps(out) + '\n') + sys.stdout.flush() + return self + +jdata: json_data = json_data() + + +def on_play(player, status, manager): + global jdata + jdata.print({"icon": PLAY_ICON}) + + +def on_pause(player, status, manager): + global jdata + jdata.print({"icon": PAUSE_ICON}) + + +def on_metadata(player, metadata, manager): + global jdata + keys = metadata.keys() + if 'xesam:artist' in keys and 'xesam:title' in keys: + jdata.print( + { + "text": f'{metadata['xesam:artist'][0]} - {metadata['xesam:title']}', + "alt": metadata['xesam:title'], + "tooltip": f'{', '.join(metadata['xesam:artist'])} - {metadata['xesam:title']}' + } + ) + + +def init_player(name): + if name.name in ['spotify']: + player = Playerctl.Player.new_from_name(name) + player.connect('playback-status::playing', on_play, manager) + player.connect('playback-status::paused', on_pause, manager) + player.connect('metadata', on_metadata, manager) + manager.manage_player(player) + + +def on_name_appeared(manager, name): + init_player(name) + + +def on_player_vanished(manager, player): + jdata.print({"text": "", "icon": ""}) + + +def get_spotify() -> Playerctl.Player | None: + for name in manager.props.player_names: + if name.name in ['spotify']: + return Playerctl.Player.new_from_name(name) + + +def main_loop(): + manager.connect('name-appeared', on_name_appeared) + manager.connect('player-vanished', on_player_vanished) + + for name in manager.props.player_names: + init_player(name) + + if spotify := get_spotify(): + jdata.print( + { + "text": f'{spotify.get_artist()} - {spotify.get_title()}', + "alt": spotify.get_title(), + "tooltip": f'{spotify.get_artist()} - {spotify.get_title()}' + } + ) + if spotify.props.status == "Playing": + jdata.print({"icon": PLAY_ICON}) + else: + jdata.print({"icon": PAUSE_ICON}) + else: + jdata.print({"text": "", "percentage": 0}) + + + main = GLib.MainLoop() + main.run() + + +def play_pause(): + if spotify := get_spotify(): + spotify.play_pause() + + +def next(): + if spotify := get_spotify(): + spotify.next() + + +def previous(): + if spotify := get_spotify(): + spotify.previous() + + +if args.main_loop: + try: + main_loop() + except KeyboardInterrupt: + exit(0) + exit(1) + +if args.play_pause: + play_pause() + exit(0) + +if args.next: + next() + exit(0) + +if args.previous: + previous() + exit(0) + diff --git a/dot-config/waybar/waybar.css b/dot-config/waybar/waybar.css index fa965b6..a3829ab 100644 --- a/dot-config/waybar/waybar.css +++ b/dot-config/waybar/waybar.css @@ -12,7 +12,7 @@ window#waybar { /* background: @base; */ transition-property: background-color; transition-duration: .5s; - border-radius: 14px 14px 0px 0px; + border-radius: 0px 0px 14px 14px; } #workspaces { @@ -47,7 +47,7 @@ window#waybar { #custom-power, #custom-runner, #battery, #backlight, #wireplumber, #wireplumber.muted, -#tray, #language, #clock { +#tray, #language, #clock, #custom-spotify { background: @mantle; border-radius: 14px; color: @text; @@ -59,7 +59,7 @@ window#waybar { padding: 0px 9px; } -#custom-runner { +#custom-spotify { padding: 0px 10px; } diff --git a/dot-config/waybar/waybar.jsonc b/dot-config/waybar/waybar.jsonc index 6783f38..a51a231 100644 --- a/dot-config/waybar/waybar.jsonc +++ b/dot-config/waybar/waybar.jsonc @@ -1,22 +1,22 @@ { - "position": "bottom", - "height": 36, + "position": "top", + "height": 34, "width": 900, "spacing": 0, - "margin-bottom": 0, "layer": "top", - "modules-left": ["tray"], + "margin-bottom": -15, + "modules-left": ["tray", "custom/spotify"], "modules-center": ["hyprland/workspaces"], "modules-right": ["wireplumber", "hyprland/language", "clock"], - "custom/power": { - "format": "", - "on-click": "~/.config/hypr/bin/powermenu" - }, - - "custom/runner": { - "format": "", - "on-click": "hyprlauncher" + "custom/spotify": { + "format": "{}", + "hide-empty-text": true, + "return-type": "json", + "exec": "~/.config/waybar/bin/spotify-info -l", + "on-click": "~/.config/waybar/bin/spotify-info -p", + "on-scroll-up": "~/.config/waybar/bin/spotify-info -N", + "on-scroll-down": "~/.config/waybar/bin/spotify-info -P" }, "hyprland/workspaces": {