mediaplayer.py (3803B)
1 #!/usr/bin/env python3 2 import argparse 3 import logging 4 import sys 5 import signal 6 import gi 7 import json 8 gi.require_version('Playerctl', '2.0') 9 from gi.repository import Playerctl, GLib 10 11 logger = logging.getLogger(__name__) 12 13 14 def write_output(text, player): 15 logger.info('Writing output') 16 17 output = {'text': text, 18 'class': 'custom-' + player.props.player_name, 19 'alt': player.props.player_name} 20 21 sys.stdout.write(json.dumps(output) + '\n') 22 sys.stdout.flush() 23 24 25 def on_play(player, status, manager): 26 logger.info('Received new playback status') 27 on_metadata(player, player.props.metadata, manager) 28 29 30 def on_metadata(player, metadata, manager): 31 logger.info('Received new metadata') 32 track_info = '' 33 34 if player.props.player_name == 'spotify' and \ 35 'mpris:trackid' in metadata.keys() and \ 36 ':ad:' in player.props.metadata['mpris:trackid']: 37 track_info = 'AD PLAYING' 38 elif player.get_artist() != '' and player.get_title() != '': 39 track_info = '{artist} - {title}'.format(artist=player.get_artist(), 40 title=player.get_title()) 41 else: 42 track_info = player.get_title() 43 44 if player.props.status != 'Playing' and track_info: 45 track_info = ' ' + track_info 46 write_output(track_info, player) 47 48 49 def on_player_appeared(manager, player, selected_player=None): 50 if player is not None and (selected_player is None or player.name == selected_player): 51 init_player(manager, player) 52 else: 53 logger.debug("New player appeared, but it's not the selected player, skipping") 54 55 56 def on_player_vanished(manager, player): 57 logger.info('Player has vanished') 58 sys.stdout.write('\n') 59 sys.stdout.flush() 60 61 62 def init_player(manager, name): 63 logger.debug('Initialize player: {player}'.format(player=name.name)) 64 player = Playerctl.Player.new_from_name(name) 65 player.connect('playback-status', on_play, manager) 66 player.connect('metadata', on_metadata, manager) 67 manager.manage_player(player) 68 on_metadata(player, player.props.metadata, manager) 69 70 71 def signal_handler(sig, frame): 72 logger.debug('Received signal to stop, exiting') 73 sys.stdout.write('\n') 74 sys.stdout.flush() 75 # loop.quit() 76 sys.exit(0) 77 78 79 def parse_arguments(): 80 parser = argparse.ArgumentParser() 81 82 # Increase verbosity with every occurence of -v 83 parser.add_argument('-v', '--verbose', action='count', default=0) 84 85 # Define for which player we're listening 86 parser.add_argument('--player') 87 88 return parser.parse_args() 89 90 91 def main(): 92 arguments = parse_arguments() 93 94 # Initialize logging 95 logging.basicConfig(stream=sys.stderr, level=logging.DEBUG, 96 format='%(name)s %(levelname)s %(message)s') 97 98 # Logging is set by default to WARN and higher. 99 # With every occurrence of -v it's lowered by one 100 logger.setLevel(max((3 - arguments.verbose) * 10, 0)) 101 102 # Log the sent command line arguments 103 logger.debug('Arguments received {}'.format(vars(arguments))) 104 105 manager = Playerctl.PlayerManager() 106 loop = GLib.MainLoop() 107 108 manager.connect('name-appeared', lambda *args: on_player_appeared(*args, arguments.player)) 109 manager.connect('player-vanished', on_player_vanished) 110 111 signal.signal(signal.SIGINT, signal_handler) 112 signal.signal(signal.SIGTERM, signal_handler) 113 114 for player in manager.props.player_names: 115 if arguments.player is not None and arguments.player != player.name: 116 logger.debug('{player} is not the filtered player, skipping it' 117 .format(player=player.name) 118 ) 119 continue 120 121 init_player(manager, player) 122 123 loop.run() 124 125 126 if __name__ == '__main__': 127 main()