示例#1
0
class PlayerControl(Gtk.Box):
    """
    Provides info and controls for any active music or other media player.  It is a
    a direct child of the AudioPanel, and is only shown if there is an active mpris
    interface we can connect to.
    """
    def __init__(self):
        super(PlayerControl, self).__init__(orientation=Gtk.Orientation.HORIZONTAL)

        self.watcher = singletons.MediaPlayerWatcher
        self.player = self.watcher.get_best_player()

        if self.player:
            self.build_layout()

    def build_layout(self):
        size = Gtk.IconSize.from_name("audio-button")

        player_status = self.player.get_playback_status()

        # Player buttons

        button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        button_box.set_homogeneous(True)
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 2)
        vbox.pack_start(button_box, True, True, 0)
        vbox.set_valign(Gtk.Align.CENTER)

        self.previous_button = TransparentButton("media-skip-backward-symbolic", size)
        self.previous_button.show()
        trackers.con_tracker_get().connect(self.previous_button,
                                           "clicked",
                                           self.on_previous_clicked)

        button_box.pack_start(self.previous_button, True, True, 2)

        self.play_pause_button = TransparentButton(self.get_play_pause_icon_name(player_status), size)
        self.play_pause_button.show()
        trackers.con_tracker_get().connect(self.play_pause_button,
                                           "clicked",
                                           self.on_play_pause_clicked)
        button_box.pack_start(self.play_pause_button, True, True, 2)

        self.next_button = TransparentButton("media-skip-forward-symbolic", size)
        self.next_button.show()
        trackers.con_tracker_get().connect(self.next_button,
                                           "clicked",
                                           self.on_next_clicked)
        button_box.pack_start(self.next_button, True, True, 2)

        self.update_buttons(player_status)

        status.focusWidgets = status.focusWidgets + [self.previous_button,
                                                     self.play_pause_button,
                                                     self.next_button]

        # Track info

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 6)

        vbox.set_valign(Gtk.Align.CENTER)

        self.track_name_label = MarqueeLabel("")
        self.track_name_label.get_style_context().add_class("trackname")
        vbox.pack_start(self.track_name_label, True, True, 2)

        self.album_artist_label = MarqueeLabel("")
        self.album_artist_label.get_style_context().add_class("albumartist")
        vbox.pack_end(self.album_artist_label, True, True, 2)

        self.show_all()

        trackers.con_tracker_get().connect(self.player,
                                           "status-changed",
                                           self.on_playback_status_changed)

        trackers.con_tracker_get().connect(self.player,
                                           "metadata-changed",
                                           self.on_metadata_changed)

        self.on_playback_status_changed(self.player, player_status)
        self.on_metadata_changed(self.player)

        trackers.con_tracker_get().connect(self,
                                           "destroy",
                                           self.on_widget_destroy)

    def on_previous_clicked(self, button, data=None):
        self.player.go_previous()

    def on_next_clicked(self, button, data=None):
        self.player.go_next()

    def on_play_pause_clicked(self, button, data=None):
        self.player.play_pause()

    def get_play_pause_icon_name(self, status):
        if status == PlaybackStatus.Playing:
            icon_name = "media-playback-pause-symbolic"
        else:
            icon_name = "media-playback-start-symbolic"

        return icon_name

    def on_playback_status_changed(self, player, status, data=None):
        self.update_buttons(status)

    def on_metadata_changed(self, player):
        """
        Update labels when the player metadata changes
        """
        self.update_labels()

    def update_labels(self):
        """
        Construct the track and artist-album labels as well as possible.
        """
        self.track_name_label.set_text(self.player.get_track_name())

        artist_name = self.player.get_artist_name()
        album_name = self.player.get_album_name()

        if artist_name != "" and album_name != "":
            self.album_artist_label.set_text("%s - %s" % (self.player.get_artist_name(), self.player.get_album_name()))
        elif artist_name != "":
            self.album_artist_label.set_text(artist_name)
        elif album_name != "":
            self.album_artist_label.set_text(album_name)
        else:
            self.album_artist_label.set_text("")

    def update_buttons(self, status):
        """
        Updates the player buttons based on the current state
        """
        self.play_pause_button.set_sensitive(self.player.get_can_play_pause())
        self.next_button.set_sensitive(self.player.get_can_go_next())
        self.previous_button.set_sensitive(self.player.get_can_go_previous())

        icon_name = self.get_play_pause_icon_name(status)

        size = Gtk.IconSize.from_name("audio-button")

        image = Gtk.Image.new_from_icon_name(icon_name, size)
        self.play_pause_button.set_image(image)

    def on_widget_destroy(self, widget, data=None):
        trackers.con_tracker_get().disconnect(self.player,
                                              "status-changed",
                                              self.on_playback_status_changed)

        trackers.con_tracker_get().disconnect(self,
                                              "destroy",
                                              self.on_widget_destroy)

    def should_show(self):
        """
        Checked by the AudioPanel, whether or not this widget should be displayed.
        """
        return self.player != None
class PlayerControl(Gtk.Box):
    def __init__(self):
        super(PlayerControl, self).__init__(orientation=Gtk.Orientation.HORIZONTAL)

        self.watcher = singletons.MediaPlayerWatcher
        self.player = self.watcher.get_best_player()

        if self.player:
            self.build_layout()

    def build_layout(self):
        size = Gtk.IconSize.from_name("audio-button")
        # size = Gtk.IconSize.MENU

        player_status = self.player.get_playback_status()

        # Player buttons

        self.pack_start(Gtk.VSeparator(), True, True, 2)

        button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        button_box.set_homogeneous(True)
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 2)
        vbox.pack_start(button_box, True, True, 0)
        vbox.set_valign(Gtk.Align.CENTER)

        self.previous_button = TransparentButton("media-skip-backward-symbolic", size)
        self.previous_button.show()
        trackers.con_tracker_get().connect(self.previous_button,
                                           "clicked",
                                           self.on_previous_clicked)

        button_box.pack_start(self.previous_button, True, True, 2)

        self.play_pause_button = TransparentButton(self.get_play_pause_icon_name(player_status), size)
        self.play_pause_button.show()
        trackers.con_tracker_get().connect(self.play_pause_button,
                                           "clicked",
                                           self.on_play_pause_clicked)
        button_box.pack_start(self.play_pause_button, True, True, 2)

        self.next_button = TransparentButton("media-skip-forward-symbolic", size)
        self.next_button.show()
        trackers.con_tracker_get().connect(self.next_button,
                                           "clicked",
                                           self.on_next_clicked)
        button_box.pack_start(self.next_button, True, True, 2)

        self.update_buttons(player_status)

        status.focusWidgets = status.focusWidgets + [self.previous_button,
                                                     self.play_pause_button,
                                                     self.next_button]

        # Position labels and bar

        self.pack_start(Gtk.VSeparator(), True, True, 2)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 4)

        vbox.set_valign(Gtk.Align.CENTER)

        position_length_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        vbox.pack_start(position_length_box, True, True, 2)

        self.current_pos_label = BlinkingLabel("", 400)
        self.current_pos_label.get_style_context().add_class("positionlabel")
        position_length_box.pack_start(self.current_pos_label, False, False, 2)

        self.max_pos_label = BlinkingLabel("", 400)
        self.max_pos_label.get_style_context().add_class("positionlabel")
        position_length_box.pack_end(self.max_pos_label, False, False, 2)

        self.position_bar = PositionBar()
        vbox.pack_end(self.position_bar, True, True, 2)

        # Track info

        self.pack_start(Gtk.VSeparator(), True, True, 2)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 6)

        vbox.set_valign(Gtk.Align.CENTER)

        self.track_name_label = MarqueeLabel("")
        self.track_name_label.get_style_context().add_class("trackname")
        vbox.pack_start(self.track_name_label, True, True, 2)

        self.album_artist_label = MarqueeLabel("")
        self.album_artist_label.get_style_context().add_class("albumartist")
        vbox.pack_end(self.album_artist_label, True, True, 2)

        self.show_all()

        trackers.con_tracker_get().connect(self.player,
                                           "position-changed",
                                           self.on_position_changed)

        trackers.con_tracker_get().connect(self.player,
                                           "status-changed",
                                           self.on_playback_status_changed)

        trackers.con_tracker_get().connect(self.player,
                                           "metadata-changed",
                                           self.on_metadata_changed)

        self.on_playback_status_changed(self.player, player_status)
        self.on_metadata_changed(self.player)

        trackers.con_tracker_get().connect(self,
                                           "destroy",
                                           self.on_widget_destroy)

        self.update_position_timer(player_status)

    def on_previous_clicked(self, button, data=None):
        self.player.go_previous()

    def on_next_clicked(self, button, data=None):
        self.player.go_next()

    def on_play_pause_clicked(self, button, data=None):
        self.player.play_pause()

    def get_play_pause_icon_name(self, status):
        if status == PlaybackStatus.Playing:
            icon_name = "media-playback-pause-symbolic"
        else:
            icon_name = "media-playback-start-symbolic"

        return icon_name

    def position_to_time_string(self, position):
        delta = datetime.timedelta(microseconds=position)

        duration = datetime.datetime.utcfromtimestamp(delta.total_seconds())

        if duration.hour < 0:
            return _("--:--")

        if duration.hour < 1:
            return duration.strftime(_("%M:%S"))
        else:
            return duration.strftime(_("%H:%M:%S"))

    def on_playback_status_changed(self, player, status, data=None):
        self.update_buttons(status)
        self.update_position_timer(status)
        self.update_position_display()

        self.update_position_values_appearance(status)

    def update_position_values_appearance(self, status):
        if status == PlaybackStatus.Paused:
            self.max_pos_label.set_blinking(True)
            self.current_pos_label.set_blinking(True)
        else:
            self.max_pos_label.set_blinking(False)
            self.current_pos_label.set_blinking(False)

    def on_metadata_changed(self, player):
        self.max_pos_label.set_text(self.position_to_time_string(self.player.get_max_position()))
        self.update_labels()

    def update_labels(self):
        self.track_name_label.set_text(self.player.get_track_name())

        artist_name = self.player.get_artist_name()
        album_name = self.player.get_album_name()

        if artist_name != "" and album_name != "":
            self.album_artist_label.set_text("%s - %s" % (self.player.get_artist_name(), self.player.get_album_name()))
        elif artist_name != "":
            self.album_artist_label.set_text(artist_name)
        elif album_name != "":
            self.album_artist_label.set_text(album_name)
        else:
            self.album_artist_label.set_text("")

    def pause_blink_step(self):
        self.max_pos_label.set_visible(not self.max_pos_label.get_visible())
        self.current_pos_label.set_visible(not self.current_pos_label.get_visible())

        return True

    def update_buttons(self, status):
        self.play_pause_button.set_sensitive(self.player.get_can_play_pause())
        self.next_button.set_sensitive(self.player.get_can_go_next())
        self.previous_button.set_sensitive(self.player.get_can_go_previous())

        icon_name = self.get_play_pause_icon_name(status)

        size = Gtk.IconSize.from_name("audio-button")

        image = Gtk.Image.new_from_icon_name(icon_name, size)
        self.play_pause_button.set_image(image)

    def update_position_display(self):
        if self.player.get_position() < self.player.get_max_position():
            value = self.player.get_position() / self.player.get_max_position()
        else:
            value = 1.0
        value = utils.CLAMP(value, 0.0, 1.0)
        self.position_bar.set_fraction(value)

        self.current_pos_label.set_text(self.position_to_time_string(self.player.get_position()))

        return True

    def update_position_timer(self, status):
        if status == PlaybackStatus.Playing:
            trackers.timer_tracker_get().start("position-timer", self.player.get_rate() * 1000, self.update_position_display)
        else:
            trackers.timer_tracker_get().cancel("position-timer")

    def on_position_changed(self, player, position, data=None):
        self.update_position_display()

    def on_widget_destroy(self, widget, data=None):
        trackers.con_tracker_get().disconnect(self.player,
                                              "position-changed",
                                              self.on_position_changed)

        trackers.con_tracker_get().disconnect(self.player,
                                              "status-changed",
                                              self.on_playback_status_changed)

        trackers.con_tracker_get().disconnect(self,
                                              "destroy",
                                              self.on_widget_destroy)

        trackers.timer_tracker_get().cancel("position-timer")

    def should_show(self):
        return self.player != None
class PlayerControl(Gtk.Box):
    """
    Provides info and controls for any active music or other media player.  It is a
    a direct child of the AudioPanel, and is only shown if there is an active mpris
    interface we can connect to.
    """
    def __init__(self):
        super(PlayerControl, self).__init__(orientation=Gtk.Orientation.HORIZONTAL)

        self.watcher = singletons.MediaPlayerWatcher
        self.player = self.watcher.get_best_player()

        if self.player:
            self.build_layout()

    def build_layout(self):
        size = Gtk.IconSize.from_name("audio-button")

        player_status = self.player.get_playback_status()

        # Player buttons

        self.pack_start(Gtk.VSeparator(), True, True, 2)

        button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        button_box.set_homogeneous(True)
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 2)
        vbox.pack_start(button_box, True, True, 0)
        vbox.set_valign(Gtk.Align.CENTER)

        self.previous_button = TransparentButton("media-skip-backward-symbolic", size)
        self.previous_button.show()
        trackers.con_tracker_get().connect(self.previous_button,
                                           "clicked",
                                           self.on_previous_clicked)

        button_box.pack_start(self.previous_button, True, True, 2)

        self.play_pause_button = TransparentButton(self.get_play_pause_icon_name(player_status), size)
        self.play_pause_button.show()
        trackers.con_tracker_get().connect(self.play_pause_button,
                                           "clicked",
                                           self.on_play_pause_clicked)
        button_box.pack_start(self.play_pause_button, True, True, 2)

        self.next_button = TransparentButton("media-skip-forward-symbolic", size)
        self.next_button.show()
        trackers.con_tracker_get().connect(self.next_button,
                                           "clicked",
                                           self.on_next_clicked)
        button_box.pack_start(self.next_button, True, True, 2)

        self.update_buttons(player_status)

        status.focusWidgets = status.focusWidgets + [self.previous_button,
                                                     self.play_pause_button,
                                                     self.next_button]

        # Position labels and bar

        self.pack_start(Gtk.VSeparator(), True, True, 2)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 4)

        vbox.set_valign(Gtk.Align.CENTER)

        position_length_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        vbox.pack_start(position_length_box, True, True, 2)

        self.current_pos_label = BlinkingLabel("", 400)
        self.current_pos_label.get_style_context().add_class("positionlabel")
        position_length_box.pack_start(self.current_pos_label, False, False, 2)

        self.max_pos_label = BlinkingLabel("", 400)
        self.max_pos_label.get_style_context().add_class("positionlabel")
        position_length_box.pack_end(self.max_pos_label, False, False, 2)

        self.position_bar = PositionBar()
        vbox.pack_end(self.position_bar, True, True, 2)

        # Track info

        self.pack_start(Gtk.VSeparator(), True, True, 2)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 6)

        vbox.set_valign(Gtk.Align.CENTER)

        self.track_name_label = MarqueeLabel("")
        self.track_name_label.get_style_context().add_class("trackname")
        vbox.pack_start(self.track_name_label, True, True, 2)

        self.album_artist_label = MarqueeLabel("")
        self.album_artist_label.get_style_context().add_class("albumartist")
        vbox.pack_end(self.album_artist_label, True, True, 2)

        self.show_all()

        trackers.con_tracker_get().connect(self.player,
                                           "position-changed",
                                           self.on_position_changed)

        trackers.con_tracker_get().connect(self.player,
                                           "status-changed",
                                           self.on_playback_status_changed)

        trackers.con_tracker_get().connect(self.player,
                                           "metadata-changed",
                                           self.on_metadata_changed)

        self.on_playback_status_changed(self.player, player_status)
        self.on_metadata_changed(self.player)

        trackers.con_tracker_get().connect(self,
                                           "destroy",
                                           self.on_widget_destroy)

        self.update_position_timer(player_status)

    def on_previous_clicked(self, button, data=None):
        self.player.go_previous()

    def on_next_clicked(self, button, data=None):
        self.player.go_next()

    def on_play_pause_clicked(self, button, data=None):
        self.player.play_pause()

    def get_play_pause_icon_name(self, status):
        if status == PlaybackStatus.Playing:
            icon_name = "media-playback-pause-symbolic"
        else:
            icon_name = "media-playback-start-symbolic"

        return icon_name

    def position_to_time_string(self, position):
        """
        We receive track position and track length values in microseconds.
        This function formats this into readable HH:MM:SS format, and handles
        any invalid values.
        """
        delta = datetime.timedelta(microseconds=position)

        duration = datetime.datetime.utcfromtimestamp(delta.total_seconds())

        if duration.hour < 0:
            return _("--:--")

        if duration.hour < 1:
            return duration.strftime(_("%M:%S"))
        else:
            return duration.strftime(_("%H:%M:%S"))

    def on_playback_status_changed(self, player, status, data=None):
        self.update_buttons(status)
        self.update_position_timer(status)
        self.update_position_display()

        self.update_position_values_appearance(status)

    def update_position_values_appearance(self, status):
        """
        When the player is paused, we blink the position/length values.
        """
        if status == PlaybackStatus.Paused:
            self.max_pos_label.set_blinking(True)
            self.current_pos_label.set_blinking(True)
        else:
            self.max_pos_label.set_blinking(False)
            self.current_pos_label.set_blinking(False)

    def on_metadata_changed(self, player):
        """
        Update max position and labels when the player metadata changes
        """
        self.max_pos_label.set_text(self.position_to_time_string(self.player.get_max_position()))
        self.update_labels()

    def update_labels(self):
        """
        Construct the track and artist-album labels as well as possible.
        """
        self.track_name_label.set_text(self.player.get_track_name())

        artist_name = self.player.get_artist_name()
        album_name = self.player.get_album_name()

        if artist_name != "" and album_name != "":
            self.album_artist_label.set_text("%s - %s" % (self.player.get_artist_name(), self.player.get_album_name()))
        elif artist_name != "":
            self.album_artist_label.set_text(artist_name)
        elif album_name != "":
            self.album_artist_label.set_text(album_name)
        else:
            self.album_artist_label.set_text("")

    def update_buttons(self, status):
        """
        Updates the player buttons based on the current state
        """
        self.play_pause_button.set_sensitive(self.player.get_can_play_pause())
        self.next_button.set_sensitive(self.player.get_can_go_next())
        self.previous_button.set_sensitive(self.player.get_can_go_previous())

        icon_name = self.get_play_pause_icon_name(status)

        size = Gtk.IconSize.from_name("audio-button")

        image = Gtk.Image.new_from_icon_name(icon_name, size)
        self.play_pause_button.set_image(image)

    def update_position_display(self):
        """
        Updates the position values and bar to reflect the current state.
        """
        if self.player.get_position() < self.player.get_max_position():
            value = self.player.get_position() / self.player.get_max_position()
        else:
            value = 1.0
        value = utils.CLAMP(value, 0.0, 1.0)
        self.position_bar.set_fraction(value)

        self.current_pos_label.set_text(self.position_to_time_string(self.player.get_position()))

        return True

    def update_position_timer(self, status):
        """
        Starts or stops the position update timer - this is based upon the provided rate
        property of the player, which is defined as the recommended update frequency for position
        data.
        """
        if status == PlaybackStatus.Playing:
            trackers.timer_tracker_get().start("position-timer", self.player.get_rate() * 1000, self.update_position_display)
        else:
            trackers.timer_tracker_get().cancel("position-timer")

    def on_position_changed(self, player, position, data=None):
        """
        Callback for an explicit position change from the player.
        """
        self.update_position_display()

    def on_widget_destroy(self, widget, data=None):
        trackers.con_tracker_get().disconnect(self.player,
                                              "position-changed",
                                              self.on_position_changed)

        trackers.con_tracker_get().disconnect(self.player,
                                              "status-changed",
                                              self.on_playback_status_changed)

        trackers.con_tracker_get().disconnect(self,
                                              "destroy",
                                              self.on_widget_destroy)

        trackers.timer_tracker_get().cancel("position-timer")

    def should_show(self):
        """
        Checked by the AudioPanel, whether or not this widget should be displayed.
        """
        return self.player != None
示例#4
0
class PlayerControl(Gtk.Box):
    """
    Provides info and controls for any active music or other media player.  It is a
    a direct child of the AudioPanel, and is only shown if there is an active mpris
    interface we can connect to.
    """
    def __init__(self):
        super(PlayerControl,
              self).__init__(orientation=Gtk.Orientation.HORIZONTAL)

        self.watcher = singletons.MediaPlayerWatcher
        self.player = self.watcher.get_best_player()

        if self.player:
            self.build_layout()

    def build_layout(self):
        size = Gtk.IconSize.from_name("audio-button")

        player_status = self.player.get_playback_status()

        # Player buttons

        button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        button_box.set_homogeneous(True)
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 2)
        vbox.pack_start(button_box, True, True, 0)
        vbox.set_valign(Gtk.Align.CENTER)

        self.previous_button = TransparentButton(
            "media-skip-backward-symbolic", size)
        self.previous_button.show()
        trackers.con_tracker_get().connect(self.previous_button, "clicked",
                                           self.on_previous_clicked)

        button_box.pack_start(self.previous_button, True, True, 2)

        self.play_pause_button = TransparentButton(
            self.get_play_pause_icon_name(player_status), size)
        self.play_pause_button.show()
        trackers.con_tracker_get().connect(self.play_pause_button, "clicked",
                                           self.on_play_pause_clicked)
        button_box.pack_start(self.play_pause_button, True, True, 2)

        self.next_button = TransparentButton("media-skip-forward-symbolic",
                                             size)
        self.next_button.show()
        trackers.con_tracker_get().connect(self.next_button, "clicked",
                                           self.on_next_clicked)
        button_box.pack_start(self.next_button, True, True, 2)

        self.update_buttons(player_status)

        status.focusWidgets = status.focusWidgets + [
            self.previous_button, self.play_pause_button, self.next_button
        ]

        # Position labels and bar

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 4)

        vbox.set_valign(Gtk.Align.CENTER)

        position_length_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        vbox.pack_start(position_length_box, True, True, 2)

        self.current_pos_label = BlinkingLabel("", 400)
        self.current_pos_label.get_style_context().add_class("positionlabel")
        position_length_box.pack_start(self.current_pos_label, False, False, 2)

        self.max_pos_label = BlinkingLabel("", 400)
        self.max_pos_label.get_style_context().add_class("positionlabel")
        position_length_box.pack_end(self.max_pos_label, False, False, 2)

        self.position_bar = PositionBar()
        vbox.pack_end(self.position_bar, True, True, 2)

        # Track info

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 6)

        vbox.set_valign(Gtk.Align.CENTER)

        self.track_name_label = MarqueeLabel("")
        self.track_name_label.get_style_context().add_class("trackname")
        vbox.pack_start(self.track_name_label, True, True, 2)

        self.album_artist_label = MarqueeLabel("")
        self.album_artist_label.get_style_context().add_class("albumartist")
        vbox.pack_end(self.album_artist_label, True, True, 2)

        self.show_all()

        trackers.con_tracker_get().connect(self.player, "position-changed",
                                           self.on_position_changed)

        trackers.con_tracker_get().connect(self.player, "status-changed",
                                           self.on_playback_status_changed)

        trackers.con_tracker_get().connect(self.player, "metadata-changed",
                                           self.on_metadata_changed)

        self.on_playback_status_changed(self.player, player_status)
        self.on_metadata_changed(self.player)

        trackers.con_tracker_get().connect(self, "destroy",
                                           self.on_widget_destroy)

        self.update_position_timer(player_status)

    def on_previous_clicked(self, button, data=None):
        self.player.go_previous()

    def on_next_clicked(self, button, data=None):
        self.player.go_next()

    def on_play_pause_clicked(self, button, data=None):
        self.player.play_pause()

    def get_play_pause_icon_name(self, status):
        if status == PlaybackStatus.Playing:
            icon_name = "media-playback-pause-symbolic"
        else:
            icon_name = "media-playback-start-symbolic"

        return icon_name

    def position_to_time_string(self, position):
        """
        We receive track position and track length values in microseconds.
        This function formats this into readable HH:MM:SS format, and handles
        any invalid values.
        """
        delta = datetime.timedelta(microseconds=position)

        duration = datetime.datetime.utcfromtimestamp(delta.total_seconds())

        if duration.hour < 0:
            return _("--:--")

        if duration.hour < 1:
            return duration.strftime(_("%M:%S"))
        else:
            return duration.strftime(_("%H:%M:%S"))

    def on_playback_status_changed(self, player, status, data=None):
        self.update_buttons(status)
        self.update_position_timer(status)
        self.update_position_display()

        self.update_position_values_appearance(status)

    def update_position_values_appearance(self, status):
        """
        When the player is paused, we blink the position/length values.
        """
        if status == PlaybackStatus.Paused:
            self.max_pos_label.set_blinking(True)
            self.current_pos_label.set_blinking(True)
        else:
            self.max_pos_label.set_blinking(False)
            self.current_pos_label.set_blinking(False)

    def on_metadata_changed(self, player):
        """
        Update max position and labels when the player metadata changes
        """
        self.max_pos_label.set_text(
            self.position_to_time_string(self.player.get_max_position()))
        self.update_labels()

    def update_labels(self):
        """
        Construct the track and artist-album labels as well as possible.
        """
        self.track_name_label.set_text(self.player.get_track_name())

        artist_name = self.player.get_artist_name()
        album_name = self.player.get_album_name()

        if artist_name != "" and album_name != "":
            self.album_artist_label.set_text(
                "%s - %s" %
                (self.player.get_artist_name(), self.player.get_album_name()))
        elif artist_name != "":
            self.album_artist_label.set_text(artist_name)
        elif album_name != "":
            self.album_artist_label.set_text(album_name)
        else:
            self.album_artist_label.set_text("")

    def update_buttons(self, status):
        """
        Updates the player buttons based on the current state
        """
        self.play_pause_button.set_sensitive(self.player.get_can_play_pause())
        self.next_button.set_sensitive(self.player.get_can_go_next())
        self.previous_button.set_sensitive(self.player.get_can_go_previous())

        icon_name = self.get_play_pause_icon_name(status)

        size = Gtk.IconSize.from_name("audio-button")

        image = Gtk.Image.new_from_icon_name(icon_name, size)
        self.play_pause_button.set_image(image)

    def update_position_display(self):
        """
        Updates the position values and bar to reflect the current state.
        """
        if self.player.get_position() < self.player.get_max_position():
            value = self.player.get_position() / self.player.get_max_position()
        else:
            value = 1.0
        value = utils.CLAMP(value, 0.0, 1.0)
        self.position_bar.set_fraction(value)

        self.current_pos_label.set_text(
            self.position_to_time_string(self.player.get_position()))

        return True

    def update_position_timer(self, status):
        """
        Starts or stops the position update timer - this is based upon the provided rate
        property of the player, which is defined as the recommended update frequency for position
        data.
        """
        if status == PlaybackStatus.Playing:
            trackers.timer_tracker_get().start("position-timer",
                                               self.player.get_rate() * 1000,
                                               self.update_position_display)
        else:
            trackers.timer_tracker_get().cancel("position-timer")

    def on_position_changed(self, player, position, data=None):
        """
        Callback for an explicit position change from the player.
        """
        self.update_position_display()

    def on_widget_destroy(self, widget, data=None):
        trackers.con_tracker_get().disconnect(self.player, "position-changed",
                                              self.on_position_changed)

        trackers.con_tracker_get().disconnect(self.player, "status-changed",
                                              self.on_playback_status_changed)

        trackers.con_tracker_get().disconnect(self, "destroy",
                                              self.on_widget_destroy)

        trackers.timer_tracker_get().cancel("position-timer")

    def should_show(self):
        """
        Checked by the AudioPanel, whether or not this widget should be displayed.
        """
        return self.player != None
示例#5
0
class PlayerControl(Gtk.Box):
    def __init__(self):
        super(PlayerControl,
              self).__init__(orientation=Gtk.Orientation.HORIZONTAL)

        self.watcher = singletons.MediaPlayerWatcher
        self.player = self.watcher.get_best_player()

        if self.player:
            self.build_layout()

    def build_layout(self):
        size = Gtk.IconSize.from_name("audio-button")
        # size = Gtk.IconSize.MENU

        player_status = self.player.get_playback_status()

        # Player buttons

        self.pack_start(Gtk.VSeparator(), True, True, 2)

        button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        button_box.set_homogeneous(True)
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 2)
        vbox.pack_start(button_box, True, True, 0)
        vbox.set_valign(Gtk.Align.CENTER)

        self.previous_button = TransparentButton(
            "media-skip-backward-symbolic", size)
        self.previous_button.show()
        trackers.con_tracker_get().connect(self.previous_button, "clicked",
                                           self.on_previous_clicked)

        button_box.pack_start(self.previous_button, True, True, 2)

        self.play_pause_button = TransparentButton(
            self.get_play_pause_icon_name(player_status), size)
        self.play_pause_button.show()
        trackers.con_tracker_get().connect(self.play_pause_button, "clicked",
                                           self.on_play_pause_clicked)
        button_box.pack_start(self.play_pause_button, True, True, 2)

        self.next_button = TransparentButton("media-skip-forward-symbolic",
                                             size)
        self.next_button.show()
        trackers.con_tracker_get().connect(self.next_button, "clicked",
                                           self.on_next_clicked)
        button_box.pack_start(self.next_button, True, True, 2)

        self.update_buttons(player_status)

        status.focusWidgets = status.focusWidgets + [
            self.previous_button, self.play_pause_button, self.next_button
        ]

        # Position labels and bar

        self.pack_start(Gtk.VSeparator(), True, True, 2)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 4)

        vbox.set_valign(Gtk.Align.CENTER)

        position_length_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        vbox.pack_start(position_length_box, True, True, 2)

        self.current_pos_label = BlinkingLabel("", 400)
        self.current_pos_label.get_style_context().add_class("positionlabel")
        position_length_box.pack_start(self.current_pos_label, False, False, 2)

        self.max_pos_label = BlinkingLabel("", 400)
        self.max_pos_label.get_style_context().add_class("positionlabel")
        position_length_box.pack_end(self.max_pos_label, False, False, 2)

        self.position_bar = PositionBar()
        vbox.pack_end(self.position_bar, True, True, 2)

        # Track info

        self.pack_start(Gtk.VSeparator(), True, True, 2)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.pack_start(vbox, True, True, 6)

        vbox.set_valign(Gtk.Align.CENTER)

        self.track_name_label = MarqueeLabel("")
        self.track_name_label.get_style_context().add_class("trackname")
        vbox.pack_start(self.track_name_label, True, True, 2)

        self.album_artist_label = MarqueeLabel("")
        self.album_artist_label.get_style_context().add_class("albumartist")
        vbox.pack_end(self.album_artist_label, True, True, 2)

        self.show_all()

        trackers.con_tracker_get().connect(self.player, "position-changed",
                                           self.on_position_changed)

        trackers.con_tracker_get().connect(self.player, "status-changed",
                                           self.on_playback_status_changed)

        trackers.con_tracker_get().connect(self.player, "metadata-changed",
                                           self.on_metadata_changed)

        self.on_playback_status_changed(self.player, player_status)
        self.on_metadata_changed(self.player)

        trackers.con_tracker_get().connect(self, "destroy",
                                           self.on_widget_destroy)

        self.update_position_timer(player_status)

    def on_previous_clicked(self, button, data=None):
        self.player.go_previous()

    def on_next_clicked(self, button, data=None):
        self.player.go_next()

    def on_play_pause_clicked(self, button, data=None):
        self.player.play_pause()

    def get_play_pause_icon_name(self, status):
        if status == PlaybackStatus.Playing:
            icon_name = "media-playback-pause-symbolic"
        else:
            icon_name = "media-playback-start-symbolic"

        return icon_name

    def position_to_time_string(self, position):
        delta = datetime.timedelta(microseconds=position)

        duration = datetime.datetime.utcfromtimestamp(delta.total_seconds())

        if duration.hour < 0:
            return _("--:--")

        if duration.hour < 1:
            return duration.strftime(_("%M:%S"))
        else:
            return duration.strftime(_("%H:%M:%S"))

    def on_playback_status_changed(self, player, status, data=None):
        self.update_buttons(status)
        self.update_position_timer(status)
        self.update_position_display()

        self.update_position_values_appearance(status)

    def update_position_values_appearance(self, status):
        if status == PlaybackStatus.Paused:
            self.max_pos_label.set_blinking(True)
            self.current_pos_label.set_blinking(True)
        else:
            self.max_pos_label.set_blinking(False)
            self.current_pos_label.set_blinking(False)

    def on_metadata_changed(self, player):
        self.max_pos_label.set_text(
            self.position_to_time_string(self.player.get_max_position()))
        self.update_labels()

    def update_labels(self):
        self.track_name_label.set_text(self.player.get_track_name())

        artist_name = self.player.get_artist_name()
        album_name = self.player.get_album_name()

        if artist_name != "" and album_name != "":
            self.album_artist_label.set_text(
                "%s - %s" %
                (self.player.get_artist_name(), self.player.get_album_name()))
        elif artist_name != "":
            self.album_artist_label.set_text(artist_name)
        elif album_name != "":
            self.album_artist_label.set_text(album_name)
        else:
            self.album_artist_label.set_text("")

    def pause_blink_step(self):
        self.max_pos_label.set_visible(not self.max_pos_label.get_visible())
        self.current_pos_label.set_visible(
            not self.current_pos_label.get_visible())

        return True

    def update_buttons(self, status):
        self.play_pause_button.set_sensitive(self.player.get_can_play_pause())
        self.next_button.set_sensitive(self.player.get_can_go_next())
        self.previous_button.set_sensitive(self.player.get_can_go_previous())

        icon_name = self.get_play_pause_icon_name(status)

        size = Gtk.IconSize.from_name("audio-button")

        image = Gtk.Image.new_from_icon_name(icon_name, size)
        self.play_pause_button.set_image(image)

    def update_position_display(self):
        if self.player.get_position() < self.player.get_max_position():
            value = self.player.get_position() / self.player.get_max_position()
        else:
            value = 1.0
        value = utils.CLAMP(value, 0.0, 1.0)
        self.position_bar.set_fraction(value)

        self.current_pos_label.set_text(
            self.position_to_time_string(self.player.get_position()))

        return True

    def update_position_timer(self, status):
        if status == PlaybackStatus.Playing:
            trackers.timer_tracker_get().start("position-timer",
                                               self.player.get_rate() * 1000,
                                               self.update_position_display)
        else:
            trackers.timer_tracker_get().cancel("position-timer")

    def on_position_changed(self, player, position, data=None):
        self.update_position_display()

    def on_widget_destroy(self, widget, data=None):
        trackers.con_tracker_get().disconnect(self.player, "position-changed",
                                              self.on_position_changed)

        trackers.con_tracker_get().disconnect(self.player, "status-changed",
                                              self.on_playback_status_changed)

        trackers.con_tracker_get().disconnect(self, "destroy",
                                              self.on_widget_destroy)

        trackers.timer_tracker_get().cancel("position-timer")

    def should_show(self):
        return self.player != None