def _add_item(self, source, param, item, remaining=0, data=None): if not item: if remaining == 0: self.view.set_model(self.model) self.window.pop_loading_notification() self.view.show() return self._offset += 1 artist = utils.get_artist_name(item) title = utils.get_media_title(item) _iter = self.model.append(None) loading_icon = Gdk.pixbuf_get_from_surface( self._loadin_icon_surface, 0, 0, self._loading_icon_surface.get_width(), self._loading_icon_surface.get_height()) self.model[_iter][0, 1, 2, 3, 4, 5, 7, 9] = [ str(item.get_id()), '', title, artist, loading_icon, item, 0, False ] self.cache.lookup(item, self._iconWidth, self._iconHeight, self._on_lookup_ready, _iter)
def _get_active_playlist(self): playlist = self._get_playlist_from_id(self.player.playlistId) \ if self.player.playlistType == 'Playlist' else None playlistName = utils.get_media_title(playlist) \ if playlist else '' return (playlist is not None, (self._get_playlist_path(playlist), playlistName, ''))
def _add_playlist_to_sidebar(self, playlist, index=None): """Add a playlist to sidebar :param GrlMedia playlist: playlist to add :param int index: position """ if index is None: index = -1 if playlists.is_static_playlist(playlist): index = 0 title = utils.get_media_title(playlist) row = Gtk.ListBoxRow() row.playlist = playlist label = Gtk.Label(label=title, xalign=0, xpad=16, ypad=16, ellipsize=Pango.EllipsizeMode.END) row.add(label) row.show_all() self._sidebar.insert(row, index) self._offset += 1 if len(self._sidebar) == 1: self._sidebar.select_row(row) self._sidebar.emit('row-activated', row)
def _create_song_widget(self, song): """Helper function to create a song widget for a single song :param song: A Grilo media item :returns: A complete song widget :rtype: Gtk.EventBox """ song_widget = SongWidget(song) self._songs.append(song_widget) title = utils.get_media_title(song) itr = self._model.append(None) self._model[itr][0, 1, 2, 5, 6] = [title, '', '', song, False] song_widget.itr = itr song_widget.model = self._model song_widget.connect('button-release-event', self._song_activated) song_widget.connect('selection-changed', self._on_selection_changed) self.bind_property('selection-mode', song_widget, 'selection-mode', GObject.BindingFlags.SYNC_CREATE) self.bind_property('show-durations', song_widget, 'show-duration', GObject.BindingFlags.SYNC_CREATE) self.bind_property('show-favorites', song_widget, 'show-favorite', GObject.BindingFlags.SYNC_CREATE) self.bind_property('show-song-numbers', song_widget, 'show-song-number', GObject.BindingFlags.SYNC_CREATE) return song_widget
def _on_playlist_activated(self, sidebar, row, data=None): """Update view with content from selected playlist""" playlist = row.playlist playlist_name = utils.get_media_title(playlist) if self.rename_active: self.disable_rename_playlist() self._current_playlist = playlist self._name_label.set_text(playlist_name) self._current_playlist_index = row.get_index() # if the active queue has been set by this playlist, # use it as model, otherwise build the liststore self._view.set_model(None) self.model.clear() self._iter_to_clean = None self._iter_to_clean_model = None self._songs_count = 0 grilo.populate_playlist_songs(playlist, self._add_song) if self._current_playlist_is_protected(): self._playlist_delete_action.set_enabled(False) self._playlist_rename_action.set_enabled(False) self._remove_song_action.set_enabled(False) self._view.set_reorderable(False) else: self._playlist_delete_action.set_enabled(True) self._playlist_rename_action.set_enabled(True) self._remove_song_action.set_enabled(True) self._view.set_reorderable(True)
def load(self, media): self._progress_scale_zero() self._set_duration(media.get_duration()) self.songTotalTimeLabel.set_label( utils.seconds_to_string(media.get_duration())) self.progressScale.set_sensitive(True) self.playBtn.set_sensitive(True) self._sync_prev_next() artist = utils.get_artist_name(media) self.artistLabel.set_label(artist) self._currentArtist = artist self.coverImg.set_from_surface(self._loading_icon_surface) self.cache.lookup(media, ArtSize.xsmall, self._on_cache_lookup, None) self._currentTitle = utils.get_media_title(media) self.titleLabel.set_label(self._currentTitle) self._currentTimestamp = int(time.time()) url = media.get_url() if url != self.player.get_value('current-uri', 0): self.player.set_property('uri', url) if self.currentTrack and self.currentTrack.valid(): currentTrack = self.playlist.get_iter(self.currentTrack.get_path()) self.emit('playlist-item-changed', self.playlist, currentTrack) self.emit('current-changed') self._validate_next_track()
def _add_item(self, source, param, item, remaining=0, data=None): self.window.notification.set_timeout(0) if not item: if remaining == 0: self.view.set_model(self.model) self.window.notification.dismiss() self.view.show() return self._offset += 1 artist = utils.get_artist_name(item) title = utils.get_media_title(item) _iter = self.model.append(None) loading_icon = Gdk.pixbuf_get_from_surface( self._loadin_icon_surface, 0, 0, self._loading_icon_surface.get_width(), self._loading_icon_surface.get_height()) self.model[_iter][0, 1, 2, 3, 4, 5, 7, 9] = [ str(item.get_id()), '', title, artist, loading_icon, item, 0, False ] self.cache.lookup(item, self._iconWidth, self._iconHeight, self._on_lookup_ready, _iter)
def _now_playing(self, media): """Internal method called by self.now_playing""" api_key = self._authentication.props.client_id sk = self._authentication.call_get_access_token_sync(None)[0] secret = self._authentication.props.client_secret artist = utils.get_artist_name(media) title = utils.get_media_title(media) sig = ("api_key{}artist{}methodtrack.updateNowPlayingsk{}track" "{}{}").format(api_key, artist, sk, title, secret) api_sig = md5(sig.encode()).hexdigest() request_dict = { "api_key": api_key, "method": "track.updateNowPlaying", "artist": artist, "track": title, "sk": sk, "api_sig": api_sig } try: r = requests.post("https://ws.audioscrobbler.com/2.0/", request_dict) if r.status_code != 200: logger.warn("Failed to update currently played track: %s %s" % (r.status_code, r.reason)) logger.warn(r.text) except Exception as e: logger.warn(e)
def _add_playlist_to_sidebar(self, playlist, index=None, select_playlist=False): """Add a playlist to sidebar :param GrlMedia playlist: playlist to add :param int index: position """ if index is None: index = -1 if playlists.is_smart_playlist(playlist): index = 0 title = utils.get_media_title(playlist) row = SidebarRow() row.props.text = title # FIXME: Passing the Grl.Media with the row object is ugly. row.playlist = playlist self._sidebar.insert(row, index) self._offset += 1 if select_playlist: self._sidebar.select_row(row) row.emit('activate')
def __init__(self, media=None, query=None, tag_text=None, source=None, coremodel=None, coreselection=None, grilo=None, tracker=None): super().__init__() if media: self.props.pl_id = media.get_id() self.props.title = utils.get_media_title(media) self.props.count = media.get_childcount() self.props.creation_date = media.get_creation_date() self.props.query = query self.props.tag_text = tag_text self._model = None self._source = source self._coremodel = coremodel self._coreselection = coreselection self._grilo = grilo self._tracker = tracker self._fast_options = Grl.OperationOptions() self._fast_options.set_resolution_flags( Grl.ResolutionFlags.FAST_ONLY | Grl.ResolutionFlags.IDLE_RELAY) self._songs_todelete = []
def _on_playlist_activated(self, sidebar, row, data=None): """Update view with content from selected playlist""" playlist = row.playlist playlist_name = utils.get_media_title(playlist) if self.rename_active: self._pl_ctrls.disable_rename_playlist() self._current_playlist = playlist self._pl_ctrls.props.playlist_name = playlist_name self._current_playlist_index = row.get_index() # if the active queue has been set by this playlist, # use it as model, otherwise build the liststore self._view.set_model(None) self.model.clear() self._iter_to_clean = None self._iter_to_clean_model = None self._update_songs_count(0) self._pl_ctrls.props.display_songs_count = False grilo.populate_playlist_songs(playlist, self._add_song) protected_pl = playlists.is_smart_playlist(self._current_playlist) self._playlist_delete_action.set_enabled(not protected_pl) self._playlist_rename_action.set_enabled(not protected_pl) self._remove_song_action.set_enabled(not protected_pl) self._view.set_reorderable(not protected_pl)
def load(self, media): self._progress_scale_zero() self._set_duration(media.get_duration()) self.songTotalTimeLabel.set_label( utils.seconds_to_string(media.get_duration())) self.progressScale.set_sensitive(True) self.playBtn.set_sensitive(True) self._sync_prev_next() artist = utils.get_artist_name(media) self.artistLabel.set_label(artist) self.coverImg.set_from_surface(self._loading_icon_surface) self.cache.lookup(media, ArtSize.XSMALL, self._on_cache_lookup, None) title = utils.get_media_title(media) self.titleLabel.set_label(title) self._time_stamp = int(time.time()) url = media.get_url() if url != self.player.get_value('current-uri', 0): self.player.set_property('uri', url) if self.currentTrack and self.currentTrack.valid(): currentTrack = self.playlist.get_iter(self.currentTrack.get_path()) self.emit('playlist-item-changed', self.playlist, currentTrack) self.emit('current-changed') self._validate_next_track()
def _update_model(self, player, playlist, current_iter): """Player changed callback. :param player: The player object :param playlist: The current playlist :param current_iter: The current iter of the playlist model """ # self is not our playlist, return if (playlist != self.model): return False current_song = playlist[current_iter][5] song_passed = False _iter = playlist.get_iter_first() self._duration = 0 while _iter: song = playlist[_iter][5] self._duration += song.get_duration() escaped_title = GLib.markup_escape_text( utils.get_media_title(song)) if (song == current_song): title = '<b>%s</b>' % escaped_title song_passed = True elif (song_passed): title = '<span>%s</span>' % escaped_title else: title = '<span color=\'grey\'>%s</span>' % escaped_title playlist[_iter][0] = title _iter = playlist.iter_next(_iter) self._ui.get_object('running_length_label_info').set_text( _("%d min") % (int(self._duration / 60) + 1)) return False
def _create_song_widget(self, track): """Helper function to create a song widget for a single song :param track: A Grilo media item :returns: A complete song widget :rtype: Gtk.EventBox """ builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Music/TrackWidget.ui') song_widget = builder.get_object('eventbox1') self._songs.append(song_widget) title = utils.get_media_title(track) itr = self._model.append(None) self._model[itr][0, 1, 2, 5, 6] = [title, '', '', track, False] song_widget.itr = itr song_widget.model = self._model track_number = track.get_track_number() if track_number == 0: track_number = "" song_widget.number = builder.get_object('num') song_widget.number.set_markup( '<span color=\'grey\'>{}</span>'.format(track_number)) song_widget.number.set_no_show_all(True) song_widget.title = builder.get_object('title') song_widget.title.set_text(title) song_widget.title.set_max_width_chars(50) song_widget.duration = builder.get_object('duration') time = utils.seconds_to_string(track.get_duration()) song_widget.duration.set_text(time) song_widget.check_button = builder.get_object('select') song_widget.check_button.set_visible(False) song_widget.check_button.connect('toggled', self._check_button_toggled, song_widget) song_widget.now_playing_sign = builder.get_object('image1') song_widget.now_playing_sign.set_from_icon_name( NOW_PLAYING_ICON_NAME, Gtk.IconSize.SMALL_TOOLBAR) song_widget.now_playing_sign.set_no_show_all(True) song_widget.can_be_played = True song_widget.connect('button-release-event', self._track_activated) song_widget.star_stack = builder.get_object('starstack') song_widget.star_stack.set_favorite(track.get_lyrics()) song_widget.star_stack.set_visible(True) song_widget.starevent = builder.get_object('starevent') song_widget.starevent.connect('button-release-event', self._toggle_favorite, song_widget) return song_widget
def __init__(self, media): """Initialize the AlbumCover :param Grl.Media media: The media object to use """ super().__init__() AlbumCover._nr_albums += 1 self._media = media self._tooltip = TwoLineTip() artist = utils.get_artist_name(media) title = utils.get_media_title(media) self._tooltip.props.title = utils.get_artist_name(media) self._tooltip.props.subtitle = utils.get_media_title(media) self._artist_label.props.label = artist self._title_label.props.label = title self.bind_property( 'selected', self._check, 'active', GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE) self.bind_property('selection-mode', self._check, 'visible', GObject.BindingFlags.BIDIRECTIONAL) self.connect('query-tooltip', self._on_tooltip_query) self._events.add_events(Gdk.EventMask.TOUCH_MASK) self._cover_stack.props.size = Art.Size.MEDIUM self.show() # FIXME: To work around slow updating of the albumsview, # load album covers with a fixed delay. This results in a # quick first show with a placeholder cover and then a # reasonably responsive view while loading the actual # covers. GLib.timeout_add(50 * self._nr_albums, self._cover_stack.update, media, priority=GLib.PRIORITY_LOW)
def GetPlaylists(self, index, max_count, order, reverse): if order != 'Alphabetical': return [] playlists = [(self._get_playlist_path(playlist), utils.get_media_title(playlist) or '', '') for playlist in self.playlists] return playlists[index:index + max_count] if not reverse \ else playlists[index + max_count - 1:index - 1 if index - 1 >= 0 else None:-1]
def enable_rename_playlist(self, pl_torename): """Enables rename button and entry :param Grl.Media pl_torename : The playlist to rename """ self._name_stack.props.visible_child_name = "renaming_dialog" self._set_rename_entry_text_and_focus( utils.get_media_title(pl_torename))
def __init__(self, media): """Initialize the AlbumCover :param Grl.Media media: The media object to use """ super().__init__() AlbumCover._nr_albums += 1 self._media = media self._tooltip = TwoLineTip() artist = utils.get_artist_name(media) title = utils.get_media_title(media) self._tooltip.props.title = utils.get_artist_name(media) self._tooltip.props.subtitle = utils.get_media_title(media) self._artist_label.props.label = artist self._title_label.props.label = title self.bind_property( 'selected', self._check, 'active', GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE) self.bind_property( 'selection-mode', self._check, 'visible', GObject.BindingFlags.BIDIRECTIONAL) self.connect('query-tooltip', self._on_tooltip_query) self._events.add_events(Gdk.EventMask.TOUCH_MASK) self._cover_stack.props.size = Art.Size.MEDIUM self.show() # FIXME: To work around slow updating of the albumsview, # load album covers with a fixed delay. This results in a # quick first show with a placeholder cover and then a # reasonably responsive view while loading the actual # covers. GLib.timeout_add( 50 * self._nr_albums, self._cover_stack.update, media, priority=GLib.PRIORITY_LOW)
def GetPlaylists(self, index, max_count, order, reverse): if order != 'Alphabetical': return [] playlists = [(self._get_playlist_dbus_path(playlist), utils.get_media_title(playlist) or '', '') for playlist in self.playlists] return playlists[index:index + max_count] if not reverse \ else playlists[index + max_count - 1:index - 1 if index - 1 >= 0 else None:-1]
def _add_item(self, source, param, item, remaining=0, data=None): self.window.notification.set_timeout(0) if not item: if remaining == 0: self.view.set_model(self.model) self.window.notification.dismiss() self.view.show() return self._offset += 1 item.set_title(utils.get_media_title(item)) artist = utils.get_artist_name(item) if item.get_url() is None: return self.model.insert_with_valuesv(-1, [2, 3, 5, 9], [ utils.get_media_title(item), artist, item, bool(item.get_lyrics()) ])
def _add_item(self, source, param, item, remaining=0, data=None): """Adds track item to the model""" if not item and not remaining: self._view.set_model(self.model) self._window.notifications_popup.pop_loading() self._view.show() return self._offset += 1 item.set_title(utils.get_media_title(item)) artist = utils.get_artist_name(item) if not item.get_url(): return self.model.insert_with_valuesv( -1, [2, 3, 5, 9], [utils.get_media_title(item), artist, item, item.get_favourite()])
def _get_active_playlist(self): playlist = None playlist_name = '' if self.player.get_playlist_type() == PlayerPlaylist.Type.PLAYLIST: playlist = self._get_playlist_from_id( self.player.get_playlist_id()) playlist_name = utils.get_media_title(playlist) path = self._get_playlist_path(playlist) return (playlist is not None, (path, playlist_name, ''))
def update(self, media): """Update the CoreAlbum object with new info :param Grl.Media media: A media object """ self.props.media = media self.props.artist = utils.get_artist_name(media) self.props.composer = media.get_composer() self.props.title = utils.get_media_title(media) self.props.year = utils.get_media_year(media)
def update(self, media): self.props.media = media self.props.album = utils.get_album_title(media) self.props.album_disc_number = media.get_album_disc_number() self.props.artist = utils.get_artist_name(media) self.props.duration = media.get_duration() self.props.favorite = media.get_favourite() self.props.play_count = media.get_play_count() self.props.title = utils.get_media_title(media) self.props.track_number = media.get_track_number() self.props.url = media.get_url()
def clean_model(self): itr = self._model.get_iter_first() while itr: song = self._model.get_value(itr, 5) song_widget = song.song_widget escaped_title = GLib.markup_escape_text(utils.get_media_title(song)) if song_widget.can_be_played: song_widget.now_playing_sign.hide() song_widget.title.set_markup('<span>%s</span>' % escaped_title) itr = self._model.iter_next(itr) return False
def _update_view(self, player, playlist, current_iter): media = playlist[current_iter][player.Field.SONG] self._duration_label.set_label( utils.seconds_to_string(media.get_duration())) self._play_button.set_sensitive(True) self._sync_prev_next() self._artist_label.set_label(utils.get_artist_name(media)) self._title_label.set_label(utils.get_media_title(media)) self._cover_stack.update(media)
def clean_model(self): itr = self._model.get_iter_first() while itr: song = self._model.get_value(itr, 5) song_widget = song.song_widget escaped_title = GLib.markup_escape_text( utils.get_media_title(song)) if song_widget.can_be_played: song_widget.now_playing_sign.hide() song_widget.title.set_markup('<span>%s</span>' % escaped_title) itr = self._model.iter_next(itr) return False
def _add_item_to_model(self, item): """Adds (non-static only) playlists to the model""" # Hide playlists that are going to be deleted if item.get_id() in self._playlists_todelete_ids: return None self._user_playlists_available = True new_iter = self._model.insert_with_valuesv( -1, [0, 1], [utils.get_media_title(item), item]) return new_iter
def _add_item(self, source, param, item, remaining=0, data=None): """Adds track item to the model""" if not item and not remaining: self.view.set_model(self.model) self.window.pop_loading_notification() self.view.show() return self._offset += 1 item.set_title(utils.get_media_title(item)) artist = utils.get_artist_name(item) if not item.get_url(): return self.model.insert_with_valuesv(-1, [2, 3, 5, 9], [ utils.get_media_title(item), artist, item, item.get_favourite() ])
def _get_removal_notification_message(self, type_, media_id): """ Returns a label for the playlist notification popup Handles two cases: - playlist removal - songs from playlist removal """ msg = "" if type_ == PlaylistNotification.Type.PLAYLIST: pl_todelete = self.pls_todelete[media_id] playlist_title = utils.get_media_title(pl_todelete['playlist']) msg = _("Playlist {} removed".format(playlist_title)) else: song_todelete = self._songs_todelete[media_id] playlist_title = utils.get_media_title(song_todelete['playlist']) song_title = utils.get_media_title(song_todelete['song']) msg = _("{} removed from {}".format(song_title, playlist_title)) return msg
def _lastfm_api_call(self, media, time_stamp, request_type_key): """Internal method called by self.scrobble""" api_key = self._goa_lastfm.client_id sk = self._goa_lastfm.session_key secret = self._goa_lastfm.secret artist = utils.get_artist_name(media) title = utils.get_media_title(media) request_type = { "update now playing": "track.updateNowPlaying", "scrobble": "track.scrobble" } # The album is optional. So only provide it when it is # available. album = media.get_album() request_dict = {} if album: request_dict.update({ "album": album }) if time_stamp is not None: request_dict.update({ "timestamp": str(time_stamp) }) request_dict.update({ "api_key": api_key, "method": request_type[request_type_key], "artist": artist, "track": title, "sk": sk, }) sig = "" for key in sorted(request_dict): sig += key + request_dict[key] sig += secret api_sig = md5(sig.encode()).hexdigest() request_dict.update({ "api_sig": api_sig }) msg = Soup.form_request_new_from_hash( "POST", "https://ws.audioscrobbler.com/2.0/", request_dict) self._soup_session.queue_message( msg, self._lastfm_api_callback, request_type_key)
def _get_metadata(self, media=None, index=None): song_dbus_path = self._get_song_dbus_path(media, index) if not self.player.props.current_song: return {'mpris:trackid': GLib.Variant('o', song_dbus_path)} if not media: media = self.player.props.current_song length = media.get_duration() * 1e6 user_rating = 1.0 if media.get_favourite() else 0.0 artist = utils.get_artist_name(media) metadata = { 'mpris:trackid': GLib.Variant('o', song_dbus_path), 'xesam:url': GLib.Variant('s', media.get_url()), 'mpris:length': GLib.Variant('x', length), 'xesam:trackNumber': GLib.Variant('i', media.get_track_number()), 'xesam:useCount': GLib.Variant('i', media.get_play_count()), 'xesam:userRating': GLib.Variant('d', user_rating), 'xesam:title': GLib.Variant('s', utils.get_media_title(media)), 'xesam:album': GLib.Variant('s', utils.get_album_title(media)), 'xesam:artist': GLib.Variant('as', [artist]), 'xesam:albumArtist': GLib.Variant('as', [artist]) } genre = media.get_genre() if genre is not None: metadata['xesam:genre'] = GLib.Variant('as', [genre]) last_played = media.get_last_played() if last_played is not None: last_played_str = last_played.format("%FT%T%:z") metadata['xesam:lastUsed'] = GLib.Variant('s', last_played_str) # If the media has already been part of an MPRIS playlist, its # thumbnail is already set. Otherwise, try to look for it in the # cache directory and set the media thumbnail for a future use. # The search is only through the cache to prevent any delayed # loading. # FIXME: The thumbnail retrieval should take place in the # player. art_url = media.get_thumbnail() if not art_url: thumb_file = lookup_art_file_from_cache(media) if thumb_file: art_url = GLib.filename_to_uri(thumb_file.get_path()) media.set_thumbnail(art_url) if art_url: metadata['mpris:artUrl'] = GLib.Variant('s', art_url) return metadata
def _get_removal_notification_message(self, type_, media_id): """ Returns a label for the playlist notification popup Handles two cases: - playlist removal - songs from playlist removal """ msg = "" if type_ == PlaylistNotification.Type.PLAYLIST: pl_todelete = self.pls_todelete[media_id] playlist_title = utils.get_media_title(pl_todelete['playlist']) msg = _("Playlist {} removed".format(playlist_title)) else: song_todelete = self._songs_todelete[media_id] playlist_title = utils.get_media_title(song_todelete['playlist']) song_title = utils.get_media_title(song_todelete['song']) msg = _("{} removed from {}".format( song_title, playlist_title)) return msg
def __init__(self, playlist): """Create a row of the PlaylistDialog :param Grl.Media playlist: the associated playlist """ super().__init__() self.props.playlist = playlist self._label.props.label = utils.get_media_title(playlist) self.bind_property( "selected", self._selection_icon, "visible", GObject.BindingFlags.SYNC_CREATE)
def _lastfm_api_call(self, media, time_stamp, request_type_key): """Internal method called by self.scrobble""" api_key = self._goa_lastfm.client_id sk = self._goa_lastfm.session_key secret = self._goa_lastfm.secret artist = utils.get_artist_name(media) title = utils.get_media_title(media) request_type = { "update now playing": "track.updateNowPlaying", "scrobble": "track.scrobble" } # The album is optional. So only provide it when it is # available. album = media.get_album() request_dict = {} if album: request_dict.update({"album": album}) if time_stamp is not None: request_dict.update({"timestamp": time_stamp}) request_dict.update({ "api_key": api_key, "method": request_type[request_type_key], "artist": artist, "track": title, "sk": sk, }) sig = "" for key in sorted(request_dict): sig += key + str(request_dict[key]) sig += secret api_sig = md5(sig.encode()).hexdigest() request_dict.update({"api_sig": api_sig}) try: r = requests.post("https://ws.audioscrobbler.com/2.0/", request_dict) if r.status_code != 200: logger.warning("Failed to {} track: {} {}".format( request_type_key, r.status_code, r.reason)) logger.warning(r.text) except Exception as e: logger.warning(e)
def _add_item_to_model(self, item): """Adds (non-static only) playlists to the model""" # Don't show static playlists if self.playlist.is_static_playlist(item): return None new_iter = self.model.append() self.model.set( new_iter, [0, 1, 2], [utils.get_media_title(item), False, item] ) return new_iter
def _add_item_to_model(self, item, model): if not item: self._update_songs_count() if self.player.playlist: self.player._validate_next_track() self.emit('playlist-songs-loaded') return self._offset += 1 title = utils.get_media_title(item) item.set_title(title) artist = item.get_artist() or _("Unknown Artist") model.insert_with_valuesv( -1, [2, 3, 5, 9], [title, artist, item, bool(item.get_lyrics())]) self.songs_count += 1
def _add_item_to_model(self, item): """Adds (non-static only) playlists to the model""" # Don't show static playlists if self._playlist.is_static_playlist(item): return None # Hide playlists that are going to be deleted if item.get_id() in self._playlists_todelete_ids: return None new_iter = self._model.insert_with_valuesv( -1, [0, 1], [utils.get_media_title(item), item]) return new_iter
def _add_item_to_model(self, item, model): if not item: self._update_songs_count() if self.player.playlist: self.player._validate_next_track() self.emit('playlist-songs-loaded') return self._offset += 1 title = utils.get_media_title(item) item.set_title(title) artist = utils.get_album_title(item) model.insert_with_valuesv( -1, [2, 3, 5, 9], [title, artist, item, item.get_favourite()]) self.songs_count += 1
def _on_item_activated(self, widget, id, path): if self.star_handler.star_renderer_click: self.star_handler.star_renderer_click = False return try: child_path = self.filter_model.convert_path_to_child_path(path) except TypeError: return _iter = self.model.get_iter(child_path) if self.model[_iter][11] == 'album': title = self.model.get_value(_iter, 2) artist = self.model.get_value(_iter, 3) item = self.model.get_value(_iter, 5) self._albumWidget.update(artist, title, item, self.header_bar, self.selection_toolbar) self.header_bar.set_state(ToolbarState.SEARCH_VIEW) title = utils.get_media_title(item) self.header_bar.header_bar.set_title(title) self.header_bar.header_bar.sub_title = artist self.set_visible_child(self._albumWidget) self.header_bar.searchbar.show_bar(False) elif self.model[_iter][11] == 'artist': artist = self.model.get_value(_iter, 2) albums = self._artists[artist.casefold()]['albums'] self._artistAlbumsWidget = ArtistAlbumsWidget( artist, albums, self.player, self.header_bar, self.selection_toolbar, self.window, True ) self.add(self._artistAlbumsWidget) self._artistAlbumsWidget.show() self.header_bar.set_state(ToolbarState.SEARCH_VIEW) self.header_bar.header_bar.set_title(artist) self.set_visible_child(self._artistAlbumsWidget) self.header_bar.searchbar.show_bar(False) elif self.model[_iter][11] == 'song': if self.model.get_value(_iter, 12) != DiscoveryStatus.FAILED: child_iter = self.songs_model.convert_child_iter_to_iter(_iter)[1] self.player.set_playlist('Search Results', None, self.songs_model, child_iter, 5, 12) self.player.set_playing(True) else: # Headers if self.view.get_generic_view().row_expanded(path): self.view.get_generic_view().collapse_row(path) else: self.view.get_generic_view().expand_row(path, False)
def _add_playlist_item_to_model(self, item, index=None): if index is None: index = -1 if not item: self.window.pop_loading_notification() self.emit('playlists-loaded') return _iter = self.playlists_model.insert_with_valuesv( index, [2, 5], [utils.get_media_title(item), item]) if self.playlists_model.iter_n_children(None) == 1: _iter = self.playlists_model.get_iter_first() selection = self.playlists_sidebar.get_generic_view().get_selection() selection.select_iter(_iter) self.playlists_sidebar.emit('item-activated', '0', self.playlists_model.get_path(_iter))
def _add_song_to_model(self, song, model, index=-1): """Add song to a playlist :param Grl.Media song: song to add :param Gtk.ListStore model: model """ if not song: return None title = utils.get_media_title(song) song.set_title(title) artist = utils.get_artist_name(song) iter_ = model.insert_with_valuesv( index, [2, 3, 5, 9], [title, artist, song, song.get_favourite()]) self._update_songs_count(self._songs_count + 1) return iter_
def _get_active_playlist(self): """Get Active Maybe_Playlist Maybe_Playlist is a structure describing a playlist, or nothing according to MPRIS specifications. If a playlist is active, return True and its description (path, name and icon). If no playlist is active, return False and an undefined structure. :returns: playlist existence and its structure :rtype: tuple """ if self.player.get_playlist_type() != PlayerPlaylist.Type.PLAYLIST: return (False, ("/", "", "")) playlist = self._get_playlist_from_id(self.player.get_playlist_id()) playlist_name = utils.get_media_title(playlist) path = self._get_playlist_dbus_path(playlist) return (True, (path, playlist_name, ""))
def _get_metadata(self, media=None, index=None): song_dbus_path = self._get_song_dbus_path(media, index) if not self.player.props.current_song: return { 'mpris:trackid': GLib.Variant('o', song_dbus_path) } if not media: media = self.player.props.current_song length = media.get_duration() * 1e6 user_rating = 1.0 if media.get_favourite() else 0.0 artist = utils.get_artist_name(media) metadata = { 'mpris:trackid': GLib.Variant('o', song_dbus_path), 'xesam:url': GLib.Variant('s', media.get_url()), 'mpris:length': GLib.Variant('x', length), 'xesam:trackNumber': GLib.Variant('i', media.get_track_number()), 'xesam:useCount': GLib.Variant('i', media.get_play_count()), 'xesam:userRating': GLib.Variant('d', user_rating), 'xesam:title': GLib.Variant('s', utils.get_media_title(media)), 'xesam:album': GLib.Variant('s', utils.get_album_title(media)), 'xesam:artist': GLib.Variant('as', [artist]), 'xesam:albumArtist': GLib.Variant('as', [artist]) } genre = media.get_genre() if genre is not None: metadata['xesam:genre'] = GLib.Variant('as', [genre]) last_played = media.get_last_played() if last_played is not None: last_played_str = last_played.format("%FT%T%:z") metadata['xesam:lastUsed'] = GLib.Variant('s', last_played_str) art_url = media.get_thumbnail() if art_url is not None: metadata['mpris:artUrl'] = GLib.Variant('s', art_url) return metadata
def _update_view(self, player): """Updates model when the song changes :param Player player: The main player object """ current_song = player.props.current_song self._duration_label.set_label( utils.seconds_to_string(current_song.get_duration())) self._play_button.set_sensitive(True) self._sync_prev_next() artist = utils.get_artist_name(current_song) title = utils.get_media_title(current_song) self._title_label.props.label = title self._artist_label.props.label = artist self._tooltip.props.title = title self._tooltip.props.subtitle = artist self._cover_stack.update(current_song)
def _on_child_activated(self, widget, child, user_data=None): item = child.media_item if self.star_handler.star_renderer_click: self.star_handler.star_renderer_click = False return # Toggle the selection when in selection mode if self.selection_mode: child.check.set_active(not child.check.get_active()) return title = utils.get_media_title(item) self._escaped_title = title self._artist = utils.get_artist_name(item) self._albumWidget.update(self._artist, title, item, self.header_bar, self.selection_toolbar) self.header_bar.set_state(ToolbarState.CHILD_VIEW) self.header_bar.header_bar.set_title(self._escaped_title) self.header_bar.header_bar.sub_title = self._artist self.set_visible_child(self._albumWidget)
def _update_model(self, player, playlist, current_iter): """Player changed callback. :param player: The player object :param playlist: The current playlist :param current_iter: The current iter of the playlist model """ if playlist != self._model: return True current_song = playlist[current_iter][5] self._duration = 0 song_passed = False _iter = playlist.get_iter_first() while _iter: song = playlist[_iter][5] song_widget = song.song_widget self._duration += song.get_duration() escaped_title = GLib.markup_escape_text(utils.get_media_title(song)) if song == current_song: song_widget.now_playing_sign.show() song_widget.title.set_markup("<b>{}</b>".format(escaped_title)) song_passed = True elif song_passed: song_widget.now_playing_sign.hide() song_widget.title.set_markup("<span>{}</span>".format(escaped_title)) else: song_widget.now_playing_sign.hide() song_widget.title.set_markup("<span color='grey'>{}</span>".format(escaped_title)) _iter = playlist.iter_next(_iter) self._builder.get_object("running_length_label_info").set_text(_("%d min") % (int(self._duration / 60) + 1)) return True
def _add_playlist_to_sidebar( self, playlist, index=None, select_playlist=False): """Add a playlist to sidebar :param GrlMedia playlist: playlist to add :param int index: position """ if index is None: index = -1 if playlists.is_smart_playlist(playlist): index = 0 title = utils.get_media_title(playlist) row = SidebarRow() row.props.text = title # FIXME: Passing the Grl.Media with the row object is ugly. row.playlist = playlist self._sidebar.insert(row, index) self._offset += 1 if select_playlist: self._sidebar.select_row(row) row.emit('activate')
def update_model(self, player, playlist, currentIter): # this is not our playlist, return if playlist != self._model: # TODO, only clean once, but that can wait util we have clean # the code a bit, and until the playlist refactoring. # the overhead is acceptable for now self.clean_model() return False currentSong = playlist.get_value(currentIter, 5) song_passed = False itr = playlist.get_iter_first() while itr: song = playlist.get_value(itr, 5) song_widget = song.song_widget if not song_widget.can_be_played: itr = playlist.iter_next(itr) continue escaped_title = GLib.markup_escape_text(utils.get_media_title(song)) if (song == currentSong): song_widget.now_playing_sign.show() song_widget.title.set_markup('<b>%s</b>' % escaped_title) song_passed = True elif (song_passed): song_widget.now_playing_sign.hide() song_widget.title.set_markup('<span>%s</span>' % escaped_title) else: song_widget.now_playing_sign.hide() song_widget.title.set_markup( '<span color=\'grey\'>%s</span>' % escaped_title ) itr = playlist.iter_next(itr) return False
def _create_song_widget(self, song): """Helper function to create a song widget for a single song :param song: A Grilo media item :returns: A complete song widget :rtype: Gtk.EventBox """ song_widget = SongWidget(song) self._songs.append(song_widget) title = utils.get_media_title(song) itr = self._model.append(None) self._model[itr][0, 1, 2, 5, 6] = [title, '', '', song, False] song_widget.itr = itr song_widget.model = self._model song_widget.connect('button-release-event', self._song_activated) song_widget.connect('selection-changed', self._on_selection_changed) self.bind_property( 'selection-mode', song_widget, 'selection-mode', GObject.BindingFlags.SYNC_CREATE) self.bind_property( 'show-durations', song_widget, 'show-duration', GObject.BindingFlags.SYNC_CREATE) self.bind_property( 'show-favorites', song_widget, 'show-favorite', GObject.BindingFlags.SYNC_CREATE) self.bind_property( 'show-song-numbers', song_widget, 'show-song-number', GObject.BindingFlags.SYNC_CREATE) return song_widget
def _create_album_item(self, item): artist = utils.get_artist_name(item) title = utils.get_media_title(item) builder = Gtk.Builder.new_from_resource("/org/gnome/Music/AlbumCover.ui") child = Gtk.FlowBoxChild() child.image = builder.get_object("image") child.check = builder.get_object("check") child.title = builder.get_object("title") child.subtitle = builder.get_object("subtitle") child.events = builder.get_object("events") child.media_item = item child.title.set_label(title) child.subtitle.set_label(artist) child.image.set_from_surface(self._loading_icon_surface) # In the case of off-sized icons (eg. provided in the soundfile) # keep the size request equal to all other icons to get proper # alignment with GtkFlowBox. child.image.set_property("width-request", ArtSize.medium.width) child.image.set_property("height-request", ArtSize.medium.height) child.events.connect("button-release-event", self._on_album_event_triggered, child) child.check_handler_id = child.check.connect("notify::active", self._on_child_toggled, child) child.check.bind_property("visible", self, "selection_mode", GObject.BindingFlags.BIDIRECTIONAL) child.add(builder.get_object("main_box")) child.show() self.cache.lookup(item, ArtSize.medium, self._on_lookup_ready, child) return child
def _get_metadata(self, media=None): if not media: media = self.player.get_current_media() if not media: return {} metadata = { 'mpris:trackid': GLib.Variant('o', self._get_media_id(media)), 'xesam:url': GLib.Variant('s', media.get_url()) } try: length = media.get_duration() * 1000000 assert length is not None metadata['mpris:length'] = GLib.Variant('x', length) except: pass try: trackNumber = media.get_track_number() assert trackNumber is not None metadata['xesam:trackNumber'] = GLib.Variant('i', trackNumber) except: pass try: useCount = media.get_play_count() assert useCount is not None metadata['xesam:useCount'] = GLib.Variant('i', useCount) except: pass try: userRating = media.get_rating() assert userRating is not None metadata['xesam:userRating'] = GLib.Variant('d', userRating) except: pass try: title = utils.get_media_title(media) assert title is not None metadata['xesam:title'] = GLib.Variant('s', title) except: pass album = utils.get_album_title(media) metadata['xesam:album'] = GLib.Variant('s', album) artist = utils.get_artist_name(media) metadata['xesam:artist'] = GLib.Variant('as', [artist]) metadata['xesam:albumArtist'] = GLib.Variant('as', [artist]) try: genre = media.get_genre() assert genre is not None metadata['xesam:genre'] = GLib.Variant('as', genre) except: pass try: lastUsed = media.get_last_played() assert lastUsed is not None metadata['xesam:lastUsed'] = GLib.Variant('s', lastUsed) except: pass try: artUrl = media.get_thumbnail() assert artUrl is not None metadata['mpris:artUrl'] = GLib.Variant('s', artUrl) except: pass return metadata
def _add_item(self, source, param, item, remaining=0, data=None): if data is None: return model, category = data self.found_items_number = ( self.model.iter_n_children(self.head_iters[0]) + self.model.iter_n_children(self.head_iters[1]) + self.model.iter_n_children(self.head_iters[2]) + self.model.iter_n_children(self.head_iters[3])) if category == 'song' and self.found_items_number == 0 and remaining == 0: if grilo.search_source: self.emit('no-music-found') # We need to remember the view before the search view if self.window.curr_view != self.window.views[5] and \ self.window.prev_view != self.window.views[5]: self.previous_view = self.window.prev_view if remaining == 0: self.window.pop_loading_notification() self.view.show() if not item or model != self.model: return self._offset += 1 title = utils.get_media_title(item) item.set_title(title) artist = utils.get_artist_name(item) # FIXME: Can't be None in treemodel composer = item.get_composer() or "" group = 3 try: group = {'album': 0, 'artist': 1, 'song': 2}[category] except: pass # FIXME: HiDPI icon lookups return a surface that can't be # scaled by GdkPixbuf, so it results in a * scale factor sized # icon for the search view. _iter = None if category == 'album': _iter = self.model.insert_with_values( self.head_iters[group], -1, [0, 2, 3, 4, 5, 9, 11, 13], [str(item.get_id()), title, artist, self._loading_icon, item, 2, category, composer]) self.cache.lookup(item, ArtSize.small, self._on_lookup_ready, _iter) elif category == 'song': _iter = self.model.insert_with_values( self.head_iters[group], -1, [0, 2, 3, 4, 5, 9, 11, 13], [str(item.get_id()), title, artist, self._loading_icon, item, 2 if source.get_id() != 'grl-tracker-source' \ else item.get_favourite(), category, composer]) self.cache.lookup(item, ArtSize.small, self._on_lookup_ready, _iter) else: if not artist.casefold() in self._artists: _iter = self.model.insert_with_values( self.head_iters[group], -1, [0, 2, 4, 5, 9, 11, 13], [str(item.get_id()), artist, self._loading_icon, item, 2, category, composer]) self.cache.lookup(item, ArtSize.small, self._on_lookup_ready, _iter) self._artists[artist.casefold()] = {'iter': _iter, 'albums': []} self._artists[artist.casefold()]['albums'].append(item) if self.model.iter_n_children(self.head_iters[group]) == 1: path = self.model.get_path(self.head_iters[group]) path = self.filter_model.convert_child_path_to_path(path) self.view.get_generic_view().expand_row(path, False)