def search_artist(self, artist_name, max_songs=None, sort='popularity', per_page=20, get_full_info=True, allow_name_change=True, artist_id=None): """Search Genius.com for songs by the specified artist. Returns an Artist object containing artist's songs. :param artist_name: Name of the artist to search for :param max_songs: Maximum number of songs to search for :param sort: Sort by 'title' or 'popularity' :param per_page: Number of results to return per search page :param get_full_info: Get full info for each song (slower) :param allow_name_change: (bool) If True, search attempts to switch to intended artist name. :param artist_id: Allows user to pass a Genius.com artist ID. """ def find_artist_id(search_term): if self.verbose: print('Searching for songs by {0}...\n'.format(search_term)) # Perform a Genius API search for the artist found_artist = None response = self.search_genius_web(search_term) found_artist = self._get_item_from_search_response( response, search_term, type_="artist", result_type="name") # Exit the search if we couldn't find an artist by the given name if not found_artist: if self.verbose: print("No results found for '{a}'.".format(a=search_term)) return None # Assume the top search result is the intended artist return found_artist['id'] # Get the artist ID (or use the one supplied) artist_id = artist_id if artist_id else find_artist_id(artist_name) if artist_id == None: return None artist_info = self.get_artist(artist_id) found_name = artist_info['artist']['name'] if found_name != artist_name and allow_name_change: if self.verbose: print("Changing artist name to '{a}'".format(a=found_name)) artist_name = found_name # Create the Artist object artist = Artist(artist_info) # Download each song by artist, stored as Song objects in Artist object page = 1 reached_max_songs = False while not reached_max_songs: songs_on_page = self.get_artist_songs(artist_id, sort, per_page, page) # Loop through each song on page of search results for song_info in songs_on_page['songs']: # Check if song is valid (e.g. has title, contains lyrics) has_title = ('title' in song_info) has_lyrics = self._result_is_lyrics(song_info['title']) valid = has_title and (has_lyrics or (not self.skip_non_songs)) # Reject non-song results (e.g. Linear Notes, Tracklists, etc.) if not valid: if self.verbose: s = song_info['title'] if has_title else "MISSING TITLE" print('"{s}" is not valid. Skipping.'.format(s=s)) continue # Create the Song object from lyrics and metadata lyrics = self._scrape_song_lyrics_from_url(song_info['url']) if get_full_info: info = self.get_song(song_info['id']) else: info = {'song': song_info} song = Song(info, lyrics) # Attempt to add the Song to the Artist result = artist.add_song(song, verbose=False) if result == 0 and self.verbose: print('Song {n}: "{t}"'.format(n=artist.num_songs, t=song.title)) # Exit search if the max number of songs has been met reached_max_songs = max_songs and artist.num_songs >= max_songs if reached_max_songs: if self.verbose: print('\nReached user-specified song limit ({m}).'. format(m=max_songs)) break # Move on to next page of search results page = songs_on_page['next_page'] if page is None: break # Exit search when last page is reached if self.verbose: print('Done. Found {n} songs.'.format(n=artist.num_songs)) return artist
def search_artist(self, artist_name, max_songs=None, sort='popularity', per_page=20, get_full_info=True, allow_name_change=True, artist_id=None, include_features=False): """Searches Genius.com for songs by the specified artist. This method looks for the artist by the name or by the ID if it's provided. It returrns an :class:`Artist <lyricsgenius.artist.Artist>` object if the search is successful. If :obj:`allow_name_change` is True, the name of the artist is changed to the artist name on Genius. Args: artist_name (:obj:`str`): Name of the artist to search for. max_songs (obj:`int`, optional): Maximum number of songs to search for. sort (:obj:`str`, optional): Sort by 'title' or 'popularity'. per_page (:obj:`int`, optional): Number of results to return per search page. It can't be more than 50. get_full_info (:obj:`bool`, optional): Get full info for each song (slower). allow_name_change (:obj:`bool`, optional): If True, search attempts to switch to intended artist name. artist_id (:obj:`int`, optional): Allows user to pass an artist ID. include_features (:obj:`bool`, optional): If True, includes tracks featuring the artist. Returns: :class:`Artist <lyricsgenius.artist.Artist>`: Artist object containing artist's songs. Examples: .. code:: python # printing the lyrics of all of the artist's songs genius = Genius(token) artist = genius.search_artist('Andy Shauf') for song in artist.songs: print(song.lyrics) Visit :class:`Aritst <lyricsgenius.artist.Artist>` for more examples. """ def find_artist_id(search_term): """Finds the ID of the artist, returns the first result if none match the search term or returns None if there were not results """ if self.verbose: print('Searching for songs by {0}...\n'.format(search_term)) # Perform a Genius API search for the artist found_artist = None response = self.search_genius_web(search_term) found_artist = self._get_item_from_search_response( response, search_term, type_="artist", result_type="name") # Exit the search if we couldn't find an artist by the given name if not found_artist: if self.verbose: print("No results found for '{a}'.".format(a=search_term)) return None # Assume the top search result is the intended artist return found_artist['id'] # Get the artist ID (or use the one supplied) artist_id = artist_id if artist_id else find_artist_id(artist_name) if not artist_id: return None artist_info = self.get_artist(artist_id) found_name = artist_info['artist']['name'] if found_name != artist_name and allow_name_change: if self.verbose: print("Changing artist name to '{a}'".format(a=found_name)) artist_name = found_name # Create the Artist object artist = Artist(artist_info) # Download each song by artist, stored as Song objects in Artist object page = 1 reached_max_songs = True if max_songs == 0 else False while not reached_max_songs: songs_on_page = self.get_artist_songs(artist_id, sort, per_page, page) # Loop through each song on page of search results for song_info in songs_on_page['songs']: # Check if song is valid (e.g. has title, contains lyrics) has_title = ('title' in song_info) has_lyrics = self._result_is_lyrics(song_info['title']) valid = has_title and (has_lyrics or (not self.skip_non_songs)) # Reject non-song results (e.g. Linear Notes, Tracklists, etc.) if not valid: if self.verbose: s = song_info['title'] if has_title else "MISSING TITLE" print('"{s}" is not valid. Skipping.'.format(s=s)) continue # Create the Song object from lyrics and metadata lyrics = self._scrape_song_lyrics_from_url(song_info['url']) if get_full_info: info = self.get_song(song_info['id']) else: info = {'song': song_info} song = Song(info, lyrics) # Attempt to add the Song to the Artist result = artist.add_song(song, verbose=False, include_features=include_features) if result == 0 and self.verbose: print('Song {n}: "{t}"'.format(n=artist.num_songs, t=song.title)) # Exit search if the max number of songs has been met reached_max_songs = max_songs and artist.num_songs >= max_songs if reached_max_songs: if self.verbose: print(('\nReached user-specified song limit ({m}).'. format(m=max_songs))) break # Move on to next page of search results page = songs_on_page['next_page'] if page is None: break # Exit search when last page is reached if self.verbose: print('Done. Found {n} songs.'.format(n=artist.num_songs)) return artist
def search_artist(self, artist_name, max_songs=100, sort='popularity', per_page=20, get_full_info=True): """Search Genius.com for songs by the specified artist. Returns an Artist object containing artist's songs. :param artist_name: Name of the artist to search for :param max_songs: Maximum number of songs to search for :param sort: Sort by 'title' or 'popularity' :param per_page: Number of results to return per search page :param get_full_info: Get full info for each song (slower) """ if self.verbose: print('Searching for songs by {0}...\n'.format(artist_name)) # Perform a Genius API search for the artist found_artist = None response = self.search_genius_web(artist_name) found_artist = self._get_item_from_search_response(response, type_="artist") # Exit the search if we couldn't find an artist by the given name if not found_artist: if self.verbose: print("No results found for '{a}'.".format(a=artist_name)) return None # Assume the top search result is the intended artist artist_id = found_artist['id'] artist_info = self.get_artist(artist_id) found_name = artist_info['artist']['name'] if found_name != artist_name: if self.verbose: print("Changing artist name to '{a}'".format(a=found_name)) artist_name = found_name # Create the Artist object artist = Artist(artist_info) # Download each song by artist, stored as Song objects in Artist object page = 1 reached_max_songs = False with Pool(10) as p: while not reached_max_songs: songs_on_page = self.get_artist_songs(artist_id, sort, per_page, page) songs_info = [song_info for song_info in songs_on_page['songs']] output = p.map(self._get_song_object, songs_info) output = [x for x in output if x] for song in output: # Attempt to add the Song to the Artist result = artist.add_song(song, verbose=False) if result == 0 and self.verbose: print('Song {n}: "{t}"'.format(n=artist.num_songs, t=song.title)) # Exit search if the max number of songs has been met reached_max_songs = max_songs and artist.num_songs >= max_songs if reached_max_songs: if self.verbose: print('\nReached user-specified song limit ({m}).'.format(m=max_songs)) break # Move on to next page of search results page = songs_on_page['next_page'] if page is None: break # Exit search when last page is reached print('Done. Found {n} songs by {g}.'.format(n=artist.num_songs, g=artist.name)) return artist