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