示例#1
0
 def search(self, search, cancellable):
     """
         Get albums related to search
         We need a thread because we are going to populate DB
         @param search as str
         @param cancellable as Gio.Cancellable
     """
     try:
         while self.wait_for_token():
             if cancellable.is_cancelled():
                 raise Exception("cancelled")
             sleep(1)
         token = "Bearer %s" % self.__token
         helper = TaskHelper()
         helper.add_header("Authorization", token)
         uri = "https://api.spotify.com/v1/search?"
         uri += "q=%s&type=album,track" % search
         (status, data) = helper.load_uri_content_sync(uri, cancellable)
         if status:
             decode = json.loads(data.decode("utf-8"))
             album_ids = []
             self.__create_albums_from_album_payload(
                                              decode["albums"]["items"],
                                              album_ids,
                                              cancellable)
             self.__create_albums_from_tracks_payload(
                                              decode["tracks"]["items"],
                                              album_ids,
                                              cancellable)
     except Exception as e:
         Logger.warning("SpotifyHelper::search(): %s", e)
         # Do not emit search-finished on cancel
         if str(e) == "cancelled":
             return
     GLib.idle_add(self.emit, "search-finished")
示例#2
0
 def __connect(self, full_sync=False):
     """
         Connect service
         @param full_sync as bool
         @thread safe
     """
     if self.__goa is not None or (self.__password != ""
                                   and self.__login != ""):
         self.__is_auth = True
     else:
         self.__is_auth = False
     try:
         self.session_key = ""
         self.__check_for_proxy()
         if self.__goa is not None:
             self.session_key = self.__goa.call_get_access_token_sync(
                 None)[0]
         else:
             skg = SessionKeyGenerator(self)
             self.session_key = skg.get_session_key(username=self.__login,
                                                    password_hash=md5(
                                                        self.__password))
         if full_sync:
             helper = TaskHelper()
             helper.run(self.__populate_loved_tracks)
     except Exception as e:
         debug("LastFM::__connect(): %s" % e)
         self.__is_auth = False
示例#3
0
 def _get_itunes_album_artwork(self, artist, album):
     """
         Get album artwork from itunes
         @param artist as string
         @param album as string
         @return image as bytes
         @tread safe
     """
     image = None
     try:
         album_formated = GLib.uri_escape_string(album, None,
                                                 True).replace(" ", "+")
         uri = "https://itunes.apple.com/search" +\
               "?entity=album&term=%s" % album_formated
         helper = TaskHelper()
         (status, data) = helper.load_uri_content_sync(uri, None)
         if status:
             decode = json.loads(data.decode("utf-8"))
             for item in decode["results"]:
                 if item["artistName"].lower() == artist.lower():
                     uri = item["artworkUrl60"].replace("60x60", "512x512")
                     (status,
                      image) = helper.load_uri_content_sync(uri, None)
                     break
     except Exception as e:
         Logger.error("Downloader::_get_album_art_itunes: %s [%s/%s]" %
                      (e, artist, album))
     return image
    def populate(self):
        """
            Populate view
        """
        image = Gtk.Image.new_from_icon_name("edit-clear-all-symbolic",
                                             Gtk.IconSize.DIALOG)
        image.set_property("valign", Gtk.Align.CENTER)
        image.set_property("halign", Gtk.Align.CENTER)
        context = image.get_style_context()
        context.add_class("cover-frame")
        padding = context.get_padding(Gtk.StateFlags.NORMAL)
        border = context.get_border(Gtk.StateFlags.NORMAL)
        image.set_size_request(
            ArtSize.BIG + padding.left + padding.right + border.left +
            border.right, ArtSize.BIG + padding.top + padding.bottom +
            border.top + border.bottom)
        image.show()
        self.__view.add(image)

        # First load local files
        if self.__album is not None:
            uris = App().art.get_album_artworks(self.__album)
            for uri in uris:
                try:
                    f = Gio.File.new_for_uri(uri)
                    (status, content, tag) = f.load_contents()
                    self.__add_pixbuf(uri, status, content, print)
                except Exception as e:
                    Logger.error("ArtworkSearch::populate(): %s" % e)
        # Then google
        uri = App().art.get_google_search_uri(self.__get_current_search())
        helper = TaskHelper()
        helper.load_uri_content(uri, self.__cancellable,
                                self.__on_google_content_loaded)
 def __populate(self, uris):
     """
         Add uris to view
         @param uris as [str]
     """
     if self.__cancellable.is_cancelled():
         return
     helper = TaskHelper()
     # Fallback to link extraction
     if uris is None and WEBKIT2:
         if self.__web_search is None:
             self.__back_button.show()
             self.__web_search = ArtworkSearchWebView(self.__spinner)
             self.__web_search.connect("populated",
                                       self.__on_web_search_populated)
             self.__web_search.show()
             self.__entry.hide()
             self.__stack.add_named(self.__web_search, "web")
             self.__stack.set_visible_child_name("web")
             self.__web_search.search(self.__get_current_search())
     # Populate the view
     elif uris:
         uri = uris.pop(0)
         helper.load_uri_content(uri, self.__cancellable, self.__add_pixbuf,
                                 self.__populate, uris)
     # Nothing to load, stop
     else:
         self.__spinner.stop()
示例#6
0
 def _get_deezer_album_artwork(self, artist, album):
     """
         Get album artwork from deezer
         @param artist as string
         @param album as string
         @return image as bytes
         @tread safe
     """
     image = None
     try:
         album_formated = GLib.uri_escape_string(album, None, True)
         uri = "https://api.deezer.com/search/album/?" +\
               "q=%s&output=json" % album_formated
         helper = TaskHelper()
         (status, data) = helper.load_uri_content_sync(uri, None)
         if status:
             decode = json.loads(data.decode("utf-8"))
             uri = None
             for item in decode["data"]:
                 if item["artist"]["name"].lower() == artist.lower():
                     uri = item["cover_xl"]
                     break
             if uri is not None:
                 (status, image) = helper.load_uri_content_sync(uri, None)
     except Exception as e:
         Logger.error("Downloader::__get_deezer_album_artwork: %s" % e)
     return image
 def __download_genius_lyrics(self):
     """
         Download lyrics from genius
     """
     self.__downloads_running += 1
     # Update lyrics
     if self.__current_track.id == Type.RADIOS:
         split = App().player.current_track.name.split(" - ")
         if len(split) < 2:
             return
         artist = split[0]
         title = split[1]
     else:
         if self.__current_track.artists:
             artist = self.__current_track.artists[0]
         elif self.__current_track.album_artists:
             artist = self.__current_track.album_artists[0]
         else:
             artist = ""
         title = self.__current_track.name
     string = escape("%s %s" % (artist, title))
     uri = "https://genius.com/%s-lyrics" % string.replace(" ", "-")
     helper = TaskHelper()
     helper.load_uri_content(uri, self.__cancellable,
                             self.__on_lyrics_downloaded,
                             "song_body-lyrics", "")
示例#8
0
 def get_similar_artists(self, artist_id, cancellable):
     """
        Get similar artists
        @param artist_id as int
        @param cancellable as Gio.Cancellable
        @return artists as [str]
     """
     artists = []
     try:
         while self.wait_for_token():
             if cancellable.is_cancelled():
                 raise Exception("cancelled")
             sleep(1)
         token = "Bearer %s" % self.__token
         helper = TaskHelper()
         helper.add_header("Authorization", token)
         uri = "https://api.spotify.com/v1/artists/%s/related-artists" %\
             artist_id
         (status, data) = helper.load_uri_content_sync(uri, cancellable)
         if status:
             decode = json.loads(data.decode("utf-8"))
             for item in decode["artists"]:
                 artists.append(item["name"])
     except Exception as e:
         Logger.error("SpotifyHelper::get_similar_artists(): %s", e)
     return artists
示例#9
0
    def populate(self):
        """
            Populate view
        """
        image = Gtk.Image()
        surface = Lp().art.get_default_icon("edit-clear-all-symbolic",
                                            ArtSize.BIG,
                                            self.get_scale_factor())
        image.set_from_surface(surface)
        image.set_property("valign", Gtk.Align.CENTER)
        image.set_property("halign", Gtk.Align.CENTER)
        image.get_style_context().add_class("cover-frame")
        image.show()
        self._view.add(image)

        # First load local files
        if self.__album is not None:
            uris = Lp().art.get_album_artworks(self.__album)
            for uri in uris:
                try:
                    f = Gio.File.new_for_uri(uri)
                    (status, content, tag) = f.load_contents()
                    self.__add_pixbuf(uri, status, content, print)
                except Exception as e:
                    print("ArtworkSearch::populate()", e)
        # Then google
        uri = Lp().art.get_google_search_uri(self.__get_current_search())
        helper = TaskHelper()
        helper.load_uri_content(uri, self.__cancellable,
                                self.__on_google_content_loaded)
 def _get_spotify_artist_artwork_uri(self, artist, cancellable=None):
     """
         Return spotify artist information
         @param artist as str
         @param cancellable as Gio.Cancellable
         @return uri as str
         @tread safe
     """
     if not get_network_available("SPOTIFY"):
         return None
     try:
         artist_formated = GLib.uri_escape_string(artist, None,
                                                  True).replace(" ", "+")
         uri = "https://api.spotify.com/v1/search?q=%s" % artist_formated +\
               "&type=artist"
         token = "Bearer %s" % self.__get_spotify_token(cancellable)
         helper = TaskHelper()
         helper.add_header("Authorization", token)
         (status, data) = helper.load_uri_content_sync(uri, cancellable)
         if status:
             uri = None
             decode = json.loads(data.decode("utf-8"))
             for item in decode["artists"]["items"]:
                 if noaccents(item["name"].lower()) ==\
                         noaccents(artist.lower()):
                     uri = item["images"][0]["url"]
                     return uri
     except Exception as e:
         Logger.debug(
             "ArtDownloader::_get_spotify_artist_artwork_uri(): %s" % e)
     return None
示例#11
0
 def _on_new_btn_clicked(self, button):
     """
         Create a new playlist based on search
         @param button as Gtk.Button
     """
     helper = TaskHelper()
     helper.run(self.__new_playlist)
示例#12
0
    def _on_delete_confirm(self, button):
        """
            Delete tracks after confirmation
            @param button as Gtk.Button
        """
        selection = self.__view.get_selection()
        selected = selection.get_selected_rows()[1]
        rows = []
        for item in selected:
            rows.append(Gtk.TreeRowReference.new(self.__model, item))

        tracks = []
        for row in rows:
            iterator = self.__model.get_iter(row.get_path())
            track = Track(self.__model.get_value(iterator, 3))
            tracks.append(track)
            if self.__playlist_id == Type.LOVED and Lp().lastfm is not None:
                if track.album.artist_id == Type.COMPILATIONS:
                    artist_name = ", ".join(track.artists)
                else:
                    artist_name = ", ".join(track.album.artists)
                helper = TaskHelper()
                helper.run(Lp().lastfm.unlove, artist_name, track.name)
            self.__model.remove(iterator)
        Lp().playlists.remove_tracks(self.__playlist_id, tracks)
        self.__infobar.hide()
        self.__unselectall()
示例#13
0
 def populate(self):
     """
         populate view if needed
     """
     if len(self.__model) == 0:
         helper = TaskHelper()
         helper.run(self.__append_tracks, callback=(self.__append_track,))
示例#14
0
    def __on_track_moved(self, widget, dst, src, up):
        """
            Move track from src to row
            Recalculate track position
            @param widget as TracksWidget
            @param dst as int
            @param src as int
            @param up as bool
        """
        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)

        (src_widget, dst_widget, src_index, dst_index) = \
            self.__move_track(dst, src, up)
        self.__update_tracks()
        self.__update_position()
        self.__update_headers()
        self.__tracks_widget_left.update_indexes(1)
        self.__tracks_widget_right.update_indexes(len(self.__tracks_left) + 1)
        helper = TaskHelper()
        helper.run(update_playlist)
 def __download_wikia_lyrics(self):
     """
         Downloas lyrics from wikia
     """
     self.__downloads_running += 1
     # Update lyrics
     if self.__current_track.id == Type.RADIOS:
         split = self.__current_track.name.split(" - ")
         if len(split) < 2:
             return
         artist = GLib.uri_escape_string(split[0], None, False)
         title = GLib.uri_escape_string(split[1], None, False)
     else:
         if self.__current_track.artists:
             artist = GLib.uri_escape_string(
                 self.__current_track.artists[0], None, False)
         elif self.__current_track.album_artists:
             artist = self.__current_track.album_artists[0]
         else:
             artist = ""
         title = GLib.uri_escape_string(self.__current_track.name, None,
                                        False)
     uri = "https://lyrics.wikia.com/wiki/%s:%s" % (artist, title)
     helper = TaskHelper()
     helper.load_uri_content(uri, self.__cancellable,
                             self.__on_lyrics_downloaded, "lyricbox", "\n")
示例#16
0
 def search_similar_artists(self, spotify_id, cancellable):
     """
         Search similar artists
         @param spotify_id as str
         @param cancellable as Gio.Cancellable
     """
     try:
         while self.wait_for_token():
             if cancellable.is_cancelled():
                 raise Exception("cancelled")
             sleep(1)
         found = False
         token = "Bearer %s" % self.__token
         helper = TaskHelper()
         helper.add_header("Authorization", token)
         uri = "https://api.spotify.com/v1/artists/%s/related-artists" % \
               spotify_id
         (status, data) = helper.load_uri_content_sync(uri, cancellable)
         if status:
             decode = json.loads(data.decode("utf-8"))
             for item in decode["artists"]:
                 if cancellable.is_cancelled():
                     raise Exception("cancelled")
                 found = True
                 artist_name = item["name"]
                 cover_uri = item["images"][1]["url"]
                 GLib.idle_add(self.emit, "new-artist",
                               artist_name, cover_uri)
     except Exception as e:
         Logger.error("SpotifyHelper::search_similar_artists(): %s", e)
     if not found:
         GLib.idle_add(self.emit, "new-artist", None, None)
示例#17
0
 def __remove_from_playlist(self, action, variant, playlist_id):
     """
         Del from playlist
         @param SimpleAction
         @param GVariant
         @param object id as int
         @param is album as bool
         @param playlist id as int
     """
     def remove(playlist_id):
         tracks = []
         if isinstance(self._object, Album):
             track_ids = Lp().albums.get_track_ids(self._object.id,
                                                   self._object.genre_ids,
                                                   self._object.artist_ids)
             for track_id in track_ids:
                 tracks.append(Track(track_id))
         else:
             tracks = [Track(self._object.id)]
         Lp().playlists.remove_tracks(playlist_id, tracks)
         if playlist_id in Lp().player.get_user_playlist_ids():
             Lp().player.update_user_playlist(
                                  Lp().playlists.get_track_ids(playlist_id))
     helper = TaskHelper()
     helper.run(remove, playlist_id)
示例#18
0
    def init(self):
        """
            Init main application
        """
        self.settings = Settings.new()
        # Mount enclosing volume as soon as possible
        uris = self.settings.get_music_uris()
        try:
            for uri in uris:
                if uri.startswith("file:/"):
                    continue
                f = Gio.File.new_for_uri(uri)
                f.mount_enclosing_volume(Gio.MountMountFlags.NONE, None, None,
                                         None)
        except Exception as e:
            Logger.error("Application::init(): %s" % e)

        cssProviderFile = Gio.File.new_for_uri(
            "resource:///org/gnome/Lollypop/application.css")
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.db = Database()
        self.cache = CacheDatabase()
        self.playlists = Playlists()
        self.albums = AlbumsDatabase(self.db)
        self.artists = ArtistsDatabase(self.db)
        self.genres = GenresDatabase(self.db)
        self.tracks = TracksDatabase(self.db)
        self.player = Player()
        self.inhibitor = Inhibitor()
        self.scanner = CollectionScanner()
        self.notify = NotificationManager()
        self.task_helper = TaskHelper()
        self.art_helper = ArtHelper()
        self.art = Art()
        self.art.update_art_size()
        self.ws_director = DirectorWebService()
        self.ws_director.start()
        if not self.settings.get_value("disable-mpris"):
            from lollypop.mpris import MPRIS
            MPRIS(self)

        settings = Gtk.Settings.get_default()
        self.__gtk_dark = settings.get_property(
            "gtk-application-prefer-dark-theme")
        if not self.__gtk_dark:
            dark = self.settings.get_value("dark-ui")
            settings.set_property("gtk-application-prefer-dark-theme", dark)
        ApplicationActions.__init__(self)
        monitor = Gio.NetworkMonitor.get_default()
        if monitor.get_network_available() and\
                not monitor.get_network_metered() and\
                self.settings.get_value("recent-youtube-dl"):
            self.task_helper.run(install_youtube_dl)
示例#19
0
 def cache_artists_info(self):
     """
         Cache info for all artists
     """
     if self.__cache_artists_running:
         return
     self.__cache_artists_running = True
     helper = TaskHelper()
     helper.run(self.__cache_artists_info)
示例#20
0
 def get(self, search_items, cancellable, callback):
     """
         Get track for name
         @param search_items as [str]
         @param cancellable as Gio.Cancellable
         @param callback as callback
     """
     helper = TaskHelper()
     helper.run(self.__get, search_items, cancellable, callback=callback)
示例#21
0
 def copy_uri_to_cache(self, uri, name, size):
     """
         Copy uri to cache at size
         @param uri as str
         @param name as str
         @param size as int
         @thread safe
     """
     helper = TaskHelper()
     helper.load_uri_content(uri, None, self.__on_uri_content, name, size)
示例#22
0
 def __download_images(self):
     """
         Download and set image for TuneItem
         @thread safe
     """
     if self.__covers_to_download and not self.__cancellable.is_cancelled():
         (item, image) = self.__covers_to_download.pop(0)
         helper = TaskHelper()
         helper.load_uri_content(item.LOGO, self.__cancellable,
                                 self.__on_image_downloaded, image)
示例#23
0
 def populate(self):
     """
         Populate view with tracks from playlist
     """
     Lp().player.set_radios(self.__radios_manager.get())
     if Lp().player.current_track.id == Type.RADIOS:
         Lp().player.set_next()  # We force next update
         Lp().player.set_prev()  # We force prev update
     helper = TaskHelper()
     helper.run(self.__get_radios, callback=(self.__on_get_radios, ))
示例#24
0
 def __update_db(self, action=None, param=None):
     """
         Search for new music
         @param action as Gio.SimpleAction
         @param param as GLib.Variant
     """
     if self.window:
         helper = TaskHelper()
         helper.run(self.art.clean_all_cache)
         self.window.update_db()
示例#25
0
 def cache_album_art(self, album_id):
     """
         Download album artwork
         @param album id as int
     """
     if album_id in self.__albums_history:
         return
     if get_network_available():
         self.__albums_queue.append(album_id)
         if not self.__in_albums_download:
             helper = TaskHelper()
             helper.run(self.__cache_albums_art)
示例#26
0
 def __populate(self, uris):
     """
         Add uris to view
         @param uris as [str]
     """
     if uris:
         uri = uris.pop(0)
         helper = TaskHelper()
         helper.load_uri_content(uri, self.__cancellable, self.__add_pixbuf,
                                 self.__populate, uris)
     elif len(self.__view.get_children()) == 0:
         self.__stack.set_visible_child_name("notfound")
示例#27
0
 def now_playing(self, artist, album, title, duration):
     """
         Now playing track
         @param artist as str
         @param title as str
         @param album as str
         @param duration as int
     """
     if get_network_available() and\
        self.__is_auth and Secret is not None:
         helper = TaskHelper()
         helper.run(self.__now_playing, artist, album, title, duration)
示例#28
0
 def do_scrobble(self, artist, album, title, timestamp):
     """
         Scrobble track
         @param artist as str
         @param title as str
         @param album as str
         @param timestamp as int
         @param duration as int
     """
     if get_network_available() and\
        self.__is_auth and Secret is not None:
         helper = TaskHelper()
         helper.run(self.__scrobble, artist, album, title, timestamp)
示例#29
0
    def save_album_artwork(self, data, album_id):
        """
            Save data for album id
            @param data as bytes
            @param album id as int
        """
        try:
            album = Album(album_id)
            arturi = None
            save_to_tags = Lp().settings.get_value("save-to-tags")
            uri_count = Lp().albums.get_uri_count(album.uri)
            filename = self.get_album_cache_name(album) + ".jpg"
            if save_to_tags:
                helper = TaskHelper()
                helper.run(self.__save_artwork_tags, data, album)

            store_path = self._STORE_PATH + "/" + filename
            if album.uri == "" or is_readonly(album.uri):
                arturi = GLib.filename_to_uri(store_path)
            # Many albums with same path, suffix with artist_album name
            elif uri_count > 1:
                arturi = album.uri + "/" + filename
                favorite_uri = album.uri + "/" + self.__favorite
                favorite = Gio.File.new_for_uri(favorite_uri)
                if favorite.query_exists():
                    favorite.trash()
            else:
                arturi = album.uri + "/" + self.__favorite
            # Save cover to uri
            dst = Gio.File.new_for_uri(arturi)
            if not save_to_tags or dst.query_exists():
                bytes = GLib.Bytes(data)
                stream = Gio.MemoryInputStream.new_from_bytes(bytes)
                bytes.unref()
                pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(
                                                               stream,
                                                               ArtSize.MONSTER,
                                                               ArtSize.MONSTER,
                                                               True,
                                                               None)
                stream.close()
                pixbuf.savev(store_path, "jpeg", ["quality"],
                             [str(Lp().settings.get_value(
                                                "cover-quality").get_int32())])
                dst = Gio.File.new_for_uri(arturi)
                src = Gio.File.new_for_path(store_path)
                src.move(dst, Gio.FileCopyFlags.OVERWRITE, None, None)
                self.clean_album_cache(album)
                GLib.idle_add(self.album_artwork_update, album.id)
        except Exception as e:
            print("Art::save_album_artwork(): %s" % e)
示例#30
0
 def charts(self, cancellable, language="global"):
     """
         Get albums related to search
         We need a thread because we are going to populate DB
         @param cancellable as Gio.Cancellable
         @param language as str
     """
     from csv import reader
     try:
         while self.wait_for_token():
             if cancellable.is_cancelled():
                 raise Exception("cancelled")
             sleep(1)
         token = "Bearer %s" % self.__token
         helper = TaskHelper()
         helper.add_header("Authorization", token)
         uri = self.__CHARTS % language
         spotify_ids = []
         (status, data) = helper.load_uri_content_sync(uri, cancellable)
         if status:
             decode = data.decode("utf-8")
             for line in decode.split("\n"):
                 try:
                     for row in reader([line]):
                         if not row:
                             continue
                         url = row[4]
                         if url == "URL":
                             continue
                         spotify_id = url.split("/")[-1]
                         if spotify_id:
                             spotify_ids.append(spotify_id)
                 except Exception as e:
                     Logger.warning("SpotifyHelper::charts(): %s", e)
         album_ids = []
         for spotify_id in spotify_ids:
             if cancellable.is_cancelled():
                 raise Exception("cancelled")
             payload = self.__get_track_payload(helper,
                                                spotify_id,
                                                cancellable)
             self.__create_albums_from_tracks_payload(
                                              [payload],
                                              album_ids,
                                              cancellable)
     except Exception as e:
         Logger.warning("SpotifyHelper::charts(): %s", e)
         # Do not emit search-finished on cancel
         if str(e) == "cancelled":
             return
     GLib.idle_add(self.emit, "search-finished")