def load_smart(): tracks = [] request = App().playlists.get_smart_sql(playlist_ids[0]) ids = App().db.execute(request) for id in ids: track = Track(id) # Smart playlist may report invalid tracks # An album always have an artist so check # object is valid. Others Lollypop widgets assume # objects are valid if not track.album.artist_ids: continue tracks.append(track) return tracks
def prev(self): """ Prev track based on history @return Track """ track_id = None if self._shuffle in [Shuffle.TRACKS, Shuffle.TRACKS_ARTIST] or\ self._is_party: if self._history is not None and \ self._history.has_prev(): track_id = self._history.get_prev().get_value() else: track_id = self.current_track.id return Track(track_id)
def __get_playlists_random(self): """ Return a track from current playlist @return Track """ for track in sorted(self._playlist_tracks, key=lambda *args: random.random()): # Ignore current track, not an issue if playing one track # in shuffle because LinearPlayer will handle next() if track != App().player.current_track and ( track.album not in self.__already_played_tracks.keys() or track not in self.__already_played_tracks[track.album]): return track return Track()
def next(self): """ Next shuffle track @return Track """ track_id = None if self._shuffle in [Shuffle.TRACKS, Shuffle.TRACKS_ARTIST] or\ self._is_party: if self._history is not None and \ self._history.has_next(): track_id = self._history.get_next().get_value() elif self._albums is not None: track_id = self._shuffle_next() return Track(track_id)
def next(self): """ Next shuffle track @return Track """ track_id = None if self._shuffle == Shuffle.TRACKS or self.__is_party: if self.shuffle_has_next: track_id = self.__history.get_next().get_value() elif self._albums: track_id = self.__shuffle_next() else: track_id = self._current_track.id return Track(track_id)
def __on_loved_playlist_changed(self, widget, playlist_id, uri, *ignore): """ Updates the loved icon @param playlist as Playlist @param playlist id as int @param track id as int """ if playlist_id != Type.LOVED: return track_id = App().tracks.get_id_by_uri(uri) for row in self.get_children(): if track_id == row.track.id: row.set_indicator(track_id == App().player.current_track.id, Track(track_id).loved)
def update_playlist(): # Save playlist in db only if one playlist visible if len(self.__playlist_ids) == 1 and self.__playlist_ids[0] >= 0: Lp().playlists.clear(self.__playlist_ids[0], False) tracks = [] for track_id in self.__tracks_left + self.__tracks_right: tracks.append(Track(track_id)) Lp().playlists.add_tracks(self.__playlist_ids[0], tracks, False) if not (set(self.__playlist_ids) - set(Lp().player.get_user_playlist_ids())): Lp().player.update_user_playlist(self.__tracks_left + self.__tracks_right)
def __init__(self): """ Init base player variables """ # In case of multiple subclassing, # do not init variables for every subclass if not hasattr(self, '_albums'): GObject.GObject.__init__(self) self._base_init = True # A user playlist used as current playlist self._user_playlist = None # Used by shuffle tracks to restore user playlist before shuffle self._user_playlist_backup = None self.current_track = Track() self.next_track = Track() self.prev_track = Track() self.context = PlayContext() # Albums in current playlist self._albums = None # Current shuffle mode self._shuffle = Lp().settings.get_enum('shuffle') # For tracks from the cmd line self._external_tracks = []
def _play_search(self, object_id=None, is_track=True): """ Play tracks based on search @param started object id as int @param is track as bool """ tracks = [] track_id = None for child in self._view.get_children(): if child.is_track: tracks.append(Track(child.id)) else: album_tracks = Lp().albums.get_tracks(child.id, None) if not is_track and child.id == object_id and album_tracks: track_id = album_tracks[0] for tid in album_tracks: tracks.append(Track(tid)) if tracks: if object_id is not None and is_track: track_id = object_id elif track_id is None: track_id = tracks[0].id GLib.idle_add(self._set_user_playlist_by_tracks, tracks, track_id)
def _on_play_all_press_event(self, widget, event): """ Play album with context @param: widget as Gtk.EventBox @param: event as Gdk.Event """ self._show_append(False) if Lp().player.is_party(): Lp().player.set_party(False) track = Track(self._album.tracks_ids[0]) Lp().player.load(track) Lp().player.set_albums(track.id, self._artist_ids, self._album.genre_ids) return True
def set_albums(self, track_id, artist_id, genre_id): """ Set album list (for next/prev) @param track id as int @param artist id as int @param genre id as int """ # Invalid track if track_id is None: return album = Track(track_id).album self._albums = None ShufflePlayer.reset_history(self) # We are not playing a user playlist anymore self._user_playlist = None self._user_playlist_id = None # We are in all artists if genre_id == Type.ALL or artist_id == Type.ALL: self._albums = Lp.albums.get_compilations(Type.ALL) self._albums += Lp.albums.get_ids() # We are in populars view, add popular albums elif genre_id == Type.POPULARS: self._albums = Lp.albums.get_populars() # We are in recents view, add recent albums elif genre_id == Type.RECENTS: self._albums = Lp.albums.get_recents() # We are in randoms view, add random albums elif genre_id == Type.RANDOMS: self._albums = Lp.albums.get_cached_randoms() # We are in compilation view without genre elif genre_id == Type.COMPILATIONS: self._albums = Lp.albums.get_compilations(None) # Random tracks/albums for artist elif self._shuffle in [Shuffle.TRACKS_ARTIST, Shuffle.ALBUMS_ARTIST]: self._albums = Lp.albums.get_ids(artist_id, genre_id) # Add all albums for genre else: self._albums = Lp.albums.get_compilations(genre_id) self._albums += Lp.albums.get_ids(None, genre_id) album.set_genre(genre_id) if track_id in album.tracks_ids: self.context.position = album.tracks_ids.index(track_id) self.context.genre_id = genre_id # Shuffle album list if needed self._shuffle_albums() else: # Error self.stop()
def _remove_from_device(self, playlists): """ Delete files not available in playlist """ track_uris = [] tracks_ids = [] # Get tracks ids for playlist in playlists: tracks_ids += Lp().playlists.get_tracks_ids(playlist) # Get tracks uris for track_id in tracks_ids: if not self._syncing: self._fraction = 1.0 self._in_thread = False return track = Track(track_id) album_name = GLib.uri_escape_string(track.album_name.lower(), "", False) artist_name = GLib.uri_escape_string(track.artist.lower(), "", False) track_path = Lp().tracks.get_path(track_id) album_uri = "%s/tracks/%s_%s" % (self._uri, artist_name, album_name) track_name = GLib.uri_escape_string(GLib.basename(track_path), "", False) on_disk = Gio.File.new_for_path(track_path) info = on_disk.query_info('time::modified', Gio.FileQueryInfoFlags.NONE, None) # Prefix track with mtime to make sure updating it later mtime = info.get_attribute_as_string('time::modified') dst_uri = "%s/%s_%s" % (album_uri, mtime, track_name) track_uris.append(dst_uri) on_mtp_files = self._get_tracks_files() # Delete file on device and not in playlists for uri in on_mtp_files: if not self._syncing: self._fraction = 1.0 self._in_thread = False return if uri not in track_uris and uri not in self._copied_art_uris: to_delete = Gio.File.new_for_uri(uri) self._retry(to_delete.delete, (None, )) self._done += 1 self._fraction = self._done / self._total GLib.idle_add(self._update_progress)
def __init__(self, object): """ Init edit menu @param object as Album/Track """ Gio.Menu.__init__(self) # Ignore genre_ids/artist_ids if isinstance(object, Album): self.__object = Album(object.id) else: self.__object = Track(object.id) if isinstance(self.__object, Album): self.__set_save_action() if self.__object.is_in_user_collection and App().art.tag_editor: self.__set_edit_action()
def prev(self): """ Prev track based on history @return Track """ repeat = App().settings.get_enum("repeat") if repeat == Repeat.TRACK: return self._current_playback_track track = Track() if self._shuffle == Shuffle.TRACKS or self.__is_party: if self.shuffle_has_prev: track = self.__history.prev.value else: track = self._current_playback_track return track
def set_loved(track_id, loved): """ Add or remove track from loved playlist @param track_id @param loved Add to loved playlist if `True`; remove if `False` """ if not is_loved(track_id): if loved: Lp().playlists.add_tracks(Type.LOVED, [Track(track_id)]) if Lp().lastfm is not None: t = Thread(target=_set_loved_on_lastfm, args=(track_id, True)) t.daemon = True t.start() else: if not loved: Lp().playlists.remove_tracks(Type.LOVED, [Track(track_id)]) if Lp().lastfm is not None: t = Thread(target=_set_loved_on_lastfm, args=(track_id, False)) t.daemon = True t.start()
def _on_play_clicked(self, widget): """ Play artist albums """ try: if Lp().player.is_party: Lp().player.set_party(False) album_id = Lp().albums.get_ids(self._artist_ids, self._genre_ids)[0] track = Track(Album(album_id).track_ids[0]) Lp().player.load(track) Lp().player.set_albums(track.id, self._artist_ids, self._genre_ids) self.__set_add_icon() except: pass # Artist not available anymore for this context
def __init__(self, object): """ Init edit menu @param object as Album/Track """ # Ignore genre_ids/artist_ids if isinstance(object, Album): obj = Album(object.id) else: obj = Track(object.id) BaseMenu.__init__(self, obj) dbus_helper = DBusHelper() dbus_helper.call("CanLaunchTagEditor", None, self.__on_can_launch_tag_editor, None)
def _on_activated(self, widget, track_id, playlist_name): """ On track activation, play track @param widget as TracksWidget @param track as Track @param playlist name as str """ if Lp.player.is_party(): Lp.player.load(Track(track_id)) else: track = Lp.player.set_user_playlist(self._tracks1 + self._tracks2, track_id) Lp.player.set_user_playlist_id(self._playlist_id) if track is not None: Lp.player.load(track)
def load(): tracks = [] all_ids = [] for playlist_id in playlist_ids: if playlist_id == Type.LOVED: ids = App().tracks.get_loved_track_ids() else: ids = App().playlists.get_track_ids(playlist_id) for id in ids: if id in all_ids: continue all_ids.append(id) track = Track(id) tracks.append(track) return tracks
def restore_state(self): """ Restore player state """ track_id = Lp().settings.get_value('track-id').get_int32() if Lp().settings.get_value('save-state') and track_id > 0: path = Lp().tracks.get_path(track_id) if path != "": self._load_track(Track(track_id)) self.set_albums(track_id, [Type.ALL], [Type.ALL]) self.set_next() self.set_prev() self.emit('current-changed') else: print("Player::restore_state(): track missing")
def _on_entry_parsed(self, parser, uri, metadata, playlist_id): """ Import entry @param parser as TotemPlParser.Parser @param playlist uri as str @param metadata as GLib.HastTable @param playlist id as int """ try: track_id = Lp().tracks.get_id_by_path( GLib.filename_from_uri(uri)[0]) if track_id is not None: self.add_tracks(playlist_id, [Track(track_id)]) except Exception as e: print("Playlists::_on_entry_parsed: %s" % e)
def next(self): """ Next Track @return Track """ track = Track() if self._external_tracks and\ self._current_track in self._external_tracks: idx = self._external_tracks.index(self._current_track) if idx + 1 >= len(self._external_tracks): idx = 0 else: idx += 1 track = self._external_tracks[idx] return track
def prev(self): """ Prev track id @return Track """ track = Track() if self._user_playlist and\ self.current_track in self._user_playlist: idx = self._user_playlist.index(self.current_track) if idx - 1 < 0: idx = len(self._user_playlist) - 1 else: idx -= 1 track = self._user_playlist[idx] return track
def next(self): """ Next Track @return Track """ track = Track() if self._user_playlist and\ self.current_track in self._user_playlist: idx = self._user_playlist.index(self.current_track) if idx + 1 >= len(self._user_playlist): idx = 0 else: idx += 1 track = self._user_playlist[idx] return track
def load_external(self, uri, name=''): """ Load external tracks @param uri as str @param name as string """ track = Track() track.set_album_artists([name]) track.set_uri(uri) if track.uri.startswith('file://'): track.id = Type.EXTERNALS track.name = GLib.path_get_basename(GLib.filename_from_uri(uri)[0]) else: track.name = uri track.id = Type.RADIOS self._external_tracks.append(track)
def prev(self): """ Prev track id @return Track """ track = Track() if self._external_tracks and\ self.current_track in self._external_tracks: idx = self._external_tracks.index(self.current_track) if idx - 1 < 0: idx = len(self._external_tracks) - 1 else: idx -= 1 track = self._external_tracks[idx] return track
def set_user_playlist_by_id(self, playlist_id): """ Set user playlist as current playback playlist @param array of tracks as [Track] @return track id as Track @thread safe """ tracks = [] self._user_playlist_id = playlist_id for track_id in Lp().playlists.get_tracks_ids(playlist_id): if track_id == Lp().player.current_track.id: tracks.append(Lp().player.current_track) else: tracks.append(Track(track_id)) self._user_playlist = tracks self._shuffle_playlist()
def __save_track_thread(self, item, persistent): """ Save item into collection as track @param item as SearchItem @param persistent as DbPersistent """ album_artist = item.artists[0] (album_id, track_id) = self.__save_track(item, persistent, album_artist) if track_id is None: return self.__save_cover(item, album_id) if Lp().settings.get_value('artist-artwork'): Lp().art.cache_artists_info() if persistent == DbPersistent.NONE: GLib.idle_add(Lp().player.load, Track(track_id))
def __add_a_new_track(self, similar_artist_ids): """ Add a new track to playback @param similar_artist_ids as [int] """ # Get an album album_ids = App().albums.get_ids(similar_artist_ids, []) track_ids = [] for album_id in album_ids: track_ids += Album(album_id).track_ids shuffle(track_ids) while track_ids: track_id = track_ids.pop(0) if track_id not in self.playlist_track_ids: self.insert_track(Track(track_id), -1) break
def prev(self): """ Prev track id @return Track """ track = Track() current_track_id = self._current_track.id track_ids = self.playlist_track_ids if track_ids and current_track_id in track_ids: idx = track_ids.index(current_track_id) if idx - 1 < 0: idx = len(track_ids) - 1 else: idx -= 1 track = self._playlist_tracks[idx] return track