def add_artist_to_playback(artist_ids, genre_ids, add): """ Add artist to current playback @param artist_ids as [int] @param genre_ids as [int] @param add as bool """ try: storage_type = get_default_storage_type() album_ids = App().albums.get_ids(genre_ids, artist_ids, storage_type, False) if App().settings.get_value("play-featured"): album_ids += App().artists.get_featured(genre_ids, artist_ids, storage_type, False) if add: albums = [] for album_id in album_ids: if album_id not in App().player.album_ids: album = Album(album_id, genre_ids, artist_ids, False) albums.append(album) App().player.add_albums(albums) else: App().player.remove_album_by_ids(album_ids) if len(App().player.albums) == 0: App().player.stop() elif App().player.current_track.album.id\ not in App().player.album_ids: App().player.skip_album() except Exception as e: Logger.error("add_artist_to_playback(): %s" % e)
def get_today_album(): """ Get today album @return Album/None """ current_date = GLib.DateTime.new_now_local().get_day_of_year() (date, album_id) = (0, None) try: (date, album_id) = load(open(LOLLYPOP_DATA_PATH + "/today.bin", "rb")) if App().albums.get_storage_type(album_id) == StorageType.NONE: date = 0 except Exception as e: Logger.warning("TodayBannerWidget::__get_today_album(): %s", e) try: if date != current_date: storage_type = get_default_storage_type() album_id = App().albums.get_randoms(storage_type, None, False, 1)[0] dump((current_date, album_id), open(LOLLYPOP_DATA_PATH + "/today.bin", "wb")) return Album(album_id) except Exception as e: Logger.error("TodayBannerWidget::__get_today_album(): %s", e) return None
def __migrate_old_dir(self): """ Migrate old data dir """ try: old_path = GLib.get_user_data_dir() + "/lollypop/info" old_src = Gio.File.new_for_path(old_path) if not old_src.query_exists(): return storage_type = get_default_storage_type() for (artist_id, artist, *ignore) in App().artists.get([], storage_type): for ext in ["jpg", "txt"]: src_path = "%s/%s.%s" % (old_path, escape(artist), ext) src = Gio.File.new_for_path(src_path) if not src.query_exists(): continue encoded = self.encode_artist_name(artist) dst_path = "%s/%s.%s" % (ARTISTS_PATH, encoded, ext) dst = Gio.File.new_for_path(dst_path) src.copy(dst, Gio.FileCopyFlags.OVERWRITE, None, None) old_dst = Gio.File.new_for_path(GLib.get_user_data_dir() + "/lollypop/info-backup") old_src.move(old_dst, Gio.FileCopyFlags.OVERWRITE, None, None) except Exception as e: Logger.error("ArtistArt::__migrate_old_dir(): %s -> %s", e, old_path)
def __handle_artist_update(self, artist_id, scan_update): """ Add/remove artist to/from list @param artist_id as int @param scan_update as ScanUpdate """ if Type.GENRES_LIST in self.sidebar.selected_ids: selection_list = self.right_list genre_ids = self.left_list.selected_ids elif Type.ARTISTS_LIST in self.sidebar.selected_ids and\ self.left_list.mask & SelectionListMask.ARTISTS: selection_list = self.left_list genre_ids = [] else: return storage_type = get_default_storage_type() artist_ids = App().artists.get_ids(genre_ids, storage_type) # We only test add, remove and absent is safe if artist_id not in artist_ids and scan_update == ScanUpdate.ADDED: return artist_name = App().artists.get_name(artist_id) sortname = App().artists.get_sortname(artist_id) genre_ids = [] if scan_update == ScanUpdate.ADDED: selection_list.add_value((artist_id, artist_name, sortname)) elif not App().albums.get_ids(genre_ids, [artist_id], storage_type, True): selection_list.remove_value(artist_id)
def search_similar_albums(self, cancellable): """ Add similar albums to DB @param cancellable as Gio.Cancellable """ Logger.info("Get similar albums from Spotify") from lollypop.similars_spotify import SpotifySimilars similars = SpotifySimilars() try: storage_type = get_default_storage_type() artists = App().artists.get_randoms( self.MAX_ITEMS_PER_STORAGE_TYPE, storage_type) artist_names = [name for (aid, name, sortname) in artists] similar_ids = similars.get_similar_artist_ids( artist_names, cancellable) # Add albums shuffle(similar_ids) for similar_id in similar_ids[:self.MAX_ITEMS_PER_STORAGE_TYPE]: albums_payload = self.__get_artist_albums_payload( similar_id, cancellable) shuffle(albums_payload) for album in albums_payload: if cancellable.is_cancelled(): raise Exception("Cancelled") lollypop_payload = SpotifyWebHelper.lollypop_album_payload( self, album) self.save_album_payload_to_db(lollypop_payload, StorageType.SPOTIFY_SIMILARS, True, cancellable) break except Exception as e: Logger.warning("SpotifyWebService::search_similar_albums(): %s", e)
def __init__(self, genre_id, view_type, header=False): """ Init decade menu @param genre_id as int @param view_type as ViewType @param header as bool """ Gio.Menu.__init__(self) if header: from lollypop.menu_header import RoundedMenuHeader name = App().genres.get_name(genre_id) artwork_name = "genre_%s" % name self.append_item(RoundedMenuHeader(name, artwork_name)) if not view_type & ViewType.BANNER: from lollypop.menu_playback import GenrePlaybackMenu self.append_section(_("Playback"), GenrePlaybackMenu(genre_id)) from lollypop.menu_sync import SyncAlbumsMenu section = Gio.Menu() self.append_section(_("Add to"), section) storage_type = get_default_storage_type() album_ids = App().albums.get_ids([genre_id], [], storage_type, False) album_ids += App().albums.get_compilation_ids([genre_id], storage_type, False) albums = [Album(album_id) for album_id in album_ids] section.append_submenu(_("Devices"), SyncAlbumsMenu(albums))
def load(): (genre_id, genre) = App().genres.get_random() GLib.idle_add(self._label.set_text, genre) storage_type = get_default_storage_type() album_ids = App().albums.get_randoms(storage_type, genre_id, False, self.ITEMS) return [Album(album_id) for album_id in album_ids]
def next_album(self): """ Get next album to add @return Album """ storage_type = get_default_storage_type() for album_id in App().albums.get_randoms(storage_type, None, False, 2): if album_id != self.current_track.album.id: return Album(album_id) return None
def load(): request = App().playlists.get_smart_sql(self.__playlist_id) # We need to inject skipped/storage_type storage_type = get_default_storage_type() split = request.split("ORDER BY") split[0] += " AND tracks.loved != %s" % Type.NONE split[0] += " AND tracks.storage_type&%s " % storage_type track_ids = App().db.execute("ORDER BY".join(split)) return tracks_to_albums( [Track(track_id) for track_id in track_ids])
def __get_album_ids(self): """ Get album ids for genre @return [int] """ storage_type = get_default_storage_type() album_ids = App().albums.get_compilation_ids([self.__genre_id], storage_type, False) album_ids += App().albums.get_ids([self.__genre_id], [], storage_type, False) return album_ids
def __init__(self, view_type, minimal=False): """ Init artist infos @param view_type as ViewType @param minimal as bool """ View.__init__(self, get_default_storage_type(), view_type) self.__information_store = InformationStore() self.__cancellable = Gio.Cancellable() self.__minimal = minimal self.__artist_name = ""
def __get_album_ids(self): """ Get album ids for decade @return [int] """ storage_type = get_default_storage_type() album_ids = [] for year in self.__years: album_ids += App().albums.get_compilation_ids_for_year( year, storage_type, False) album_ids += App().albums.get_ids_for_year(year, storage_type, False) return album_ids
def __handle_genre_update(self, genre_id, scan_update): """ Add genre to genre list @param genre_id as int @param scan_update as ScanUpdate """ if Type.GENRES_LIST in self.sidebar.selected_ids: storage_type = get_default_storage_type() if scan_update == ScanUpdate.ADDED: genre_name = App().genres.get_name(genre_id) self.left_list.add_value((genre_id, genre_name, genre_name)) elif not App().artists.get_ids([genre_id], storage_type): self.left_list.remove_value(genre_id)
def __on_right_list_activated(self, listbox, row): """ Update view based on selected object @param listbox as Gtk.ListBox @param row as Gtk.ListBoxRow """ storage_type = get_default_storage_type() genre_ids = self.left_list.selected_ids artist_ids = self.right_list.selected_ids view = self._get_view_artists(genre_ids, artist_ids, storage_type) view.show() self._stack.add(view) self._stack.set_visible_child(view) self.set_focused_view(view) self.sub_widget.set_visible_child(self.grid_view)
def _get_album_ids(self): """ Get album ids @return [int] """ storage_type = get_default_storage_type() album_ids = [] for year in self._data: album_ids += App().albums.get_ids_for_year(year, storage_type, True, self._ALBUMS_COUNT) l = len(album_ids) if l < self._ALBUMS_COUNT: album_ids += App().albums.get_compilation_ids_for_year( year, storage_type, True, self._ALBUMS_COUNT) return album_ids
def has_albums(self, artist_id): """ Get album for artist id @param artist_id as int @return bool """ with SqlCursor(self.__db) as sql: storage_type = get_default_storage_type() request = "SELECT DISTINCT albums.rowid\ FROM album_artists, albums\ WHERE albums.rowid=album_artists.album_id\ AND album_artists.artist_id=?\ AND albums.storage_type & ?" result = sql.execute(request, (artist_id, storage_type)) return len(list(itertools.chain(*result))) != 0
def __get_album_from_artists(self, similar_artist_ids): """ Add a new album to playback @param similar_artist_ids as [int] @return Album """ # Get an album storage_type = get_default_storage_type() album_ids = App().albums.get_ids( [], similar_artist_ids, storage_type, False) shuffle(album_ids) while album_ids: album_id = album_ids.pop(0) if album_id not in self.album_ids: return Album(album_id, [], [], False) return None
def __init__(self, artist_id, storage_type, view_type, header=False): """ Init artist menu @param artist_id as int @param storage_type as StorageType @param view_type as ViewType @param header as bool """ Gio.Menu.__init__(self) if header: from lollypop.menu_header import ArtistMenuHeader self.append_item(ArtistMenuHeader(artist_id)) if view_type & ViewType.BANNER: show_artist_tracks = App().settings.get_value("show-artist-tracks") action = Gio.SimpleAction.new_stateful( "show-artist-tracks", None, GLib.Variant.new_boolean(show_artist_tracks)) App().add_action(action) action.connect("change-state", self.__on_change_state) self.append(_("Show tracks"), "app.show-artist-tracks") if not show_artist_tracks: action = Gio.SimpleAction.new_stateful( "show-year-below-name", None, GLib.Variant.new_boolean( App().settings.get_value("show-year-below-name"))) App().add_action(action) action.connect("change-state", self.__on_change_state) self.append(_("Show year"), "app.show-year-below-name") action = Gio.SimpleAction.new_stateful( "play-featured", None, GLib.Variant.new_boolean( App().settings.get_value("play-featured"))) App().add_action(action) action.connect("change-state", self.__on_change_state) self.append(_("Play featured"), "app.play-featured") else: from lollypop.menu_playback import ArtistPlaybackMenu self.append_section(_("Playback"), ArtistPlaybackMenu(artist_id, storage_type)) menu = Gio.Menu() self.append_section(_("Artist"), menu) storage_type = get_default_storage_type() album_ids = App().albums.get_ids([], [artist_id], storage_type, False) albums = [Album(album_id) for album_id in album_ids] menu.append_submenu(_("Devices"), SyncAlbumsMenu(albums)) menu.append_submenu(_("Playlists"), PlaylistsMenu(albums))
def set_party_ids(self): """ Set party mode ids """ if not self._is_party: return party_ids = App().settings.get_value("party-ids") storage_type = get_default_storage_type() album_ids = App().albums.get_ids(party_ids, [], storage_type, False) emit_signal(self, "playback-setted", []) self._albums = [] if album_ids: emit_signal(self, "loading-changed", True, Track()) for album_id in album_ids: album = Album(album_id, [], [], False) self._albums.append(album) emit_signal(self, "playback-setted", list(self._albums))
def __get_albums(self, playlist_id): """ Get albums for playlist_id @parma playlist_id as int """ if App().playlists.get_smart(playlist_id): request = App().playlists.get_smart_sql(playlist_id) # We need to inject skipped/storage_type storage_type = get_default_storage_type() split = request.split("ORDER BY") split[0] += " AND loved != %s" % Type.NONE split[0] += " AND tracks.storage_type&%s " % storage_type track_ids = App().db.execute("ORDER BY".join(split)) albums = tracks_to_albums( [Track(track_id) for track_id in track_ids]) else: tracks = App().playlists.get_tracks(playlist_id) albums = tracks_to_albums(tracks) return albums
def play_artists(artist_ids, genre_ids): """ Play artists @param artist_ids as [int] @param genre_ids as [int] """ try: storage_type = get_default_storage_type() if App().player.is_party: App().lookup_action("party").change_state(GLib.Variant("b", False)) album_ids = App().albums.get_ids(genre_ids, artist_ids, storage_type, False) if App().settings.get_value("play-featured"): album_ids += App().artists.get_featured(genre_ids, artist_ids, storage_type, False) albums = [] for album_id in album_ids: albums.append(Album(album_id, genre_ids, artist_ids, False)) App().player.play_albums(albums) except Exception as e: Logger.error("play_artists(): %s" % e)
def __on_left_list_activated(self, listbox, row): """ Update view based on selected object @param listbox as Gtk.ListBox @param row as Gtk.ListBoxRow """ Logger.debug("Container::__on_left_list_activated()") selected_ids = self.left_list.selected_ids view = None storage_type = get_default_storage_type() if self.left_list.mask & SelectionListMask.GENRES: if not App().window.folded: view = self._get_view_albums(selected_ids, [], storage_type) self._show_artists_list(self.right_list, selected_ids) self._show_right_list() else: view = self._get_view_artists([], selected_ids, storage_type) self.set_focused_view(view) self.sub_widget.set_visible_child(self.grid_view) if view is not None: view.show() self._stack.add(view) self._stack.set_visible_child(view)
def get_track_ids(self, playlist_id): """ Return availables track ids for playlist @param playlist_id as int @return [int] """ track_ids = [] limit = App().settings.get_value("view-limit").get_int32() storage_type = get_default_storage_type() if playlist_id == Type.POPULARS: track_ids = App().tracks.get_populars([], storage_type, False, limit) elif playlist_id == Type.RECENTS: track_ids = App().tracks.get_recently_listened_to(storage_type, False, limit) elif playlist_id == Type.LITTLE: track_ids = App().tracks.get_little_played(storage_type, False, limit) elif playlist_id == Type.RANDOMS: track_ids = App().tracks.get_randoms([], storage_type, False, limit) elif playlist_id == Type.ALL: track_ids = App().tracks.get_ids(storage_type, False) elif playlist_id == Type.LOVED: track_ids = App().tracks.get_loved_track_ids([], storage_type) else: with SqlCursor(self) as sql: result = sql.execute("SELECT music.tracks.rowid\ FROM tracks, music.tracks\ WHERE tracks.playlist_id=?\ AND music.tracks.uri=\ main.tracks.uri", (playlist_id,)) track_ids = list(itertools.chain(*result)) return track_ids
def load(): storage_type = get_default_storage_type() album_ids = App().albums.get_populars_at_the_moment(storage_type, False, self.ITEMS) return [Album(album_id) for album_id in album_ids]
def load(): storage_type = get_default_storage_type() ids = App().artists.get_randoms(15, storage_type) return ids
def __on_sidebar_activated(self, listbox, row): """ Update view based on selected object @param listbox as Gtk.ListBox @param row as Gtk.ListBoxRow """ Logger.debug("Container::__on_sidebar_activated()") self.sub_widget.set_visible_child(self.grid_view) view = None focus_set = False selected_id = self._sidebar.selected_id if selected_id is None: return # Update lists if selected_id in [Type.ARTISTS_LIST, Type.GENRES_LIST] and\ self.type_ahead.get_reveal_child() and\ self.left_list.get_visible(): self.set_focused_view(self.left_list) focus_set = True elif selected_id == Type.ARTISTS_LIST: self._show_artists_list(self.left_list) self._hide_right_list() self.left_list.show() self.widget.set_visible_child(self.sub_widget) self.sub_widget.set_visible_child(self.left_list) self.set_focused_view(self.left_list) focus_set = True elif selected_id == Type.GENRES_LIST: self._show_genres_list(self.left_list) self._hide_right_list() self.left_list.show() self.widget.set_visible_child(self.sub_widget) self.sub_widget.set_visible_child(self.left_list) self.set_focused_view(self.left_list) focus_set = True else: self.left_list.hide() self.left_list.clear() if self.widget.get_folded(): self.widget.set_visible_child(self.sub_widget) self.sub_widget.set_visible_child(self.grid_view) storage_type = get_default_storage_type() if selected_id in [Type.ARTISTS_LIST, Type.GENRES_LIST] and not\ App().window.folded: view = NoneView() view.show() elif selected_id == Type.PLAYLISTS: view = self._get_view_playlists() elif selected_id == Type.LYRICS: view = self._get_view_lyrics() elif selected_id == Type.CURRENT: view = self.get_view_current() elif selected_id == Type.SEARCH: view = self.get_view_search() elif selected_id == Type.SUGGESTIONS: view = self._get_view_suggestions(storage_type) elif selected_id in [Type.POPULARS, Type.LOVED, Type.RECENTS, Type.LITTLE, Type.RANDOMS]: view = self._get_view_albums([selected_id], [], storage_type) elif selected_id == Type.WEB: view = self._get_view_albums([selected_id], [], StorageType.SAVED) elif selected_id == Type.YEARS: view = self._get_view_albums_decades(storage_type) elif selected_id == Type.GENRES: view = self._get_view_genres(storage_type) elif selected_id == Type.ARTISTS: view = self._get_view_artists_rounded(storage_type) elif selected_id == Type.ALL: view = self._get_view_albums([selected_id], [], storage_type) elif selected_id == Type.COMPILATIONS: view = self._get_view_albums([selected_id], [], storage_type) if view is not None and view not in self._stack.get_children(): view.show() self._stack.add(view) if view is not None: self._stack.set_visible_child(view) if not focus_set: self.set_focused_view(view) emit_signal(self, "can-go-back-changed", self.can_go_back)
def load(): storage_type = get_default_storage_type() artists = App().artists.get(genre_ids, storage_type) return artists
def show_view(self, item_ids, data=None, storage_type=None): """ Show view for item id @param item_ids as [int] @param data as object @param storage_type as StorageType """ self.sub_widget.set_visible_child(self.grid_view) view = None if storage_type is None: storage_type = get_default_storage_type() hide_selection_list = True if item_ids: if item_ids[0] in [ Type.POPULARS, Type.LOVED, Type.RECENTS, Type.LITTLE, Type.RANDOMS ]: view = self._get_view_albums(item_ids, [], storage_type) elif item_ids[0] == Type.WEB: view = self._get_view_albums(item_ids, [], StorageType.SAVED) elif item_ids[0] == Type.SUGGESTIONS: view = self._get_view_suggestions(storage_type) elif item_ids[0] == Type.SEARCH: view = self.get_view_search(data) elif item_ids[0] == Type.INFO: view = self._get_view_info() elif item_ids[0] == Type.DEVICE_ALBUMS: view = self._get_view_device_albums(data) elif item_ids[0] == Type.DEVICE_PLAYLISTS: view = self._get_view_device_playlists(data) elif item_ids[0] == Type.LYRICS: view = self._get_view_lyrics() elif item_ids[0] == Type.GENRES: if data is None: view = self._get_view_genres(storage_type) else: view = self._get_view_albums([data], [], storage_type) elif item_ids[0] == Type.ALBUM: hide_selection_list = False view = self._get_view_album(data, storage_type) elif item_ids[0] == Type.YEARS: if data is None: view = self._get_view_albums_decades(storage_type) else: view = self._get_view_albums_years(data, storage_type) elif item_ids[0] == Type.PLAYLISTS: view = self._get_view_playlists(data) elif item_ids[0] == Type.EQUALIZER: from lollypop.view_equalizer import EqualizerView view = EqualizerView() elif item_ids[0] == Type.ALL: view = self._get_view_albums(item_ids, [], storage_type) elif item_ids[0] == Type.COMPILATIONS: view = self._get_view_albums(item_ids, [], storage_type) elif item_ids[0] == Type.ARTISTS: view = self._get_view_artists([], data, storage_type) self._sidebar.select_ids(item_ids, False) if hide_selection_list: self._hide_right_list() self.left_list.hide() if view is not None: self.set_focused_view(view) view.show() self._stack.add(view) self._stack.set_visible_child(view) emit_signal(self, "can-go-back-changed", self.can_go_back)
def populate(self, artist_id=None): """ Show information for artists @param artist_id as int """ builder = Gtk.Builder() builder.add_from_resource( "/org/gnome/Lollypop/ArtistInformation.ui") builder.connect_signals(self) self.__scrolled = builder.get_object("scrolled") widget = builder.get_object("widget") self.add(widget) self.__stack = builder.get_object("stack") self.__listbox = builder.get_object("listbox") self.__artist_label = builder.get_object("artist_label") title_label = builder.get_object("title_label") self.__artist_artwork = builder.get_object("artist_artwork") bio_eventbox = builder.get_object("bio_eventbox") artist_label_eventbox = builder.get_object("artist_label_eventbox") bio_eventbox.connect("realize", set_cursor_type) artist_label_eventbox.connect("realize", set_cursor_type) self.__gesture1 = GesturesHelper( bio_eventbox, primary_press_callback=self._on_info_label_press) self.__gesture2 = GesturesHelper( artist_label_eventbox, primary_press_callback=self._on_artist_label_press) self.__bio_label = builder.get_object("bio_label") if artist_id is None and App().player.current_track.id is not None: builder.get_object("header").show() if App().player.current_track.album.artist_ids[0] ==\ Type.COMPILATIONS: artist_id = App().player.current_track.artist_ids[0] else: artist_id = App().player.current_track.album.artist_ids[0] title_label.set_text(App().player.current_track.title) self.__artist_name = App().artists.get_name(artist_id) if self.__minimal: self.__bio_label.set_margin_start(MARGIN) self.__bio_label.set_margin_end(MARGIN) self.__bio_label.set_margin_top(MARGIN) self.__bio_label.set_margin_bottom(MARGIN) self.__artist_artwork.hide() else: self.__artist_artwork.set_margin_start(MARGIN_SMALL) builder.get_object("header").show() self.__artist_label.set_text(self.__artist_name) self.__artist_label.show() title_label.show() App().art_helper.set_artist_artwork( self.__artist_name, ArtSize.SMALL * 3, ArtSize.SMALL * 3, self.__artist_artwork.get_scale_factor(), ArtBehaviour.ROUNDED | ArtBehaviour.CROP_SQUARE | ArtBehaviour.CACHE, self.__on_artist_artwork) albums_view = AlbumsListView([], [], ViewType.SCROLLED) albums_view.set_size_request(300, -1) albums_view.show() albums_view.set_margin_start(5) albums_view.add_widget(albums_view.box) widget.attach(albums_view, 2, 1, 1, 2) albums = [] storage_type = get_default_storage_type() for album_id in App().albums.get_ids([], [artist_id], storage_type, True): albums.append(Album(album_id)) if not albums: albums = [App().player.current_track.album] albums_view.populate(albums) content = self.__information_store.get_information(self.__artist_name, ARTISTS_PATH) if content is None: self.__bio_label.set_text(_("Loading information")) from lollypop.information_downloader import InformationDownloader downloader = InformationDownloader() downloader.get_information(self.__artist_name, self.__on_artist_information, self.__artist_name) else: App().task_helper.run(self.__to_markup, content, callback=(self.__bio_label.set_markup,))