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")
def _get_audiodb_album_artwork_uri(self, artist, album, cancellable=None): """ Get album artwork from audiodb @param artist as str @param album as str @param cancellable as Gio.Cancellable @return uri as str @thread safe """ if not get_network_available("AUDIODB"): return None try: album = GLib.uri_escape_string(album, None, True) artist = GLib.uri_escape_string(artist, None, True) uri = "https://theaudiodb.com/api/v1/json/" uri += "%s/searchalbum.php?s=%s&a=%s" % (AUDIODB_CLIENT_ID, artist, album) (status, data) = App().task_helper.load_uri_content_sync(uri, cancellable) if status: decode = json.loads(data.decode("utf-8")) if decode["album"]: for item in decode["album"]: uri = item["strAlbumThumb"] return uri except Exception as e: Logger.error("ArtDownloader::_get_audiodb_album_artwork_uri: %s" % e) return None
def _get_tracks_files(self): """ Return children uris for uri @return [str] """ children = [] dir_uris = [self._uri+'/tracks/'] while dir_uris: uri = dir_uris.pop(0) album_name = uri.replace(self._uri+"/tracks/", "") album = GLib.uri_escape_string(album_name, "", False) d = Gio.File.new_for_uri(self._uri+"/tracks/"+album) infos = d.enumerate_children( 'standard::name,standard::type', Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, None) for info in infos: if info.get_file_type() == Gio.FileType.DIRECTORY: dir_uris.append(uri+info.get_name()) else: track = GLib.uri_escape_string(info.get_name(), "", False) children.append("%s/tracks/%s/%s" % (self._uri, album, track)) return children
def _on_map_lyrics(self, widget): """ Load on map @param widget as Gtk.Viewport """ self._on_child_unmap(widget) Lp().settings.set_value('infoswitch', GLib.Variant('s', 'lyrics')) self.__jump_button.hide() if self.__current_track.id is None: self.__current_track = Lp().player.current_track # First try to get lyrics from tags from lollypop.tagreader import TagReader reader = TagReader() try: info = reader.get_info(self.__current_track.uri) except: info = None lyrics = "" if info is not None: tags = info.get_tags() lyrics = reader.get_lyrics(tags) if lyrics or InfoPopover.WebView is None\ or not get_network_available(): label = Gtk.Label() label.set_vexpand(True) label.set_hexpand(True) label.set_margin_top(10) label.set_margin_end(10) label.show() widget.add(label) if lyrics: label.set_label(lyrics) elif not get_network_available(): string = GLib.markup_escape_text(_("Network access disabled")) label.get_style_context().add_class('dim-label') label.set_markup("<span font_weight='bold' size='xx-large'>" + string + "</span>") else: string = GLib.markup_escape_text( _("No lyrics found, please install gir1.2-webkit2-4.0")) label.get_style_context().add_class('dim-label') label.set_markup("<span font_weight='bold' size='xx-large'>" + string + "</span>") elif get_network_available(): title = self.__current_track.name if self.__current_track.id == Type.RADIOS: search = GLib.uri_escape_string(title, None, True) else: artists = ", ".join(Lp().player.current_track.artists) search = GLib.uri_escape_string(artists + " " + title, None, True) url = "http://genius.com/search?q=%s" % search # Delayed load due to WebKit memory loading and Gtk animation web = self.WebView(True, True) web.add_word('search') web.add_word('lyrics') web.show() widget.add(web) GLib.timeout_add(250, web.load, url, OpenLink.OPEN)
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) album_uri = "%s/tracks/%s_%s" % (self._uri, artist_name, album_name) track_name = GLib.uri_escape_string(GLib.basename(track.path), "", False) # Check extension, if not mp3, convert ext = os.path.splitext(track.path)[1] if ext != ".mp3" and self._convert: track_name = track_name.replace(ext, ".mp3") 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
def __on_decide_destination(self, download, filename, wanted_filename): """ Modify destination if needed @param download as WebKit2.Download @param filename as str @param wanted_filename as str """ filename = filename.replace("/", "_") extension = filename.split(".")[-1] if wanted_filename: # FIXME We should find a way to pass good extension, # fallback to avi if extension == filename: extension = "avi" filename = wanted_filename + "." + extension directory_uri = App().settings.get_value('download-uri').get_string() if not directory_uri: directory = GLib.get_user_special_dir( GLib.UserDirectory.DIRECTORY_DOWNLOAD) directory_uri = GLib.filename_to_uri(directory, None) destination_uri = "%s/%s" % (directory_uri, GLib.uri_escape_string(filename, None, False)) not_ok = True i = 1 try: while not_ok: f = Gio.File.new_for_uri(destination_uri) if f.query_exists(): extension_less = filename.replace(".%s" % extension, "") new_filename = "%s_%s.%s" % (extension_less, i, extension) destination_uri = "%s/%s" % (directory_uri, GLib.uri_escape_string( new_filename, None, False)) else: not_ok = False i += 1 except: # Fallback to be sure destination_uri = "%s/@@%s" % (directory_uri, GLib.uri_escape_string( filename, None, False)) webkit_uri = GLib.uri_unescape_string(destination_uri, None) download.set_destination(webkit_uri) self.emit('download-start', str(download)) # Notify user about download window = App().active_window if window is not None: window.toolbar.end.show_download(download)
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) album_uri = "%s/tracks/%s_%s" % (self._uri, artist_name, album_name) track_name = GLib.uri_escape_string(GLib.basename(track.path), "", False) # Check extension, if not mp3, convert ext = os.path.splitext(track.path)[1] if ext != ".mp3" and self._convert: track_name = track_name.replace(ext, ".mp3") 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
def get_artist_id(self, artist_name, cancellable): """ Get artist id @param artist_name as str @param cancellable as Gio.Cancellable @return str/None """ try: artist_name = GLib.uri_escape_string(artist_name, None, True).replace(" ", "+") token = App().ws_director.token_ws.get_token( "SPOTIFY", cancellable) bearer = "Bearer %s" % token headers = [("Authorization", bearer)] uri = "https://api.spotify.com/v1/search?q=%s&type=artist" %\ artist_name (status, data) = App().task_helper.load_uri_content_sync_with_headers( uri, headers, cancellable) if status: decode = json.loads(data.decode("utf-8")) for item in decode["artists"]["items"]: return item["id"] except Exception as e: Logger.error("SpotifyWebHelper::get_artist_id(): %s", e) return None
def tracks(self, name): """ Return tracks containing name @param name as str """ try: formated = GLib.uri_escape_string(name, None, True).replace( ' ', '+') s = Lio.File.new_for_uri("https://api.spotify.com/v1/search?q=%s" "&type=track" % formated) (status, data, tag) = s.load_contents(self._cancel) if status: decode = json.loads(data.decode('utf-8')) tracks = [] for item in decode['tracks']['items']: if item['name'].lower() in tracks: continue album_item = SearchItem() search_item = SearchItem() search_item.is_track = True search_item.name = item['name'] album_item.name = item['name'] search_item.album = album_item tracks.append(search_item.name.lower()) search_item.tracknumber = int(item['track_number']) search_item.discnumber = int(item['disc_number']) search_item.duration = int(item['duration_ms']) / 1000 search_item.cover = item['album']['images'][0]['url'] search_item.smallcover = item['album']['images'][2]['url'] for artist in item['artists']: search_item.artists.append(artist['name']) self._items.append(search_item) GLib.idle_add(self.emit, 'item-found') except Exception as e: print("SpotifySearch::tracks(): %s" % e)
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) s = Lio.File.new_for_uri("https://api.deezer.com/search/album/?" "q=%s&output=json" % album_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) url = None for item in decode['data']: if item['artist']['name'].lower() == artist.lower(): url = item['cover_xl'] break if url is not None: s = Lio.File.new_for_uri(url) (status, image, tag) = s.load_contents() except Exception as e: print("Downloader::__get_deezer_album_artwork: %s" % e) return image
def _get_spotify_artist_artwork_uri(self, artist, cancellable=None): """ Get artist artwork using Spotify @param artist as str @param cancellable as Gio.Cancellable @return uri as str @tread safe """ if not get_network_available("SPOTIFY"): return [] 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 = App().ws_director.token_ws.get_token("SPOTIFY", cancellable) bearer = "Bearer %s" % token headers = [("Authorization", bearer)] (status, data) = App().task_helper.load_uri_content_sync_with_headers( uri, headers, 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.warning("%s %s", e, artist) Logger.warning( "DownloaderArt::_get_spotify_artist_artwork_uri(): %s", data) return []
def __get_uris_to_copy(self, tracks): """ Get on device URI for all tracks @param tracks as [Track] """ uris = [] art_uris = [] for track in tracks: f = Gio.File.new_for_uri(track.uri) album_device_uri = "%s/%s" % ( self.__uri, self.__get_album_on_device_uri(track)) album_local_uri = f.get_parent().get_uri() src_uri = "%s/%s" % (album_local_uri, GLib.uri_escape_string( f.get_basename(), None, True)) dst_uri = "%s/%s" % (album_device_uri, escape(f.get_basename())) (convertion_needed, dst_uri) = self.__is_convertion_needed(src_uri, dst_uri) uris.append((src_uri, dst_uri)) art_uri = App().art.get_album_artwork_uri(track.album) if art_uri is not None: art_filename = Gio.File.new_for_uri(art_uri).get_basename() art_uris.append( (art_uri, "%s/%s" % (album_device_uri, escape(art_filename)))) return uris + art_uris
def _get_deezer_artist_artwork_uri(self, artist, cancellable=None): """ Return deezer artist information @param artist as str @param cancellable as Gio.Cancellable @return uri as str @tread safe """ if not get_network_available("DEEZER"): return None try: artist_formated = GLib.uri_escape_string(artist, None, True).replace(" ", "+") uri = "https://api.deezer.com/search/artist/?" +\ "q=%s&output=json&index=0&limit=1&" % artist_formated (status, data) = App().task_helper.load_uri_content_sync(uri, cancellable) if status: uri = None decode = json.loads(data.decode("utf-8")) uri = decode["data"][0]["picture_xl"] return uri except Exception as e: Logger.debug( "ArtDownloader::_get_deezer_artist_artwork_uri(): %s" % e) return None
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 tracks(self, name): """ Return tracks containing name @param name as str """ try: formated = GLib.uri_escape_string(name, None, True).replace(' ', '+') s = Gio.File.new_for_uri("https://api.spotify.com/v1/search?q=%s" "&type=track" % formated) (status, data, tag) = s.load_contents(self._cancel) if status: decode = json.loads(data.decode('utf-8')) tracks = [] for item in decode['tracks']['items']: if item['name'].lower() in tracks: continue search_item = SearchItem() search_item.is_track = True search_item.name = item['name'] tracks.append(search_item.name.lower()) search_item.album = item['album']['name'] search_item.tracknumber = int(item['track_number']) search_item.discnumber = int(item['disc_number']) search_item.duration = int(item['duration_ms']) / 1000 search_item.cover = item['album']['images'][0]['url'] search_item.smallcover = item['album']['images'][2]['url'] for artist in item['artists']: search_item.artists.append(artist['name']) self._items.append(search_item) GLib.idle_add(self.emit, 'item-found') except Exception as e: print("SpotifySearch::tracks(): %s" % e)
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 __get_youtube_id_fallback(self, item): """ Get youtube id (fallback) @param item as SearchItem @return youtube id as str """ try: from bs4 import BeautifulSoup except: print("$ sudo pip3 install beautifulsoup4") return None try: # Try to handle compilations (itunes one) if item.artists[0].lower() == "various artists": if len(item.artists) > 1: artist = item.artists[1] else: artist = "" else: artist = item.artists[0] unescaped = "%s %s" % (artist, item.name) search = GLib.uri_escape_string(unescaped.replace(' ', '+'), None, True) f = Gio.File.new_for_uri("https://www.youtube.com/" "results?search_query=%s" % search) (status, data, tag) = f.load_contents(None) if not status: return None html = data.decode('utf-8') soup = BeautifulSoup(html, 'html.parser') ytems = [] for link in soup.findAll('a'): href = link.get('href') title = link.get('title') if href is None or title is None: continue if href.startswith("/watch?v="): href = href.replace("/watch?v=", "") ytems.append((href, title)) dic = {} best = self.__BAD_SCORE for (yid, title) in ytems: score = self.__get_youtube_score(title, item.name, artist, item.album) if score < best: best = score elif score == best: continue # Keep first result dic[score] = yid # Return url from first dic item if best == self.__BAD_SCORE: return None else: return dic[best] except Exception as e: print("Youtube::__get_youtube_id_fallback():", e) self.__fallback = True return None
def _on_map_lyrics(self, widget): """ Load on map @param widget as Gtk.Viewport """ self._on_child_unmap(widget) Lp().settings.set_value('infoswitch', GLib.Variant('s', 'lyrics')) self.__jump_button.hide() if self.__current_track.id is None: self.__current_track = Lp().player.current_track # First try to get lyrics from tags from lollypop.tagreader import TagReader reader = TagReader() try: info = reader.get_info(self.__current_track.uri) except: info = None lyrics = "" if info is not None: tags = info.get_tags() lyrics = reader.get_lyrics(tags) if lyrics or InfoPopover.WebView is None\ or not get_network_available(): label = Gtk.Label() label.set_vexpand(True) label.set_hexpand(True) label.set_margin_top(10) label.set_margin_end(10) label.show() widget.add(label) if lyrics: label.set_label(lyrics) elif not get_network_available(): string = GLib.markup_escape_text(_("Network access disabled")) label.get_style_context().add_class('dim-label') label.set_markup( "<span font_weight='bold' size='xx-large'>" + string + "</span>") else: string = GLib.markup_escape_text( _("No lyrics found, please install gir1.2-webkit2-4.0")) label.get_style_context().add_class('dim-label') label.set_markup( "<span font_weight='bold' size='xx-large'>" + string + "</span>") elif get_network_available(): artists = ", ".join(Lp().player.current_track.artists) title = self.__current_track.name search = GLib.uri_escape_string(artists + " " + title, None, True) url = "http://genius.com/search?q=%s" % search # Delayed load due to WebKit memory loading and Gtk animation web = self.WebView(True, True) web.add_word('search') web.add_word('lyrics') web.show() widget.add(web) GLib.timeout_add(250, web.load, url, OpenLink.OPEN)
def get_duck_arts(self, search): """ Get arts on duck image corresponding to search @param search words as string @return [urls as string] """ data = None urls = [] if not Gio.NetworkMonitor.get_default().get_network_available(): return [] try: f = Gio.File.new_for_uri("https://duckduckgo.com/i.js" "?q=%s&ia=images" % (GLib.uri_escape_string(search, "", False),)) (status, data, tag) = f.load_contents() if not status: return [] except Exception as e: print(e) return [] try: decode = json.loads(data.decode('utf-8')) if decode is None: return urls for item in decode['results']: urls.append(item['image']) except: pass return urls
def tracks(self, name): """ Return tracks containing name @param name as str """ try: formated = GLib.uri_escape_string(name, None, True).replace(' ', '+') s = Lio.File.new_for_uri("https://itunes.apple.com/search" "?entity=musicTrack&term=%s" % formated) (status, data, tag) = s.load_contents(self._cancel) if status: decode = json.loads(data.decode('utf-8')) tracks = [] for item in decode['results']: if item['trackName'].lower() in tracks: continue album_item = SearchItem() album_item.name = item['collectionName'] search_item = SearchItem() search_item.is_track = True search_item.name = item['trackName'] tracks.append(search_item.name.lower()) search_item.album = album_item search_item.tracknumber = int(item['trackNumber']) search_item.discnumber = int(item['discNumber']) search_item.duration = int(item['trackTimeMillis']) / 1000 search_item.cover = item['artworkUrl60'].replace( '60x60', '512x512') search_item.smallcover = item['artworkUrl100'] search_item.artists.append(item['artistName']) self._items.append(search_item) GLib.idle_add(self.emit, 'item-found') except Exception as e: print("SpotifySearch::tracks(): %s" % e)
def _get_album_art_itunes(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(' ', '+') s = Gio.File.new_for_uri("https://itunes.apple.com/search" "?entity=album&term=%s" % album_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) for item in decode['results']: if item['artistName'].lower() == artist.lower(): url = item['artworkUrl60'].replace('60x60', '512x512') s = Gio.File.new_for_uri(url) (status, image, tag) = s.load_contents() break except Exception as e: print("ArtDownloader::_get_album_art_itunes: %s [%s/%s]" % (e, artist, album)) return image
def _get_album_art_itunes(self, artist, album): """ Get album artwork from itunes @param artist as string @param album as string @return pixbuf as GdkPixbuf.Pixbuf @tread safe """ pixbuf = None try: album_formated = GLib.uri_escape_string( album, None, True).replace(' ', '+') s = Gio.File.new_for_uri("https://itunes.apple.com/search" "?entity=album&term=%s" % album_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) for item in decode['results']: if item['artistName'].lower() == artist.lower(): url = item['artworkUrl60'].replace('60x60', '512x512') s = Gio.File.new_for_uri(url) (status, data, tag) = s.load_contents() if status: stream = Gio.MemoryInputStream.new_from_data(data, None) pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, ArtSize.MONSTER, ArtSize.MONSTER, False, None) break except Exception as e: print("ArtDownloader::_get_album_art_itunes: %s" % e) return pixbuf
def _get_audiodb_artist_info(self, artist): """ Get artist info from audiodb @param artist as str @return info as bytes """ if not get_network_available("AUDIODB"): return None try: artist = GLib.uri_escape_string(artist, None, True) uri = "https://theaudiodb.com/api/v1/json/" uri += "%s/search.php?s=%s" % (AUDIODB_CLIENT_ID, artist) (status, data) = App().task_helper.load_uri_content_sync(uri, None) if status: decode = json.loads(data.decode("utf-8")) language = getdefaultlocale()[0][-2:] for item in decode["artists"]: for key in ["strBiography%s" % language, "strBiographyEN"]: info = item[key] if info is not None: return info.encode("utf-8") except Exception as e: Logger.error("InfoDownloader::_get_audiodb_artist_info: %s, %s" % (e, artist)) return None
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(' ', '+') s = Gio.File.new_for_uri("https://itunes.apple.com/search" "?entity=album&term=%s" % album_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) for item in decode['results']: if item['artistName'].lower() == artist.lower(): url = item['artworkUrl60'].replace('60x60', '512x512') s = Gio.File.new_for_uri(url) (status, image, tag) = s.load_contents() break except Exception as e: print("Downloader::_get_album_art_itunes: %s [%s/%s]" % (e, artist, album)) return image
def get_google_arts(self, search): """ Get arts on duck image corresponding to search @param search words as string @return [urls as string] """ data = None urls = [] if not get_network_available(): return [] cs_api_key = Lp().settings.get_value('cs-api-key').get_string() try: f = Lio.File.new_for_uri("https://www.googleapis.com/" "customsearch/v1?key=%s&cx=%s" "&q=%s&searchType=image" % (cs_api_key, GOOGLE_API_ID, GLib.uri_escape_string(search, "", False))) (status, data, tag) = f.load_contents() if status: decode = json.loads(data.decode('utf-8')) if decode is None: return urls for item in decode['items']: urls.append(item['link']) except Exception as e: print(e) return urls
def __fallback(self, current_search): """ Fallback google image search, low quality @param current search as str """ try: from bs4 import BeautifulSoup except: print("$ sudo pip3 install beautifulsoup4") return urls = [] GLib.idle_add(self._label.set_text, _("Low quality, missing API key…")) try: for search in self.__get_current_searches(): url = "https://www.google.fr/search?q=%s&tbm=isch" %\ GLib.uri_escape_string(search, None, True) f = Lio.File.new_for_uri(url) (status, data, tag) = f.load_contents() if status: html = data.decode("utf-8") soup = BeautifulSoup(html, "html.parser") for link in soup.findAll("img"): try: urls.append(link.attrs["data-src"]) except: pass except Exception as e: print("ArtworkSearch::__fallback: %s" % e) self.__add_pixbufs(urls, current_search)
def get_duck_arts(self, search): """ Get arts on duck image corresponding to search @param search words as string @return [urls as string] """ data = None urls = [] if not Gio.NetworkMonitor.get_default().get_network_available(): return [] try: f = Gio.File.new_for_uri( "https://duckduckgo.com/i.js" "?q=%s&ia=images" % (GLib.uri_escape_string(search, "", False), )) (status, data, tag) = f.load_contents() if not status: return [] except Exception as e: print(e) return [] try: decode = json.loads(data.decode('utf-8')) if decode is None: return urls for item in decode['results']: urls.append(item['image']) except: pass return urls
def _get_deezer_album_artwork_uri(self, artist, album, cancellable=None): """ Get album artwork uri from deezer @param artist as str @param album as str @param cancellable as Gio.Cancellable @return uri as str @tread safe """ if not get_network_available("DEEZER"): return None try: album_formated = GLib.uri_escape_string(album, None, True) uri = "https://api.deezer.com/search/album/?" +\ "q=%s&output=json" % album_formated (status, data) = App().task_helper.load_uri_content_sync(uri, cancellable) if status: decode = json.loads(data.decode("utf-8")) uri = None for item in decode["data"]: if noaccents(item["artist"]["name"].lower()) ==\ noaccents(artist.lower()): uri = item["cover_xl"] return uri except Exception as e: Logger.error("ArtDownloader::__get_deezer_album_artwork_uri: %s" % e) return None
def __init__(self, item): """ Init row @param item as Item """ Gtk.ListBoxRow.__init__(self) self.__item = item value = GLib.uri_escape_string(item.get_property("value"), None, True) markup = "%s <b>%s</b>" % (item.get_property("name"), value) self.__label = Gtk.Label() self.__label.set_markup(markup) self.__label.set_max_width_chars(20) self.__label.set_property("halign", Gtk.Align.START) self.__label.show() eventbox = Gtk.EventBox() eventbox.show() eventbox.add(self.__label) self.add(eventbox) self.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, [], Gdk.DragAction.MOVE) self.drag_source_add_text_targets() self.connect("drag-data-get", self.__on_drag_data_get) self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION, [], Gdk.DragAction.MOVE) self.drag_dest_add_text_targets() self.connect("drag-data-received", self.__on_drag_data_received) self.connect("drag-motion", self.__on_drag_motion) self.connect("drag-leave", self.__on_drag_leave)
def __fallback(self, current_search): """ Fallback google image search, low quality @param current search as str """ try: from bs4 import BeautifulSoup except: print("$ sudo pip3 install beautifulsoup4") return urls = [] GLib.idle_add(self._label.set_text, _("Low quality, missing API key…")) try: for search in self.__get_current_searches(): url = "https://www.google.fr/search?q=%s&tbm=isch" %\ GLib.uri_escape_string(search, None, True) f = Lio.File.new_for_uri(url) (status, data, tag) = f.load_contents() if status: html = data.decode('utf-8') soup = BeautifulSoup(html, 'html.parser') for link in soup.findAll('img'): try: urls.append(link.attrs['data-src']) except: pass except Exception as e: print("ArtworkSearch::__fallback: %s" % e) self.__add_pixbufs(urls, current_search)
def _get_itunes_album_artwork_uri(self, artist, album, cancellable=None): """ Get album artwork uri from itunes @param artist as str @param album as str @param cancellable as Gio.Cancellable @return uri as str @tread safe """ if not get_network_available("ITUNES"): return None try: album_formated = GLib.uri_escape_string(album, None, True).replace(" ", "+") uri = "https://itunes.apple.com/search" +\ "?entity=album&term=%s" % album_formated (status, data) = App().task_helper.load_uri_content_sync(uri, cancellable) if status: decode = json.loads(data.decode("utf-8")) for item in decode["results"]: if noaccents(item["artistName"].lower()) ==\ noaccents(artist.lower()): uri = item["artworkUrl60"].replace( "60x60", "1024x1024") return uri except Exception as e: Logger.error("ArtDownloader::_get_album_art_itunes_uri: %s" % e) return None
def _get_audiodb_artist_artwork_uri(self, artist, cancellable=None): """ Get artist artwork using AutdioDB @param artist as str @param cancellable as Gio.Cancellable @return uri as str @thread safe """ if not get_network_available("AUDIODB"): return [] try: artist = GLib.uri_escape_string(artist, None, True) uri = "https://theaudiodb.com/api/v1/json/" uri += "%s/search.php?s=%s" % (AUDIODB_CLIENT_ID, artist) (status, data) = App().task_helper.load_uri_content_sync( uri, cancellable) if status: decode = json.loads(data.decode("utf-8")) uri = None for item in decode["artists"]: for key in ["strArtistFanart", "strArtistThumb"]: uri = item[key] if uri is not None: return [uri] except Exception as e: Logger.warning("%s %s", e, artist) Logger.warning( "DownloaderArt::_get_audiodb_artist_artwork_uri: %s", data) return []
def get_artist_id(self, artist_name, callback): """ Get artist id @param artist_name as str @param callback as function """ if self.wait_for_token(): GLib.timeout_add( 500, self.get_artist_id, artist_name, callback) return try: def on_content(uri, status, data): found = False if status: decode = json.loads(data.decode("utf-8")) for item in decode["artists"]["items"]: found = True artist_id = item["uri"].split(":")[-1] callback(artist_id) return if not found: callback(None) artist_name = GLib.uri_escape_string( artist_name, None, True).replace(" ", "+") token = "Bearer %s" % self.__token helper = TaskHelper() helper.add_header("Authorization", token) uri = "https://api.spotify.com/v1/search?q=%s&type=artist" %\ artist_name helper.load_uri_content(uri, None, on_content) except Exception as e: Logger.error("SpotifyHelper::get_artist_id(): %s", e) callback(None)
def tracks(self, name): """ Return tracks containing name @param name as str """ try: formated = GLib.uri_escape_string(name, None, True).replace( " ", "+") s = Lio.File.new_for_uri("https://api.spotify.com/v1/search?q=%s" "&type=track" % formated) (status, data, tag) = s.load_contents(self._cancel) if status: decode = json.loads(data.decode("utf-8")) tracks = [] for item in decode["tracks"]["items"]: if item["name"].lower() in tracks: continue album_item = SearchItem() search_item = SearchItem() search_item.is_track = True search_item.name = item["name"] album_item.name = item["name"] search_item.album = album_item tracks.append(search_item.name.lower()) search_item.tracknumber = int(item["track_number"]) search_item.discnumber = int(item["disc_number"]) search_item.duration = int(item["duration_ms"]) / 1000 search_item.cover = item["album"]["images"][0]["url"] search_item.smallcover = item["album"]["images"][2]["url"] for artist in item["artists"]: search_item.artists.append(artist["name"]) self._items.append(search_item) GLib.idle_add(self.emit, "item-found") except Exception as e: print("SpotifySearch::tracks(): %s" % e)
def archive_open(path): """ Opens the archive @path as a GFile representing it as a directory. @path must be a local path (for the moment). """ # This is crazy, but it's the only way to get it working: # 1. get a URI with special characters escaped. This makes sense. # 2. escape that result, so it can be part of the archive:// URI. More tricky, # but still makes some sense. # 3. escape the URI a *3rd* time, getting e.g. "/" to %253A. Things that got # escaped in step 1 are then escaped 3 times (e.g. "é" becomes %2525A9). # GOD WHY!?? # 4. make all this an archive:// URI uri = GLib.filename_to_uri(path) for i in range(2): # WTF, seriously!?? uri = GLib.uri_escape_string(uri, None, False) uri = 'archive://' + uri print(uri) zf = Gio.File.new_for_uri(uri) zf._was_already_mounted = False try: func = synchronize_async( type(zf).mount_enclosing_volume, type(zf).mount_enclosing_volume_finish) func(zf, Gio.MountMountFlags.NONE, None, None) except GLib.Error as ex: if ex.matches(GLib.quark_from_string('g-io-error-quark'), Gio.IOErrorEnum.ALREADY_MOUNTED): zf._was_already_mounted = True else: raise return zf
def get_google_arts(self, search): """ Get arts on duck image corresponding to search @param search words as string @return [urls as string] """ data = None urls = [] if not get_network_available(): return [] cs_api_key = Lp().settings.get_value("cs-api-key").get_string() try: f = Lio.File.new_for_uri("https://www.googleapis.com/" "customsearch/v1?key=%s&cx=%s" "&q=%s&searchType=image" % (cs_api_key, GOOGLE_API_ID, GLib.uri_escape_string(search, "", False))) (status, data, tag) = f.load_contents() if status: decode = json.loads(data.decode("utf-8")) if decode is None: return urls for item in decode["items"]: urls.append(item["link"]) except Exception as e: print(e) return urls
def _get_album_art_itunes(self, artist, album): """ Get album artwork from itunes @param artist as string @param album as string @return pixbuf as GdkPixbuf.Pixbuf @tread safe """ pixbuf = None try: album_formated = GLib.uri_escape_string(album, None, True).replace(' ', '+') s = Gio.File.new_for_uri("https://itunes.apple.com/search" "?entity=album&term=%s" % album_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) for item in decode['results']: if item['artistName'].lower() == artist.lower(): url = item['artworkUrl60'].replace('60x60', '512x512') s = Gio.File.new_for_uri(url) (status, data, tag) = s.load_contents() if status: stream = Gio.MemoryInputStream.new_from_data( data, None) pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, ArtSize.MONSTER, ArtSize.MONSTER, False, None) break except Exception as e: print("ArtDownloader::_get_album_art_itunes: %s" % e) return pixbuf
def tracks(self, name): """ Return tracks containing name @param name as str """ try: formated = GLib.uri_escape_string(name, None, True).replace( ' ', '+') s = Lio.File.new_for_uri("https://itunes.apple.com/search" "?entity=musicTrack&term=%s" % formated) (status, data, tag) = s.load_contents(self._cancel) if status: decode = json.loads(data.decode('utf-8')) tracks = [] for item in decode['results']: if item['trackName'].lower() in tracks: continue album_item = SearchItem() album_item.name = item['collectionName'] search_item = SearchItem() search_item.is_track = True search_item.name = item['trackName'] tracks.append(search_item.name.lower()) search_item.album = album_item search_item.tracknumber = int(item['trackNumber']) search_item.discnumber = int(item['discNumber']) search_item.duration = int(item['trackTimeMillis']) / 1000 search_item.cover = item['artworkUrl60'].replace('60x60', '512x512') search_item.smallcover = item['artworkUrl100'] search_item.artists.append(item['artistName']) self._items.append(search_item) GLib.idle_add(self.emit, 'item-found') except Exception as e: print("SpotifySearch::tracks(): %s" % e)
def __on_report_activate(self, action, param): """ Launch bug report page @param action as Gio.SimpleAction @param param as GLib.Variant """ argv = ["uname", "-a", None] (s, o, e, s) = GLib.spawn_sync(None, argv, None, GLib.SpawnFlags.SEARCH_PATH, None) if o: os = o.decode("utf-8") else: os = "Unknown" github = "https://github.com/gnumdk/eolie/issues/new?body=" body = """ TRANSLATORS: https://translate.zanata.org/project/view/eolie ### Environment - Eolie version: %s - GTK+ version: %s.%s - Operating system: %s ### Bug/Feature If your bug is a rendering bug or a WebKit crash, you should report it here: https://bugs.webkit.org -> Section WebKit Gtk -> title starting with [GTK] <Describe your bug here>""" % (self.__version, Gtk.get_major_version(), Gtk.get_minor_version(), os) url = github + GLib.uri_escape_string(body, "", False) self.active_window.container.add_webview(url, LoadingType.FOREGROUND, False)
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) s = Gio.File.new_for_uri("https://api.deezer.com/search/album/?" "q=%s&output=json" % album_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) url = None for item in decode['data']: if item['artist']['name'].lower() == artist.lower(): url = item['cover_xl'] break if url is not None: s = Gio.File.new_for_uri(url) (status, image, tag) = s.load_contents() except Exception as e: print("Downloader::__get_deezer_album_artwork: %s" % e) return image
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
def __get_youtube_id(self, item): """ Get youtube id @param item as SearchItem @return youtube id as str """ if self.__fallback: return self.__get_youtube_id_fallback(item) # Try to handle compilations (itunes one) if item.artists[0].lower() == "various artists": if len(item.artists) > 1: artist = item.artists[1] else: artist = "" else: artist = item.artists[0] unescaped = "%s %s" % (artist, item.name) search = GLib.uri_escape_string( unescaped.replace(' ', '+'), None, True) key = Lp().settings.get_value('cs-api-key').get_string() try: f = Gio.File.new_for_uri("https://www.googleapis.com/youtube/v3/" "search?part=snippet&q=%s&" "type=video&key=%s&cx=%s" % ( search, key, GOOGLE_API_ID)) (status, data, tag) = f.load_contents(None) if status: decode = json.loads(data.decode('utf-8')) dic = {} best = self.__BAD_SCORE for i in decode['items']: score = self.__get_youtube_score(i['snippet']['title'], item.name, artist, item.album) if score < best: best = score elif score == best: continue # Keep first result dic[score] = i['id']['videoId'] # Return url from first dic item if best == self.__BAD_SCORE: return None else: return dic[best] except IndexError: pass except Exception as e: print("WebYouTube::__get_youtube_id():", e) self.__fallback = True return self.__get_youtube_id_fallback(item) return None
def __on_search_timeout(self, string): """ Populate widget @param string as str """ self.__timeout_id = None url = "http://opml.radiotime.com/Search.ashx?query=%s" %\ GLib.uri_escape_string(string, "/", False) self.populate(url)
def _append_playlists(self, playlists): """ Append a playlist @param playlists as [(int, str)] @param playlist selected as bool """ for playlist in playlists: playlist_name = GLib.uri_escape_string(playlist[1], "", False) playlist_obj = Gio.File.new_for_uri(self._uri + "/" + playlist_name + '.m3u') selected = playlist_obj.query_exists(None) self._model.append([selected, playlist[1], playlist[0]])
def __get_albums(self, name): """ Get albums for name @param name as str """ try: # Read album list formated = GLib.uri_escape_string(name, None, True).replace( ' ', '+') s = Lio.File.new_for_uri("https://itunes.apple.com/search" "?entity=album&term=%s" % formated) (status, data, tag) = s.load_contents(self._cancel) if not status: raise decode = json.loads(data.decode('utf-8')) # For each album, get cover and tracks for item in decode['results']: album_item = SearchItem() album_item.name = item['collectionName'] album_item.is_track = False album_item.artists = [item['artistName']] album_item.cover = item['artworkUrl60'].replace('60x60', '512x512') album_item.smallcover = item['artworkUrl100'] s = Lio.File.new_for_uri("https://itunes.apple.com/lookup" "?id=%s&entity=song" % item['collectionId']) (status, data, tag) = s.load_contents(self._cancel) if not status: raise decode = json.loads(data.decode('utf-8')) for item in decode['results']: if item['wrapperType'] == "collection": continue track_item = SearchItem() track_item.is_track = True try: track_item.year = decode['releaseDate'][:4] except: pass # May be missing track_item.name = item['trackName'] track_item.album = album_item track_item.tracknumber = int(item['trackNumber']) track_item.discnumber = int(item['discNumber']) track_item.duration = int(item['trackTimeMillis'])\ / 1000 track_item.artists.append(item['artistName']) album_item.subitems.append(track_item) self._items.append(album_item) GLib.idle_add(self.emit, 'item-found') except Exception as e: print("ItunesSearch::__get_albums(): %s" % e)
def __append_playlists(self, playlists): """ Append a playlist @param playlists as [(int, str)] """ if playlists and not self.__stop: playlist = playlists.pop(0) playlist_name = GLib.uri_escape_string(playlist[1], "", False) playlist_obj = Gio.File.new_for_uri(self._uri + "/" + playlist_name + '.m3u') selected = playlist_obj.query_exists() self.__model.append([selected, playlist[1], playlist[0]]) GLib.idle_add(self.__append_playlists, playlists)
def _append_playlists(self, playlists): """ Append a playlist @param playlists as [(int, str)] @param playlist selected as bool """ if playlists: playlist = playlists.pop(0) playlist_name = GLib.uri_escape_string(playlist[1], "", False) selected = playlist_name + ".m3u" in self._on_disk_playlists self._model.append([selected, playlist[1], playlist[0]]) GLib.idle_add(self._append_playlists, playlists) else: self._view.get_selection().unselect_all()
def __get_albums(self, name): """ Get albums for name @param name as str """ try: # Read album list formated = GLib.uri_escape_string(name, None, True).replace( ' ', '+') s = Lio.File.new_for_uri("https://api.spotify.com/v1/search?q=%s" "&type=album" % formated) (status, data, tag) = s.load_contents(self._cancel) if status: decode = json.loads(data.decode('utf-8')) # For each album, get cover and tracks for item in decode['albums']['items']: album_item = SearchItem() album_item.name = item['name'] album_item.is_track = False album_item.cover = item['images'][0]['url'] album_item.smallcover = item['images'][2]['url'] s = Lio.File.new_for_uri("https://api.spotify.com/v1/" "albums/%s" % item['id']) (status, data, tag) = s.load_contents(self._cancel) if status: decode = json.loads(data.decode('utf-8')) for item in decode['tracks']['items']: track_item = SearchItem() track_item.is_track = True try: track_item.year = decode[ 'release_date'][:4] except: pass # May be missing track_item.name = item['name'] track_item.album = album_item track_item.tracknumber = int(item['track_number']) track_item.discnumber = int(item['disc_number']) track_item.duration = int(item['duration_ms'])\ / 1000 for artist in item['artists']: track_item.artists.append(artist['name']) if not album_item.artists: album_item.artists = track_item.artists album_item.subitems.append(track_item) self._items.append(album_item) GLib.idle_add(self.emit, 'item-found') except Exception as e: print("SpotifySearch::albums(): %s" % e)
def _get_album_art_spotify(self, artist, album): """ Get album artwork from itunes @param artist as string @param album as string @return pixbuf as GdkPixbuf.Pixbuf @tread safe """ pixbuf = None artists_spotify_ids = [] try: artist_formated = GLib.uri_escape_string( artist, None, True).replace(' ', '+') s = Gio.File.new_for_uri("https://api.spotify.com/v1/search?q=%s" "&type=artist" % artist_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) for item in decode['artists']['items']: artists_spotify_ids.append(item['id']) for artist_spotify_id in artists_spotify_ids: s = Gio.File.new_for_uri("https://api.spotify.com/v1/artists/" "%s/albums" % artist_spotify_id) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) url = None for item in decode['items']: if item['name'] == album: url = item['images'][0]['url'] break if url is not None: s = Gio.File.new_for_uri(url) (status, data, tag) = s.load_contents() if status: stream = Gio.MemoryInputStream.new_from_data(data, None) pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, ArtSize.MONSTER, ArtSize.MONSTER, False, None) break except Exception as e: print("ArtDownloader::_get_album_art_spotify: %s" % e) return pixbuf
def _append_playlists(self, playlists): """ Append a playlist @param playlists as [(int, str)] @param playlist selected as bool """ if playlists: playlist = playlists.pop(0) playlist_name = GLib.uri_escape_string(playlist[1], "", False) playlist_obj = Gio.File.new_for_uri(self._uri + "/" + playlist_name + '.m3u') selected = playlist_obj.query_exists(None) self._model.append([selected, playlist[1], playlist[0]]) GLib.idle_add(self._append_playlists, playlists) else: self._view.get_selection().unselect_all()
def __get_jgm_id(self, item): """ Get jmg id @param item as SearchItem @return jpg id as str """ # Try to handle compilations (itunes one) unwanted = ["variout artists", "multi-interprètes"] if item.artists[0].lower() in unwanted: if len(item.artists) > 1: artist = item.artists[1] else: artist = "" else: artist = item.artists[0] unescaped = "%s %s" % (artist, item.name) for c in ['/', '?', '!']: if c in unescaped: unescaped = unescaped.replace(c, ' ') search = GLib.uri_escape_string(unescaped, '', True) try: # Strip /? as API doesn't like it f = Lio.File.new_for_uri("http://app.jgm90.com/cmapi/search/" "%s/1/10" % search.strip('/?')) (status, data, tag) = f.load_contents(None) if status: decode = json.loads(data.decode('utf-8')) for song in decode['result']['songs']: try: song_artist = escape( song['artists'][0]['name'].lower()) if song_artist == escape(artist.lower()): return song['id'] except Exception as e: print("WebJmg90::__get_jmg_id():", e) except IndexError: pass except KeyError: pass except Exception as e: print("WebJmg90::__get_jmg_id():", e) return None
def get_spotify_artist_artwork(self, artist): """ Return spotify artwork url @param artist as str @return url as str/None """ try: artist_formated = GLib.uri_escape_string( artist, None, True).replace(' ', '+') s = Gio.File.new_for_uri("https://api.spotify.com/v1/search?q=%s" "&type=artist" % artist_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) return decode['artists']['items'][0]['images'][0]['url'] except Exception as e: debug("ArtDownloader::get_spotify_artist_artwork(): %s" % e) return None
def _get_album_art_spotify(self, artist, album): """ Get album artwork from itunes @param artist as string @param album as string @return pixbuf as GdkPixbuf.Pixbuf @tread safe """ pixbuf = None album_spotify_id = None try: album_formated = GLib.uri_escape_string( album, None, True).replace(' ', '+') s = Gio.File.new_for_uri("https://ws.spotify.com/search/" "1/album.json?q=%s" % album_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) for item in decode['albums']: if item['artists'][0]['name'].lower() == artist.lower(): album_spotify_id = item['href'].replace( 'spotify:album:', '') break if album_spotify_id is not None: s = Gio.File.new_for_uri("https://api.spotify.com/" "v1/albums/%s" % album_spotify_id) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) url = decode['images'][0]['url'] s = Gio.File.new_for_uri(url) (status, data, tag) = s.load_contents() if status: stream = Gio.MemoryInputStream.new_from_data(data, None) pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, ArtSize.MONSTER, ArtSize.MONSTER, False, None) except Exception as e: print("ArtDownloader::_get_album_art_spotify: %s" % e) return pixbuf
def _dequeue(self): self._lock.acquire() if not self._queued: self._lock.release() return uri, target = self._queued.pop() # Really crappy way to figure out an extension extension = "." + AUDIO_ENCODER.split('enc')[0][-3:] target = os.path.join(MUSIC_DIRECTORY, GLib.uri_escape_string(target, None, False) + extension) self._lock.release() pipeline = Gst.parse_launch("uridecodebin uri=" + uri + " ! " + AUDIO_ENCODER + " ! filesink location=" + target) if self.pipeline: self.pipeline.disconnect_by_func(self._eosCb) self.pipeline.setState(Gst.State.NULL) self.pipeline = SimplePipeline(pipeline, None) self.pipeline.connect("eos", self._eosCb) self.pipeline.setState(Gst.State.PLAYING)
def _get_deezer_artist_info(self, artist): """ Return deezer artist information @param artist as str @return (url as str/None, content as None) """ try: artist_formated = GLib.uri_escape_string( artist, None, True).replace(' ', '+') s = Lio.File.new_for_uri("https://api.deezer.com/search/artist/?" "q=%s&output=json&index=0&limit=1&" % artist_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) return (decode['data'][0]['picture_xl'], None) except Exception as e: debug("Downloader::_get_deezer_artist_artwork(): %s [%s]" % (e, artist)) return (None, None)
def _get_album_art_spotify(self, artist, album): """ Get album artwork from itunes @param artist as string @param album as string @return image as bytes @tread safe """ image = None artists_spotify_ids = [] try: artist_formated = GLib.uri_escape_string( artist, None, True).replace(' ', '+') s = Gio.File.new_for_uri("https://api.spotify.com/v1/search?q=%s" "&type=artist" % artist_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) for item in decode['artists']['items']: artists_spotify_ids.append(item['id']) for artist_spotify_id in artists_spotify_ids: s = Gio.File.new_for_uri("https://api.spotify.com/v1/artists/" "%s/albums" % artist_spotify_id) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) url = None for item in decode['items']: if item['name'] == album: url = item['images'][0]['url'] break if url is not None: s = Gio.File.new_for_uri(url) (status, image, tag) = s.load_contents() break except Exception as e: print("ArtDownloader::_get_album_art_spotify: %s [%s/%s]" % (e, artist, album)) return image
def _get_spotify_artist_info(self, artist): """ Return spotify artist information @param artist as str @return (url as str/None, content as None) """ try: artist_formated = GLib.uri_escape_string( artist, None, True).replace(' ', '+') s = Lio.File.new_for_uri("https://api.spotify.com/v1/search?q=%s" "&type=artist" % artist_formated) (status, data, tag) = s.load_contents() if status: decode = json.loads(data.decode('utf-8')) for item in decode['artists']['items']: if item['name'].lower() == artist.lower(): return (item['images'][0]['url'], None) except Exception as e: debug("Downloader::_get_spotify_artist_artwork(): %s [%s]" % (e, artist)) return (None, None)
def __get_jgm_id(self, item): """ Get jmg id @param item as SearchItem @return jpg id as str """ # Try to handle compilations (itunes one) if item.artists[0].lower() == "various artists": if len(item.artists) > 1: artist = item.artists[1] else: artist = "" else: artist = item.artists[0] unescaped = "%s %s" % (artist, item.name) search = GLib.uri_escape_string(unescaped, None, True) try: f = Gio.File.new_for_uri("http://app.jgm90.com/cmapi/search/" "%s/1/10" % search) (status, data, tag) = f.load_contents(None) if status: decode = json.loads(data.decode('utf-8')) for song in decode['result']['songs']: try: song_artist = escape( song['artists'][0]['name'].lower()) if song_artist == escape(artist.lower()): return song['id'] except: pass except IndexError: pass except KeyError: pass except Exception as e: print("WebJmg90::__get_jmg_id():", e) return None
def _copy_to_device(self, playlists): """ Copy file from playlist to device @param playlists as [str] """ for playlist in playlists: try: playlist_name = Lp().playlists.get_name(playlist) # Create playlist m3u = Gio.File.new_for_path( "/tmp/lollypop_%s.m3u" % (playlist_name,)) self._retry(m3u.replace_contents, (b'#EXTM3U\n', None, False, Gio.FileCreateFlags.REPLACE_DESTINATION, None)) stream = m3u.open_readwrite(None) except Exception as e: print("DeviceWidget::_copy_to_device(): %s" % e) m3u = None stream = None # Start copying tracks_ids = Lp().playlists.get_tracks_ids(playlist) for track_id in tracks_ids: if track_id is None: continue 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) on_device_album_uri = "%s/tracks/%s_%s" %\ (self._uri, artist_name, album_name) d = Gio.File.new_for_uri(on_device_album_uri) if not d.query_exists(None): self._retry(d.make_directory_with_parents, (None,)) # Copy album art art = Lp().art.get_album_artwork_path(track.album) if art is not None: src_art = Gio.File.new_for_path(art) art_uri = "%s/cover.jpg" % on_device_album_uri self._copied_art_uris.append(art_uri) dst_art = Gio.File.new_for_uri(art_uri) if not dst_art.query_exists(None): self._retry(src_art.copy, (dst_art, Gio.FileCopyFlags.OVERWRITE, None, None)) track_name = GLib.uri_escape_string(GLib.basename(track.path), "", False) # Check extension, if not mp3, convert ext = os.path.splitext(track.path)[1] if ext != ".mp3" and self._convert: convertion_needed = True track_name = track_name.replace(ext, ".mp3") else: convertion_needed = False src_track = Gio.File.new_for_path(track.path) info = src_track.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" % (on_device_album_uri, mtime, track_name) if stream is not None: line = "tracks/%s_%s/%s_%s\n" %\ (artist_name.lower(), album_name.lower(), mtime, track_name) self._retry(stream.get_output_stream().write, (line.encode(encoding='UTF-8'), None)) dst_track = Gio.File.new_for_uri(dst_uri) if not dst_track.query_exists(None): if convertion_needed: mp3_uri = "file:///tmp/%s" % track_name mp3_file = Gio.File.new_for_uri(mp3_uri) pipeline = self._convert_to_mp3(src_track, mp3_file) # Check if encoding is finished if pipeline is not None: bus = pipeline.get_bus() bus.add_signal_watch() bus.connect('message::eos', self._on_bus_eos) self._encoding = True while self._encoding and self._sync: sleep(1) bus.disconnect_by_func(self._on_bus_eos) pipeline.set_state(Gst.State.PAUSED) pipeline.set_state(Gst.State.READY) pipeline.set_state(Gst.State.NULL) self._retry( mp3_file.move, (dst_track, Gio.FileCopyFlags.OVERWRITE, None, None)) # To be sure try: mp3_file.delete(None) except: pass else: self._retry(src_track.copy, (dst_track, Gio.FileCopyFlags.OVERWRITE, None, None)) else: self._done += 1 self._done += 1 self._fraction = self._done/self._total if stream is not None: stream.close() if m3u is not None: playlist_name = GLib.uri_escape_string(playlist_name, "", False) dst = Gio.File.new_for_uri(self._uri+'/'+playlist_name+'.m3u') self._retry(m3u.move, (dst, Gio.FileCopyFlags.OVERWRITE, None, None))
def _copy_to_device(self, playlists): """ Copy file from playlist to device @param playlists as [str] """ for playlist in playlists: try: playlist_name = Lp().playlists.get_name(playlist) # Create playlist m3u = Gio.File.new_for_path( "/tmp/lollypop_%s.m3u" % (playlist_name,)) self._retry(m3u.replace_contents, (b'#EXTM3U\n', None, False, Gio.FileCreateFlags.REPLACE_DESTINATION, None)) stream = m3u.open_readwrite(None) except Exception as e: print("DeviceWidget::_copy_to_device(): %s" % e) m3u = None stream = None # Start copying tracks_ids = Lp().playlists.get_tracks_ids(playlist) for track_id in tracks_ids: if track_id is None: continue 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, "", False) artist_name = GLib.uri_escape_string(track.artist, "", False) on_device_album_uri = "%s/tracks/%s_%s" %\ (self._uri, artist_name.lower(), album_name.lower()) d = Gio.File.new_for_uri(on_device_album_uri) if not d.query_exists(None): self._retry(d.make_directory_with_parents, (None,)) # Copy album art art = Lp().art.get_album_artwork_path(track.album) if art is not None: src_art = Gio.File.new_for_path(art) art_uri = "%s/cover.jpg" % on_device_album_uri self._copied_art_uris.append(art_uri) dst_art = Gio.File.new_for_uri(art_uri) if not dst_art.query_exists(None): self._retry(src_art.copy, (dst_art, Gio.FileCopyFlags.OVERWRITE, None, None)) track_name = GLib.uri_escape_string(GLib.basename(track.path), "", False) src_track = Gio.File.new_for_path(track.path) info = src_track.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" % (on_device_album_uri, mtime, track_name) if stream is not None: line = "tracks/%s_%s/%s_%s\n" %\ (artist_name.lower(), album_name.lower(), mtime, track_name) self._retry(stream.get_output_stream().write, (line.encode(encoding='UTF-8'), None)) dst_track = Gio.File.new_for_uri(dst_uri) if not dst_track.query_exists(None): self._retry(src_track.copy, (dst_track, Gio.FileCopyFlags.OVERWRITE, None, None)) else: self._done += 1 self._done += 1 self._fraction = self._done/self._total GLib.idle_add(self._update_progress) if stream is not None: stream.close() if m3u is not None: playlist_name = GLib.uri_escape_string(playlist_name, "", False) dst = Gio.File.new_for_uri(self._uri+'/'+playlist_name+'.m3u') self._retry(m3u.move, (dst, Gio.FileCopyFlags.OVERWRITE, None, None))