1#!/usr/local/bin/python3.8 2 3import gi 4gi.require_version('Cvc', '1.0') 5 6from gi.repository import Gtk 7import datetime 8 9from util import trackers, utils 10from dbusdepot.mediaPlayerWatcher import PlaybackStatus 11from widgets.marqueeLabel import MarqueeLabel 12from widgets.transparentButton import TransparentButton 13import singletons 14import status 15 16class PlayerControl(Gtk.Box): 17 """ 18 Provides info and controls for any active music or other media player. It is a 19 a direct child of the AudioPanel, and is only shown if there is an active mpris 20 interface we can connect to. 21 """ 22 def __init__(self): 23 super(PlayerControl, self).__init__(orientation=Gtk.Orientation.HORIZONTAL) 24 25 self.watcher = singletons.MediaPlayerWatcher 26 self.player = self.watcher.get_best_player() 27 28 if self.player: 29 self.build_layout() 30 31 def build_layout(self): 32 player_status = self.player.get_playback_status() 33 34 # Player buttons 35 36 button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) 37 button_box.set_homogeneous(True) 38 vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) 39 self.pack_start(vbox, True, True, 2) 40 vbox.pack_start(button_box, True, True, 0) 41 vbox.set_valign(Gtk.Align.CENTER) 42 43 self.previous_button = TransparentButton("media-skip-backward-symbolic", Gtk.IconSize.BUTTON) 44 self.previous_button.show() 45 trackers.con_tracker_get().connect(self.previous_button, 46 "clicked", 47 self.on_previous_clicked) 48 49 button_box.pack_start(self.previous_button, True, True, 2) 50 51 self.play_pause_button = TransparentButton(self.get_play_pause_icon_name(player_status), Gtk.IconSize.BUTTON) 52 self.play_pause_button.show() 53 trackers.con_tracker_get().connect(self.play_pause_button, 54 "clicked", 55 self.on_play_pause_clicked) 56 button_box.pack_start(self.play_pause_button, True, True, 2) 57 58 self.next_button = TransparentButton("media-skip-forward-symbolic", Gtk.IconSize.BUTTON) 59 self.next_button.show() 60 trackers.con_tracker_get().connect(self.next_button, 61 "clicked", 62 self.on_next_clicked) 63 button_box.pack_start(self.next_button, True, True, 2) 64 65 self.update_buttons(player_status) 66 67 status.focusWidgets = status.focusWidgets + [self.previous_button, 68 self.play_pause_button, 69 self.next_button] 70 71 # Track info 72 73 vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) 74 self.pack_start(vbox, True, True, 6) 75 76 vbox.set_valign(Gtk.Align.CENTER) 77 78 self.track_name_label = MarqueeLabel("") 79 self.track_name_label.get_style_context().add_class("trackname") 80 vbox.pack_start(self.track_name_label, True, True, 2) 81 82 self.album_artist_label = MarqueeLabel("") 83 self.album_artist_label.get_style_context().add_class("albumartist") 84 vbox.pack_end(self.album_artist_label, True, True, 2) 85 86 self.show_all() 87 88 trackers.con_tracker_get().connect(self.player, 89 "status-changed", 90 self.on_playback_status_changed) 91 92 trackers.con_tracker_get().connect(self.player, 93 "metadata-changed", 94 self.on_metadata_changed) 95 96 self.on_playback_status_changed(self.player, player_status) 97 self.on_metadata_changed(self.player) 98 99 trackers.con_tracker_get().connect(self, 100 "destroy", 101 self.on_widget_destroy) 102 103 def on_previous_clicked(self, button, data=None): 104 self.player.go_previous() 105 106 def on_next_clicked(self, button, data=None): 107 self.player.go_next() 108 109 def on_play_pause_clicked(self, button, data=None): 110 self.player.play_pause() 111 112 def get_play_pause_icon_name(self, status): 113 if status == PlaybackStatus.Playing: 114 icon_name = "media-playback-pause-symbolic" 115 else: 116 icon_name = "media-playback-start-symbolic" 117 118 return icon_name 119 120 def on_playback_status_changed(self, player, status, data=None): 121 self.update_buttons(status) 122 123 def on_metadata_changed(self, player): 124 """ 125 Update labels when the player metadata changes 126 """ 127 self.update_labels() 128 129 def update_labels(self): 130 """ 131 Construct the track and artist-album labels as well as possible. 132 """ 133 self.track_name_label.set_text(self.player.get_track_name()) 134 135 artist_name = self.player.get_artist_name() 136 album_name = self.player.get_album_name() 137 138 if artist_name != "" and album_name != "": 139 self.album_artist_label.set_text("%s - %s" % (self.player.get_artist_name(), self.player.get_album_name())) 140 elif artist_name != "": 141 self.album_artist_label.set_text(artist_name) 142 elif album_name != "": 143 self.album_artist_label.set_text(album_name) 144 else: 145 self.album_artist_label.set_text("") 146 147 def update_buttons(self, status): 148 """ 149 Updates the player buttons based on the current state 150 """ 151 self.play_pause_button.set_sensitive(self.player.get_can_play_pause()) 152 self.next_button.set_sensitive(self.player.get_can_go_next()) 153 self.previous_button.set_sensitive(self.player.get_can_go_previous()) 154 155 icon_name = self.get_play_pause_icon_name(status) 156 157 image = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.BUTTON) 158 self.play_pause_button.set_image(image) 159 160 def on_widget_destroy(self, widget, data=None): 161 trackers.con_tracker_get().disconnect(self.player, 162 "status-changed", 163 self.on_playback_status_changed) 164 165 trackers.con_tracker_get().disconnect(self, 166 "destroy", 167 self.on_widget_destroy) 168 169 def should_show(self): 170 """ 171 Checked by the AudioPanel, whether or not this widget should be displayed. 172 """ 173 return self.player != None 174