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