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 __check_value_to_mark(self): """ Look at visible treeview range, and mark char as needed """ try: (start, end) = self.__view.get_visible_range() # As start may not really visible, use next # start.next() if start is not None and end is not None: # Check if start is really visible area = self.__view.get_cell_area(start) if area.y + area.height / 2 < 0: start.next() # Check if start is non static: value = self.__get_value_for_path(start, 0) while value is not None and value < 0: start.next() value = self.__get_value_for_path(start, 0) # Check if end is really visible area = self.__view.get_cell_area(end) scrolled_allocation = self.__scrolled.get_allocation() if area.y + area.height / 2 > scrolled_allocation.height: end.prev() start_value = self.__get_value_for_path(start, 3) end_value = self.__get_value_for_path(end, 3) if start_value is not None and end_value is not None: start_value = noaccents(start_value[0]).upper() end_value = noaccents(end_value[0]).upper() self.__mark_values(start_value, end_value) except: pass # get_visible_range() == None
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 __calculate_score(self, row): """ Calculate score for row @param row as SearchRow """ if row.score is not None: return # Network search score less if row.id is None: score = 0 artists = row.artists else: score = 1 artists = [] for artist_id in row.artist_ids: artists.append(Lp().artists.get_name(artist_id)) for item in self.__current_search.split(): for artist in artists: if noaccents(artist.lower()).find( noaccents(item).lower()) != -1: score += 2 if not row.is_track: score += 1 if noaccents(row.name).lower().find( noaccents(item).lower()) != -1: score += 1 if row.is_track: score += 1 row.set_score(score)
def __calculate_score(self, row): """ Calculate score for row @param row as SearchRow """ if row.score is not None: return score = 0 artists = [] for artist_id in row.artist_ids: artists.append(Lp().artists.get_name(artist_id)) for item in self.__current_search.split(): try: year = int(item) if year == row.year: score += 2 except: pass for artist in artists: if noaccents(artist.lower()).find( noaccents(item).lower()) != -1: score += 2 if not row.is_track: score += 1 if noaccents(row.name).lower().find(noaccents(item).lower()) != -1: score += 1 if row.is_track: score += 1 row.set_score(score)
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_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 __search_albums(self, search, storage_type, cancellable): """ Get albums for search items @param search as str @param storage_type as StorageType @param cancellable as Gio.Cancellable @return [int] """ albums = [] album_ids = [] split = self.__split_string(search) for search_str in [search] + split: albums += App().albums.search(search_str, storage_type) if cancellable.is_cancelled(): break for (album_id, album_name) in albums: valid = True no_accents = noaccents(album_name) if not no_accents.startswith(search): for word in split: if word not in no_accents: valid = False break else: album_ids.append(album_id) if valid: album_ids.append(album_id) return album_ids
def search_for_child(self, text): """ Search child and scroll @param text as str """ for child in self.filtered: style_context = child.get_style_context() style_context.remove_class("typeahead") if not text: return for child in self.filtered: if noaccents(child.name).find(noaccents(text)) != -1: style_context = child.get_style_context() style_context.add_class("typeahead") GLib.idle_add(self._scroll_to_child, child) break
def __on_button_press_event(self, eventbox, event): """ Scroll to activated child char """ char = None row = None for child in self.__grid.get_children(): allocation = child.get_allocation() if allocation.y <= event.y <= allocation.y + allocation.height: char = child.get_text() break if char is not None: if char == "▲": row = self.__listbox.get_children()[0] elif char == "▼": row = self.__listbox.get_children()[-1] else: for child in self.__listbox.get_children(): if child.id < 0: continue if noaccents(index_of(child.sortname))[0].upper() == char: row = child break if row is not None: values = row.translate_coordinates(self.__listbox, 0, 0) if values is not None: adj = self.__scrolled.get_vadjustment() adj.set_value(values[1])
def __on_button_press(self, eventbox, event): """ Scroll to activated child char """ char = None for child in self.__grid.get_children(): allocation = child.get_allocation() if event.y >= allocation.y and\ event.y <= allocation.y + allocation.height: char = child.get_text() break if char is not None: if char == "▲": self.__view.scroll_to_cell( self.__model.get_path(self.__model[0].iter), None, True, 0, 0) elif char == "▼": self.__view.scroll_to_cell( self.__model.get_path(self.__model[-1].iter), None, True, 0, 0) else: for row in self.__model: if row[0] < 0: continue if noaccents(index_of(row[3]))[0].upper() == char: self.__view.scroll_to_cell( self.__model.get_path(row.iter), None, True, 0, 0) break
def add_char(self, c): """ Add a char to widget, will not be shown @param c as char """ to_add = noaccents(c.upper()) if to_add not in self.__chars: self.__chars.append(to_add)
def search_next(self, text): """ Search previous child and scroll @param text as str """ found = False previous_style_context = None for child in self.filtered: style_context = child.get_style_context() if style_context.has_class("typeahead"): previous_style_context = style_context found = True continue if found and noaccents(child.name).find(noaccents(text)) != -1: previous_style_context.remove_class("typeahead") style_context.add_class("typeahead") GLib.idle_add(self._scroll_to_child, child) break
def add_char(self, c): """ Add a char to widget, will not be shown @param c as char """ if c: to_add = noaccents(index_of(c)).upper() if to_add not in self.__chars: self.__chars.append(to_add)
def search(self, string, limit=25): """ Search for albums looking like string @param search as str @param limit as int/None @return album ids as [int] """ with SqlCursor(Lp().db) as sql: if limit is None: filters = ("%" + noaccents(string) + "%", ) else: filters = ("%" + noaccents(string) + "%", limit) request = ("SELECT albums.rowid\ FROM albums\ WHERE noaccents(name) LIKE ?") if limit is not None: request += " LIMIT ?" result = sql.execute(request, filters) return list(itertools.chain(*result))
def search_prev(self, text): """ Search previous child and scroll @param text as str """ previous_children = [] found_child = None for child in self.filtered: style_context = child.get_style_context() if style_context.has_class("typeahead"): found_child = child break previous_children.insert(0, child) if previous_children and found_child is not None: for child in previous_children: if noaccents(child.name).find(noaccents(text)) != -1: found_child.get_style_context().remove_class("typeahead") child.get_style_context().add_class("typeahead") GLib.idle_add(self._scroll_to_child, child) break
def _get_spotify_album_artwork_uri(self, artist, album, cancellable=None): """ Get album artwork uri from spotify @param artist as str @param album as str @param cancellable as Gio.Cancellable @return uri as str @tread safe """ if not get_network_available("SPOTIFY"): return None artists_spotify_ids = [] try: token = self.__get_spotify_token(cancellable) 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" % token helper = TaskHelper() helper.add_header("Authorization", token) (status, data) = helper.load_uri_content_sync(uri, cancellable) 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: uri = "https://api.spotify.com/v1/artists/" +\ "%s/albums" % artist_spotify_id (status, data) = helper.load_uri_content_sync(uri, cancellable) if status: decode = json.loads(data.decode("utf-8")) uri = None for item in decode["items"]: if noaccents(item["name"].lower()) ==\ noaccents(album.lower()): return item["images"][0]["url"] except Exception as e: Logger.error("ArtDownloader::_get_album_art_spotify_uri: %s" % e) return None
def search(self, string): """ Search for artists looking like string @param string @return Array of id as int """ with SqlCursor(App().db) as sql: result = sql.execute( "SELECT artists.rowid FROM artists\ WHERE noaccents(artists.name) LIKE ?\ LIMIT 25", ("%" + noaccents(string) + "%", )) return list(itertools.chain(*result))
def __check_value_to_mark(self): """ Look at visible listbox range, and mark char as needed """ start = self.__scrolled.get_vadjustment().get_value() end = start + self.__scrolled.get_allocated_height() start_value = None end_value = None for row in self.__listbox.get_children(): if row.id < 0: continue values = row.translate_coordinates(self.__listbox, 0, 0) if values is not None: if values[1] >= start and start_value is None: start_value = noaccents(row.sortname[0]).upper() elif values[1] <= end: end_value = noaccents(row.sortname[0]).upper() else: break if start_value is not None and end_value is not None: self.__mark_values(start_value, end_value)
def search(self, string): """ Search for albums looking like string @param search as str @return album ids as [int] """ with SqlCursor(Lp().db) as sql: result = sql.execute("SELECT albums.rowid\ FROM albums\ WHERE noaccents(name) LIKE ?\ LIMIT 25", ('%' + noaccents(string) + '%',)) return list(itertools.chain(*result))
def get(self, search, storage_type, cancellable): """ Get match for search @param search as str @param storage_type as StorageType @param cancellable as Gio.Cancellable """ search = noaccents(search) self.__get_artists(search, storage_type, cancellable) self.__get_albums(search, storage_type, cancellable) self.__get_tracks(search, storage_type, cancellable) GLib.idle_add(self.emit, "finished")
def get_ids_for_name(self, name): """ Return tracks ids with name @param name as str @return track id as [int] """ with SqlCursor(self.__db) as sql: result = sql.execute("SELECT rowid\ FROM tracks WHERE noaccents(name)=?\ COLLATE NOCASE", (noaccents(name),)) return list(itertools.chain(*result))
def search(self, string, limit=25): """ Search for albums looking like string @param search as str @param limit as int/None @return album ids as [int] """ with SqlCursor(Lp().db) as sql: if limit is None: filters = ('%' + noaccents(string) + '%', Type.CHARTS) else: filters = ('%' + noaccents(string) + '%', Type.CHARTS, limit) request = ("SELECT albums.rowid\ FROM albums, album_genres\ WHERE noaccents(name) LIKE ?\ AND album_genres.genre_id!=?\ AND album_genres.album_id=albums.rowid") if limit is not None: request += " LIMIT ?" result = sql.execute(request, filters) return list(itertools.chain(*result))
def search(self, searched): """ Search for tracks looking like searched @param searched as string return: list of [id as int, name as string] """ with SqlCursor(Lp().db) as sql: result = sql.execute("SELECT tracks.rowid, tracks.name\ FROM tracks\ WHERE noaccents(name) LIKE ? LIMIT 25", ("%" + noaccents(searched) + "%",)) return list(result)
def __mark_values(self, start, end): """ Mark values @param start as char @param end as char """ start = noaccents(index_of(start)).upper() end = noaccents(index_of(end)).upper() chars = sorted(self.__chars, key=strxfrm) start_idx = chars.index(start) end_idx = chars.index(end) selected = chars[start_idx:end_idx + 1] + ["▲", "▼"] for child in self.__grid.get_children(): label = child.get_text() mark = True if label in selected else False if mark: child.set_opacity(0.9) if label == chars[start_idx]: values = child.translate_coordinates(self.__grid, 0, 0) if values is not None: self.get_vadjustment().set_value(values[1]) else: child.set_opacity(0.4)
def search_track(self, artist, title): """ Get track id for artist and title @param artist as string @param title as string @return track id as int """ artist = noaccents(artist.lower()) track_ids = self.get_ids_for_name(title) for track_id in track_ids: album_id = App().tracks.get_album_id(track_id) artist_ids = set(App().albums.get_artist_ids(album_id)) &\ set(App().tracks.get_artist_ids(track_id)) for artist_id in artist_ids: db_artist = noaccents( App().artists.get_name(artist_id).lower()) if artist.find(db_artist) != -1 or\ db_artist.find(artist) != -1: return track_id artists = ", ".join(App().tracks.get_artists(track_id)).lower() if noaccents(artists) == artist: return track_id return None
def __search_tracks(self, search, storage_type, cancellable): """ Get tracks for search items @param search as str @param storage_type as StorageType @param cancellable as Gio.Cancellable @return [int] """ tracks = [] track_ids = [] split = self.__split_string(search) for search_str in [search] + split: tracks += App().tracks.search_performed(search_str, storage_type) tracks += App().tracks.search(search_str, storage_type) if cancellable.is_cancelled(): break for (track_id, track_name) in tracks: valid = True no_accents = noaccents(track_name) if not no_accents.startswith(search): for word in split: if word not in no_accents: valid = False break # Start with same word, adding to result else: track_ids.append(track_id) # All words are valid, adding to result if valid: track_ids.append(track_id) # Detect an artist match, adding to result for artist in App().tracks.get_artists(track_id): no_accents = noaccents(artist) for word in split: if word in no_accents: track_ids.append(track_id) return track_ids
def search(self, searched): """ Search for tracks looking like searched @param searched as string return: list of [id as int, name as string] """ with SqlCursor(Lp().db) as sql: result = sql.execute( "SELECT tracks.rowid, tracks.name\ FROM tracks, track_genres\ WHERE noaccents(name) LIKE ?\ AND tracks.rowid=track_genres.track_id\ AND track_genres.genre_id!=? LIMIT 25", ('%' + noaccents(searched) + '%', Type.CHARTS)) return list(result)
def search(self, searched): """ Search for tracks looking like searched @param searched as string return: list of [id as int, name as string] """ with SqlCursor(Lp().db) as sql: result = sql.execute("SELECT tracks.rowid, tracks.name\ FROM tracks, track_genres\ WHERE noaccents(name) LIKE ?\ AND tracks.rowid=track_genres.track_id\ AND track_genres.genre_id!=? LIMIT 25", ('%' + noaccents(searched) + '%', Type.CHARTS)) return list(result)
def search(self, string, limit=25): """ Search for albums looking like string @param search as str @param limit as int/None @return album ids as [int] """ with SqlCursor(Lp().db) as sql: if limit is None: filters = ("%" + noaccents(string) + "%", Type.CHARTS) else: filters = ("%" + noaccents(string) + "%", Type.CHARTS, limit) request = ("SELECT albums.rowid\ FROM albums, album_genres AS AG\ WHERE noaccents(name) LIKE ?\ AND ? NOT IN (\ SELECT album_genres.genre_id\ FROM album_genres\ WHERE AG.album_id=album_genres.album_id)\ AND AG.album_id=albums.rowid") if limit is not None: request += " LIMIT ?" result = sql.execute(request, filters) return list(itertools.chain(*result))
def __calculate_score(self, row): """ Calculate score for row @param row as SearchRow """ if row.score is not None: return # Network search score less if row.id is None: score = 0 artists = row.artists else: score = 1 artists = [] for artist_id in row.artist_ids: artists.append(Lp().artists.get_name(artist_id)) for item in self.__current_search.split(): try: year = int(item) if year == int(row.year): score += 2 except: pass for artist in artists: if noaccents(artist.lower()).find( noaccents(item).lower()) != -1: score += 2 if not row.is_track: score += 1 if noaccents(row.name).lower().find( noaccents(item).lower()) != -1: score += 1 if row.is_track: score += 1 row.set_score(score)
def search(self, string): """ Search for artists looking like string @param string @return Array of id as int """ with SqlCursor(Lp().db) as sql: result = sql.execute("SELECT artists.rowid FROM artists, albums,\ album_genres, album_artists\ WHERE noaccents(artists.name) LIKE ?\ AND album_artists.artist_id=artists.rowid\ AND album_artists.album_id=albums.rowid\ AND album_genres.album_id=albums.rowid\ AND album_genres.genre_id!=?\ LIMIT 25", ('%' + noaccents(string) + '%', Type.CHARTS)) return list(itertools.chain(*result))
def search(self, searched): """ Search for albums looking like string @param searched as str @return album ids as [int] """ no_accents = noaccents(searched) with SqlCursor(App().db) as sql: items = [] for filter in [(no_accents + "%",), ("%" + no_accents,), ("%" + no_accents + "%",)]: request = "SELECT albums.rowid FROM albums\ WHERE noaccents(name) LIKE ?\ AND albums.mtime!=0 LIMIT 25" result = sql.execute(request, filter) items += list(itertools.chain(*result)) return items
def __on_button_press(self, eventbox, event): """ Scroll to activated child char """ char = None for child in self.__grid.get_children(): allocation = child.get_allocation() if event.x >= allocation.x and\ event.x <= allocation.x + allocation.width and\ event.y >= allocation.y and\ event.y <= allocation.y + allocation.height: char = child.get_text() break if char is not None: for row in self.__model: if row[0] < 0: continue if noaccents(row[3])[0].upper() == char: self.__view.scroll_to_cell(self.__model.get_path(row.iter), None, True, 0, 0) break