def generate_playlist(search: str, sp_user: Spotify, sp_app: Spotify, use_musicmap: bool = False): """ Generates a playlist of top songs of similar artists. :param search: the name of the artist. Also supports Spotify URI or ID of the artist when use_musicmap is False :param sp_user: a Spotify object authenticated by the user who will be creating the playlist :param sp_app: a Spotify object authenticated by the app for a higher rate limit :param use_musicmap: True= uses music map for related artists, False = uses Spotify's related artists :return: a dict containing information on the playlist or nothing if the process failed. """ uri_prefix = 'spotify:artist:' if use_musicmap: artist = get_artist(search, sp_user) if not artist: return False track_ids = generate_track_ids_musicmap(artist, sp_user) else: if search.startswith(uri_prefix) and not use_musicmap: artist = sp_user.artist(search) else: artist = get_artist(search, sp_user) print(artist) if not artist: return "Artist not found" track_ids = generate_track_ids_spotify(artist, sp_user) if track_ids: playlist_name = artist['name'] + " recommendations" status = create_and_populate_playlist(playlist_name, track_ids, sp_user) print(status) if status: return status else: return "Playlist creation failed" else: print("track_ids is empty") return "No similar tracks found"
def get_playlist_genres(tracks, suggestion_count): # Pagination should happen, at some point above. artists_num_appearances = [] genres = [] token = sp_oauth.get_cached_token()['access_token'] sp = Spotify(token) # Assemble a list of all artists represented. for track in tracks: for artist in track['track']['artists']: artists_num_appearances.append(artist['id']) # Count it artists_num_appearances = Counter(artists_num_appearances) # Grab the 10 most common artists in the playlist, and get their genres. for artist_id, _ in artists_num_appearances.most_common(10): artist_info = sp.artist(artist_id) for genre in artist_info['genres']: genres.append(genre) # Count genres genre_counter = Counter(genres) top_n_genres = genre_counter.most_common(suggestion_count) # Resolve these to actual tag objects tags = [] for genre in top_n_genres: name = genre[0] tag = Tag.objects.get_or_create(name=name, category=TAG_CATEGORY_GENRE)[0] tags.append(tag) print tag return tags
def get_artist_information(sp_api: Spotify, base_track: dict): artist_data: list = [] try: artists: list = base_track['artists'] artists_obj: list = [ sp_api.artist(artist.get('id')) for artist in artists ] artist_data += [ SpotifyArtistDoc(artist=artist) for artist in artists_obj ] except Exception as e: logger.error(e) return artist_data
class SpotifyWrapper: def __init__(self): credentials = SpotifyClientCredentials( client_id='d9a2223d179b4d9b845953cdc3b1f49b', client_secret='0b2e5ce4a3d345b6a31793c13141b3aa', ) self.spotify = Spotify(client_credentials_manager=credentials) def filter(self, artist): return {key: artist[key] for key in ('name', 'popularity')} def artist(self, n): artist = self.spotify.artist(n) return self.filter(artist) def related_artists(self, n): related = self.spotify.artist_related_artists(n) for artist in related['artists']: yield artist['id'], self.filter(artist)
class SpotifyWrapper: def __init__(self): credentials = SpotifyClientCredentials( client_id='25b010562dbf458c80912f82d5eefe15', client_secret='ec41140f13124929862f5ba3cb61ccf6', ) self.spotify = Spotify(client_credentials_manager=credentials) def filter(self, artist): return {key: artist[key] for key in ('name', 'popularity')} def artist(self, n): artist = self.spotify.artist(n) return self.filter(artist) def related_artists(self, n): related = self.spotify.artist_related_artists(n) for artist in related['artists']: yield artist['id'], self.filter(artist)
class SpotifyWrapper: def __init__(self): credentials = SpotifyClientCredentials( client_id='84c3ea3f396146dba5b4dd15c597a922', client_secret='f3e30734460940828047485819f8692f', ) self.spotify = Spotify(client_credentials_manager=credentials) def filter(self, artist): return {key: artist[key] for key in ('name', 'popularity')} def artist(self, n): artist = self.spotify.artist(n) return self.filter(artist) def related_artists(self, n): related = self.spotify.artist_related_artists(n) for artist in related['artists']: yield artist['id'], self.filter(artist)
class SpotifyWrapper: def __init__(self): credentials = SpotifyClientCredentials( client_id='SEU CLIENT ID', client_secret='SEU CLIENT SECRET', ) self.spotify = Spotify(client_credentials_manager=credentials) def filter(self, artist): return {key: artist[key] for key in ('name', 'popularity')} def artist(self, n): artist = self.spotify.artist(n) return self.filter(artist) def related_artists(self, n): related = self.spotify.artist_related_artists(n) for artist in related['artists']: yield artist['id'], self.filter(artist)
class ClientCredentialsTestSpotipy(unittest.TestCase): """ These tests require user authentication - provide client credentials using the following environment variables :: 'SPOTIPY_CLIENT_USERNAME' 'SPOTIPY_CLIENT_ID' 'SPOTIPY_CLIENT_SECRET' 'SPOTIPY_REDIRECT_URI' """ @classmethod def setUpClass(self): self.spotify = Spotify(client_credentials_manager=SpotifyClientCredentials()) self.spotify.trace = False muse_urn = 'spotify:artist:12Chz98pHFMPJEknJQMWvI' def test_request_with_token(self): artist = self.spotify.artist(self.muse_urn) self.assertTrue(artist['name'] == 'Muse')
class TestSpotipy(unittest.TestCase): """ These tests require user authentication - provide client credentials using the following environment variables :: 'SPOTIPY_CLIENT_USERNAME' 'SPOTIPY_CLIENT_ID' 'SPOTIPY_CLIENT_SECRET' 'SPOTIPY_REDIRECT_URI' """ creep_urn = 'spotify:track:3HfB5hBU0dmBt8T0iCmH42' creep_id = '3HfB5hBU0dmBt8T0iCmH42' creep_url = 'http://open.spotify.com/track/3HfB5hBU0dmBt8T0iCmH42' el_scorcho_urn = 'spotify:track:0Svkvt5I79wficMFgaqEQJ' el_scorcho_bad_urn = 'spotify:track:0Svkvt5I79wficMFgaqEQK' pinkerton_urn = 'spotify:album:04xe676vyiTeYNXw15o9jT' weezer_urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu' pablo_honey_urn = 'spotify:album:6AZv3m27uyRxi8KyJSfUxL' radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb' angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM' bad_id = 'BAD_ID' @classmethod def setUpClass(self): missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV)) if missing: raise Exception( 'Please set the client credentials for the test application using the following environment variables: {}' .format(CCEV.values())) self.username = os.getenv(CCEV['client_username']) self.scope = 'user-library-read' self.token = prompt_for_user_token(self.username, scope=self.scope) self.spotify = Spotify(auth=self.token) def test_artist_urn(self): artist = self.spotify.artist(self.radiohead_urn) self.assertTrue(artist['name'] == 'Radiohead') def test_artists(self): results = self.spotify.artists([self.weezer_urn, self.radiohead_urn]) self.assertTrue('artists' in results) self.assertTrue(len(results['artists']) == 2) def test_album_urn(self): album = self.spotify.album(self.pinkerton_urn) self.assertTrue(album['name'] == 'Pinkerton') def test_album_tracks(self): results = self.spotify.album_tracks(self.pinkerton_urn) self.assertTrue(len(results['items']) == 10) def test_album_tracks_many(self): results = self.spotify.album_tracks(self.angeles_haydn_urn) tracks = results['items'] total, received = results['total'], len(tracks) while received < total: results = self.spotify.album_tracks(self.angeles_haydn_urn, offset=received) tracks.extend(results['items']) received = len(tracks) self.assertEqual(received, total) def test_albums(self): results = self.spotify.albums( [self.pinkerton_urn, self.pablo_honey_urn]) self.assertTrue('albums' in results) self.assertTrue(len(results['albums']) == 2) def test_track_urn(self): track = self.spotify.track(self.creep_urn) self.assertTrue(track['name'] == 'Creep') def test_track_id(self): track = self.spotify.track(self.creep_id) self.assertTrue(track['name'] == 'Creep') def test_track_url(self): track = self.spotify.track(self.creep_url) self.assertTrue(track['name'] == 'Creep') def test_track_bad_urn(self): try: track = self.spotify.track(self.el_scorcho_bad_urn) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_tracks(self): results = self.spotify.tracks([self.creep_url, self.el_scorcho_urn]) self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']) == 2) def test_artist_top_tracks(self): results = self.spotify.artist_top_tracks(self.weezer_urn) self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']) == 10) def test_artist_related_artists(self): results = self.spotify.artist_related_artists(self.weezer_urn) self.assertTrue('artists' in results) self.assertTrue(len(results['artists']) == 20) for artist in results['artists']: if artist['name'] == 'Jimmy Eat World': found = True self.assertTrue(found) def test_artist_search(self): results = self.spotify.search(q='weezer', type='artist') self.assertTrue('artists' in results) self.assertTrue(len(results['artists']['items']) > 0) self.assertTrue(results['artists']['items'][0]['name'] == 'Weezer') def test_artist_search_with_market(self): results = self.spotify.search(q='weezer', type='artist', market='GB') self.assertTrue('artists' in results) self.assertTrue(len(results['artists']['items']) > 0) self.assertTrue(results['artists']['items'][0]['name'] == 'Weezer') def test_artist_albums(self): results = self.spotify.artist_albums(self.weezer_urn) self.assertTrue('items' in results) self.assertTrue(len(results['items']) > 0) found = False for album in results['items']: if album['name'] == 'Hurley': found = True self.assertTrue(found) def test_search_timeout(self): sp = Spotify(auth=self.token, requests_timeout=.01) try: results = sp.search(q='my*', type='track') self.assertTrue(False, 'unexpected search timeout') except requests.Timeout: self.assertTrue(True, 'expected search timeout') def test_album_search(self): results = self.spotify.search(q='weezer pinkerton', type='album') self.assertTrue('albums' in results) self.assertTrue(len(results['albums']['items']) > 0) self.assertTrue( results['albums']['items'][0]['name'].find('Pinkerton') >= 0) def test_track_search(self): results = self.spotify.search(q='el scorcho weezer', type='track') self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']['items']) > 0) self.assertTrue(results['tracks']['items'][0]['name'] == 'El Scorcho') def test_user(self): user = self.spotify.user(user='******') self.assertTrue(user['uri'] == 'spotify:user:plamere') def test_track_bad_id(self): try: track = self.spotify.track(self.bad_id) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_track_bad_id(self): try: track = self.spotify.track(self.bad_id) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_unauthenticated_post_fails(self): with self.assertRaises(SpotifyException) as cm: self.spotify.user_playlist_create("spotify", "Best hits of the 90s") self.assertTrue(cm.exception.http_status == 401 or cm.exception.http_status == 403) def test_custom_requests_session(self): sess = requests.Session() sess.headers["user-agent"] = "spotipy-test" with_custom_session = Spotify(auth=self.token, requests_session=sess) self.assertTrue( with_custom_session.user(user="******")["uri"] == "spotify:user:akx") def test_force_no_requests_session(self): with_no_session = Spotify(auth=self.token, requests_session=False) self.assertFalse(isinstance(with_no_session._session, requests.Session)) self.assertTrue( with_no_session.user(user="******")["uri"] == "spotify:user:akx")
class AuthTestSpotipy(unittest.TestCase): """ These tests require client authentication - provide client credentials using the following environment variables :: 'SPOTIPY_CLIENT_ID' 'SPOTIPY_CLIENT_SECRET' """ playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx" four_tracks = [ "spotify:track:6RtPijgfPKROxEzTHNRiDp", "spotify:track:7IHOIqZUUInxjVkko181PB", "4VrWlk8IQxevMvERoX08iC", "http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf" ] two_tracks = [ "spotify:track:6RtPijgfPKROxEzTHNRiDp", "spotify:track:7IHOIqZUUInxjVkko181PB" ] other_tracks = [ "spotify:track:2wySlB6vMzCbQrRnNGOYKa", "spotify:track:29xKs5BAHlmlX1u4gzQAbJ", "spotify:track:1PB7gRWcvefzu7t3LJLUlf" ] bad_id = 'BAD_ID' creep_urn = 'spotify:track:6b2oQwSGFkzsMtQruIWm2p' creep_id = '6b2oQwSGFkzsMtQruIWm2p' creep_url = 'http://open.spotify.com/track/6b2oQwSGFkzsMtQruIWm2p' el_scorcho_urn = 'spotify:track:0Svkvt5I79wficMFgaqEQJ' el_scorcho_bad_urn = 'spotify:track:0Svkvt5I79wficMFgaqEQK' pinkerton_urn = 'spotify:album:04xe676vyiTeYNXw15o9jT' weezer_urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu' pablo_honey_urn = 'spotify:album:6AZv3m27uyRxi8KyJSfUxL' radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb' angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM' heavyweight_urn = 'spotify:show:5c26B28vZMN8PG0Nppmn5G' heavyweight_id = '5c26B28vZMN8PG0Nppmn5G' heavyweight_url = 'https://open.spotify.com/show/5c26B28vZMN8PG0Nppmn5G' reply_all_urn = 'spotify:show:7gozmLqbcbr6PScMjc0Zl4' heavyweight_ep1_urn = 'spotify:episode:68kq3bNz6hEuq8NtdfwERG' heavyweight_ep1_id = '68kq3bNz6hEuq8NtdfwERG' heavyweight_ep1_url = 'https://open.spotify.com/episode/68kq3bNz6hEuq8NtdfwERG' reply_all_ep1_urn = 'spotify:episode:1KHjbpnmNpFmNTczQmTZlR' @classmethod def setUpClass(self): self.spotify = Spotify( client_credentials_manager=SpotifyClientCredentials()) self.spotify.trace = False def test_audio_analysis(self): result = self.spotify.audio_analysis(self.four_tracks[0]) assert ('beats' in result) def test_audio_features(self): results = self.spotify.audio_features(self.four_tracks) self.assertTrue(len(results) == len(self.four_tracks)) for track in results: assert ('speechiness' in track) def test_audio_features_with_bad_track(self): bad_tracks = ['spotify:track:bad'] input = self.four_tracks + bad_tracks results = self.spotify.audio_features(input) self.assertTrue(len(results) == len(input)) for track in results[:-1]: if track is not None: assert ('speechiness' in track) self.assertTrue(results[-1] is None) def test_recommendations(self): results = self.spotify.recommendations(seed_tracks=self.four_tracks, min_danceability=0, max_loudness=0, target_popularity=50) self.assertTrue(len(results['tracks']) == 20) def test_artist_urn(self): artist = self.spotify.artist(self.radiohead_urn) self.assertTrue(artist['name'] == 'Radiohead') def test_artists(self): results = self.spotify.artists([self.weezer_urn, self.radiohead_urn]) self.assertTrue('artists' in results) self.assertTrue(len(results['artists']) == 2) def test_album_urn(self): album = self.spotify.album(self.pinkerton_urn) self.assertTrue(album['name'] == 'Pinkerton') def test_album_tracks(self): results = self.spotify.album_tracks(self.pinkerton_urn) self.assertTrue(len(results['items']) == 10) def test_album_tracks_many(self): results = self.spotify.album_tracks(self.angeles_haydn_urn) tracks = results['items'] total, received = results['total'], len(tracks) while received < total: results = self.spotify.album_tracks(self.angeles_haydn_urn, offset=received) tracks.extend(results['items']) received = len(tracks) self.assertEqual(received, total) def test_albums(self): results = self.spotify.albums( [self.pinkerton_urn, self.pablo_honey_urn]) self.assertTrue('albums' in results) self.assertTrue(len(results['albums']) == 2) def test_track_urn(self): track = self.spotify.track(self.creep_urn) self.assertTrue(track['name'] == 'Creep') def test_track_id(self): track = self.spotify.track(self.creep_id) self.assertTrue(track['name'] == 'Creep') self.assertTrue(track['popularity'] > 0) def test_track_url(self): track = self.spotify.track(self.creep_url) self.assertTrue(track['name'] == 'Creep') def test_track_bad_urn(self): try: self.spotify.track(self.el_scorcho_bad_urn) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_tracks(self): results = self.spotify.tracks([self.creep_url, self.el_scorcho_urn]) self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']) == 2) def test_artist_top_tracks(self): results = self.spotify.artist_top_tracks(self.weezer_urn) self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']) == 10) def test_artist_related_artists(self): results = self.spotify.artist_related_artists(self.weezer_urn) self.assertTrue('artists' in results) self.assertTrue(len(results['artists']) == 20) for artist in results['artists']: if artist['name'] == 'Jimmy Eat World': found = True self.assertTrue(found) def test_artist_search(self): results = self.spotify.search(q='weezer', type='artist') self.assertTrue('artists' in results) self.assertTrue(len(results['artists']['items']) > 0) self.assertTrue(results['artists']['items'][0]['name'] == 'Weezer') def test_artist_search_with_market(self): results = self.spotify.search(q='weezer', type='artist', market='GB') self.assertTrue('artists' in results) self.assertTrue(len(results['artists']['items']) > 0) self.assertTrue(results['artists']['items'][0]['name'] == 'Weezer') def test_artist_search_with_multiple_markets(self): total = 5 countries_list = ['GB', 'US', 'AU'] countries_tuple = ('GB', 'US', 'AU') results_multiple = self.spotify.search_markets(q='weezer', type='artist', markets=countries_list) results_all = self.spotify.search_markets(q='weezer', type='artist') results_tuple = self.spotify.search_markets(q='weezer', type='artist', markets=countries_tuple) results_limited = self.spotify.search_markets(q='weezer', limit=3, type='artist', markets=countries_list, total=total) self.assertTrue( all('artists' in results_multiple[country] for country in results_multiple)) self.assertTrue( all('artists' in results_all[country] for country in results_all)) self.assertTrue( all('artists' in results_tuple[country] for country in results_tuple)) self.assertTrue( all('artists' in results_limited[country] for country in results_limited)) self.assertTrue( all( len(results_multiple[country]['artists']['items']) > 0 for country in results_multiple)) self.assertTrue( all( len(results_all[country]['artists']['items']) > 0 for country in results_all)) self.assertTrue( all( len(results_tuple[country]['artists']['items']) > 0 for country in results_tuple)) self.assertTrue( all( len(results_limited[country]['artists']['items']) > 0 for country in results_limited)) self.assertTrue( all(results_multiple[country]['artists']['items'][0]['name'] == 'Weezer' for country in results_multiple)) self.assertTrue( all(results_all[country]['artists']['items'][0]['name'] == 'Weezer' for country in results_all)) self.assertTrue( all(results_tuple[country]['artists']['items'][0]['name'] == 'Weezer' for country in results_tuple)) self.assertTrue( all(results_limited[country]['artists']['items'][0]['name'] == 'Weezer' for country in results_limited)) total_limited_results = 0 for country in results_limited: total_limited_results += len( results_limited[country]['artists']['items']) self.assertTrue(total_limited_results <= total) def test_artist_albums(self): results = self.spotify.artist_albums(self.weezer_urn) self.assertTrue('items' in results) self.assertTrue(len(results['items']) > 0) found = False for album in results['items']: if album['name'] == 'Hurley': found = True self.assertTrue(found) def test_search_timeout(self): client_credentials_manager = SpotifyClientCredentials() sp = spotipy.Spotify( requests_timeout=0.01, client_credentials_manager=client_credentials_manager) # depending on the timing or bandwidth, this raises a timeout or connection error" self.assertRaises( (requests.exceptions.Timeout, requests.exceptions.ConnectionError), lambda: sp.search(q='my*', type='track')) def test_album_search(self): results = self.spotify.search(q='weezer pinkerton', type='album') self.assertTrue('albums' in results) self.assertTrue(len(results['albums']['items']) > 0) self.assertTrue( results['albums']['items'][0]['name'].find('Pinkerton') >= 0) def test_track_search(self): results = self.spotify.search(q='el scorcho weezer', type='track') self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']['items']) > 0) self.assertTrue(results['tracks']['items'][0]['name'] == 'El Scorcho') def test_user(self): user = self.spotify.user(user='******') self.assertTrue(user['uri'] == 'spotify:user:plamere') def test_track_bad_id(self): try: self.spotify.track(self.bad_id) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_show_urn(self): show = self.spotify.show(self.heavyweight_urn, market="US") self.assertTrue(show['name'] == 'Heavyweight') def test_show_id(self): show = self.spotify.show(self.heavyweight_id, market="US") self.assertTrue(show['name'] == 'Heavyweight') def test_show_url(self): show = self.spotify.show(self.heavyweight_url, market="US") self.assertTrue(show['name'] == 'Heavyweight') def test_show_bad_urn(self): with self.assertRaises(SpotifyException): self.spotify.show("bogus_urn", market="US") def test_shows(self): results = self.spotify.shows( [self.heavyweight_urn, self.reply_all_urn], market="US") self.assertTrue('shows' in results) self.assertTrue(len(results['shows']) == 2) def test_show_episodes(self): results = self.spotify.show_episodes(self.heavyweight_urn, market="US") self.assertTrue(len(results['items']) > 1) def test_show_episodes_many(self): results = self.spotify.show_episodes(self.reply_all_urn, market="US") episodes = results['items'] total, received = results['total'], len(episodes) while received < total: results = self.spotify.show_episodes(self.reply_all_urn, offset=received, market="US") episodes.extend(results['items']) received = len(episodes) self.assertEqual(received, total) def test_episode_urn(self): episode = self.spotify.episode(self.heavyweight_ep1_urn, market="US") self.assertTrue(episode['name'] == '#1 Buzz') def test_episode_id(self): episode = self.spotify.episode(self.heavyweight_ep1_id, market="US") self.assertTrue(episode['name'] == '#1 Buzz') def test_episode_url(self): episode = self.spotify.episode(self.heavyweight_ep1_url, market="US") self.assertTrue(episode['name'] == '#1 Buzz') def test_episode_bad_urn(self): with self.assertRaises(SpotifyException): self.spotify.episode("bogus_urn", market="US") def test_episodes(self): results = self.spotify.episodes( [self.heavyweight_ep1_urn, self.reply_all_ep1_urn], market="US") self.assertTrue('episodes' in results) self.assertTrue(len(results['episodes']) == 2) def test_unauthenticated_post_fails(self): with self.assertRaises(SpotifyException) as cm: self.spotify.user_playlist_create("spotify", "Best hits of the 90s") self.assertTrue(cm.exception.http_status == 401 or cm.exception.http_status == 403) def test_custom_requests_session(self): sess = requests.Session() sess.headers["user-agent"] = "spotipy-test" with_custom_session = spotipy.Spotify( client_credentials_manager=SpotifyClientCredentials(), requests_session=sess) self.assertTrue( with_custom_session.user(user="******")["uri"] == "spotify:user:akx") sess.close() def test_force_no_requests_session(self): with_no_session = spotipy.Spotify( client_credentials_manager=SpotifyClientCredentials(), requests_session=False) self.assertNotIsInstance(with_no_session._session, requests.Session) user = with_no_session.user(user="******") self.assertEqual(user["uri"], "spotify:user:akx")
async def spotify(self, ctx: Context, url: str = None, type_: str = None): if not url: return await ctx.send(embed=ErrorEmbed( author=ctx.author, title=':x: Missing Spotify link or ID' )) elif not type_: try: type_ = url.split('&')[0].split('?')[0].split('/')[3] except IndexError: pass if type_ == 'user': return await ctx.send(embed=ErrorEmbed( author=ctx.author, title=':x: User profiles are not supported', description='...yet?' )) elif type_ not in ['track', 'album', 'artist', 'playlist']: return await ctx.send(embed=ErrorEmbed( author=ctx.author, title=':x: What is this?', description='Is it `track`, `album`, `artist` or `playlist`?' )) if url.startswith(('http://open.spotify.com', 'https://open.spotify.com')): url = url.split('?')[0].split('/')[-1] type_ = type_.lower() try: sp = Spotify(auth_manager=SpotifyClientCredentials( client_id=spotify_client_id(), client_secret=spotify_client_secret() )) except SpotifyOauthError: sp = None if not sp: return await ctx.send(embed=ErrorEmbed( author=ctx.author, title=':x: Unable to connect to Spotify!' )) result = error_code = None em = SuccessEmbed( author=ctx.author ).set_author( name=f'{ctx.author.display_name} shared a{"n" if type_[0] == "a" else ""} {type_}:', icon_url=ctx.author.avatar_url ) if type_ == 'track': try: result = sp.track(url) except SpotifyException as e: error_code = int(e.http_status) elif type_ == 'album': try: result = sp.album(url) except SpotifyException as e: error_code = int(e.http_status) elif type_ == 'playlist': try: result = sp.playlist(url) except SpotifyException as e: error_code = int(e.http_status) elif type_ == 'artist': try: result = sp.artist(url) except SpotifyException as e: error_code = int(e.http_status) else: return await ctx.send(embed=ErrorEmbed( author=ctx.author, title=':x: Unknown object type', description='Check `>help` for valid object types.' )) if error_code: if error_code == 400: d = 'Invalid ID or URL.' elif error_code == 429: d = 'Unable to do that now, please try again in 5 minutes.' elif str(error_code).startswith('5'): d = 'Spotify is not responding.' else: d = 'Unknown error. Please try again in a few minutes and please make sure URL or ID is valid.' return await ctx.send(embed=ErrorEmbed( author=ctx.author, title=':x: An error occurred!', description=d )) elif not result: return await ctx.send(embed=ErrorEmbed( author=ctx.author, title=':x: Unable to find anything on Spotify', description='Probably URL/ID is wrong.' )) title = result['name'] # Artists if type_ not in ['artist', 'playlist']: artists = list(map(lambda x: [x['name'], x['external_urls']['spotify']], result['artists'])) elif type_ in ['playlist']: artists = [[result['owner']['display_name'], result['owner']['external_urls']['spotify']]] else: artists = None # Released if type_ == 'track': released = result['album']['release_date'] elif type_ == 'album': released = result['release_date'] else: released = None # Genres if type_ in ['artist', 'album']: genres = ', '.join(result['genres']) or 'Not specified' else: genres = None ex_url = result['external_urls']['spotify'] thumbnail = result['album']['images'][0]['url'] if type_ == 'track' else result['images'][0]['url'] # Title if title: em.add_field( name='Name' if type_ in ['artist'] else 'Title', value=title ) # Author / Artist(s) if artists: em.add_field( name='Author' if type_ == 'playlist' else 'Artist' if len(artists) == 1 else 'Artists', value=', '.join(map(lambda x: f'[{x[0]}]({x[1]} "Check it on Spotify")', artists)) ) # Followers if type_ in ['artist', 'playlist']: em.add_field( name='Followers', value=result['followers']['total'] ) # Album if type_ == 'track': em.add_field( name='Album', value=f'[{result["name"]}]({result["album"]["external_urls"]["spotify"]} "Check it on Spotify")' ) # Released if released: em.add_field( name='Released', value=released ) # Tracks if type_ in ['playlist', 'album']: em.add_field( name='Tracks', value=str(result['tracks']['total']) ) # Genres if genres: em.add_field( name='Genres', value=genres ) # Popularity if type_ in ['track', 'artist', 'album']: em.add_field( name='Popularity', value=str(result['popularity']) ) # Label elif type_ == 'album': em.add_field( name='Label', value=result['label'] ) # Spotify link if ex_url: em.add_field( name='Spotify', value=ex_url, inline=False ) # YouTube link if type_ == 'track': # Lookup YouTube query = '{} {}'.format(result['name'], ' '.join(map(lambda x: x['name'], result['artists']))) yt = SearchVideos( query, mode='dict', max_results=1 ).result() # noinspection PyTypeChecker yt = yt['search_result'][0]['link'] if yt else None em.add_field( name='YouTube', value=yt, inline=False ) # Thumbnail if thumbnail: em.set_thumbnail( url=thumbnail ) await ctx.send(embed=em) try: await ctx.message.delete() except Forbidden or NotFound or HTTPException: pass
class AuthTestSpotipy(unittest.TestCase): """ These tests require client authentication - provide client credentials using the following environment variables :: 'SPOTIPY_CLIENT_ID' 'SPOTIPY_CLIENT_SECRET' """ playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx" four_tracks = [ "spotify:track:6RtPijgfPKROxEzTHNRiDp", "spotify:track:7IHOIqZUUInxjVkko181PB", "4VrWlk8IQxevMvERoX08iC", "http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf" ] two_tracks = [ "spotify:track:6RtPijgfPKROxEzTHNRiDp", "spotify:track:7IHOIqZUUInxjVkko181PB" ] other_tracks = [ "spotify:track:2wySlB6vMzCbQrRnNGOYKa", "spotify:track:29xKs5BAHlmlX1u4gzQAbJ", "spotify:track:1PB7gRWcvefzu7t3LJLUlf" ] bad_id = 'BAD_ID' creep_urn = 'spotify:track:3HfB5hBU0dmBt8T0iCmH42' creep_id = '3HfB5hBU0dmBt8T0iCmH42' creep_url = 'http://open.spotify.com/track/3HfB5hBU0dmBt8T0iCmH42' el_scorcho_urn = 'spotify:track:0Svkvt5I79wficMFgaqEQJ' el_scorcho_bad_urn = 'spotify:track:0Svkvt5I79wficMFgaqEQK' pinkerton_urn = 'spotify:album:04xe676vyiTeYNXw15o9jT' weezer_urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu' pablo_honey_urn = 'spotify:album:6AZv3m27uyRxi8KyJSfUxL' radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb' angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM' @classmethod def setUpClass(self): self.spotify = Spotify( client_credentials_manager=SpotifyClientCredentials()) self.spotify.trace = False def test_audio_analysis(self): result = self.spotify.audio_analysis(self.four_tracks[0]) assert ('beats' in result) def test_audio_features(self): results = self.spotify.audio_features(self.four_tracks) self.assertTrue(len(results) == len(self.four_tracks)) for track in results: assert ('speechiness' in track) def test_audio_features_with_bad_track(self): bad_tracks = ['spotify:track:bad'] input = self.four_tracks + bad_tracks results = self.spotify.audio_features(input) self.assertTrue(len(results) == len(input)) for track in results[:-1]: if track is not None: assert ('speechiness' in track) self.assertTrue(results[-1] is None) def test_recommendations(self): results = self.spotify.recommendations(seed_tracks=self.four_tracks, min_danceability=0, max_loudness=0, target_popularity=50) self.assertTrue(len(results['tracks']) == 20) def test_artist_urn(self): artist = self.spotify.artist(self.radiohead_urn) self.assertTrue(artist['name'] == 'Radiohead') def test_artists(self): results = self.spotify.artists([self.weezer_urn, self.radiohead_urn]) self.assertTrue('artists' in results) self.assertTrue(len(results['artists']) == 2) def test_album_urn(self): album = self.spotify.album(self.pinkerton_urn) self.assertTrue(album['name'] == 'Pinkerton') def test_album_tracks(self): results = self.spotify.album_tracks(self.pinkerton_urn) self.assertTrue(len(results['items']) == 10) def test_album_tracks_many(self): results = self.spotify.album_tracks(self.angeles_haydn_urn) tracks = results['items'] total, received = results['total'], len(tracks) while received < total: results = self.spotify.album_tracks(self.angeles_haydn_urn, offset=received) tracks.extend(results['items']) received = len(tracks) self.assertEqual(received, total) def test_albums(self): results = self.spotify.albums( [self.pinkerton_urn, self.pablo_honey_urn]) self.assertTrue('albums' in results) self.assertTrue(len(results['albums']) == 2) def test_track_urn(self): track = self.spotify.track(self.creep_urn) self.assertTrue(track['name'] == 'Creep') def test_track_id(self): track = self.spotify.track(self.creep_id) self.assertTrue(track['name'] == 'Creep') self.assertTrue(track['popularity'] > 0) def test_track_url(self): track = self.spotify.track(self.creep_url) self.assertTrue(track['name'] == 'Creep') def test_track_bad_urn(self): try: self.spotify.track(self.el_scorcho_bad_urn) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_tracks(self): results = self.spotify.tracks([self.creep_url, self.el_scorcho_urn]) self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']) == 2) def test_artist_top_tracks(self): results = self.spotify.artist_top_tracks(self.weezer_urn) self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']) == 10) def test_artist_related_artists(self): results = self.spotify.artist_related_artists(self.weezer_urn) self.assertTrue('artists' in results) self.assertTrue(len(results['artists']) == 20) for artist in results['artists']: if artist['name'] == 'Jimmy Eat World': found = True self.assertTrue(found) def test_artist_search(self): results = self.spotify.search(q='weezer', type='artist') self.assertTrue('artists' in results) self.assertTrue(len(results['artists']['items']) > 0) self.assertTrue(results['artists']['items'][0]['name'] == 'Weezer') def test_artist_search_with_market(self): results = self.spotify.search(q='weezer', type='artist', market='GB') self.assertTrue('artists' in results) self.assertTrue(len(results['artists']['items']) > 0) self.assertTrue(results['artists']['items'][0]['name'] == 'Weezer') def test_artist_albums(self): results = self.spotify.artist_albums(self.weezer_urn) self.assertTrue('items' in results) self.assertTrue(len(results['items']) > 0) found = False for album in results['items']: if album['name'] == 'Hurley': found = True self.assertTrue(found) def test_search_timeout(self): client_credentials_manager = SpotifyClientCredentials() sp = spotipy.Spotify( client_credentials_manager=client_credentials_manager, requests_timeout=.01) try: sp.search(q='my*', type='track') self.assertTrue(False, 'unexpected search timeout') except requests.exceptions.Timeout: self.assertTrue(True, 'expected search timeout') def test_album_search(self): results = self.spotify.search(q='weezer pinkerton', type='album') self.assertTrue('albums' in results) self.assertTrue(len(results['albums']['items']) > 0) self.assertTrue( results['albums']['items'][0]['name'].find('Pinkerton') >= 0) def test_track_search(self): results = self.spotify.search(q='el scorcho weezer', type='track') self.assertTrue('tracks' in results) self.assertTrue(len(results['tracks']['items']) > 0) self.assertTrue(results['tracks']['items'][0]['name'] == 'El Scorcho') def test_user(self): user = self.spotify.user(user='******') self.assertTrue(user['uri'] == 'spotify:user:plamere') def test_track_bad_id(self): try: self.spotify.track(self.bad_id) self.assertTrue(False) except SpotifyException: self.assertTrue(True) def test_unauthenticated_post_fails(self): with self.assertRaises(SpotifyException) as cm: self.spotify.user_playlist_create("spotify", "Best hits of the 90s") self.assertTrue(cm.exception.http_status == 401 or cm.exception.http_status == 403) def test_custom_requests_session(self): sess = requests.Session() sess.headers["user-agent"] = "spotipy-test" with_custom_session = spotipy.Spotify( client_credentials_manager=SpotifyClientCredentials(), requests_session=sess) self.assertTrue( with_custom_session.user(user="******")["uri"] == "spotify:user:akx") sess.close() def test_force_no_requests_session(self): from requests import Session with_no_session = spotipy.Spotify( client_credentials_manager=SpotifyClientCredentials(), requests_session=False) self.assertFalse(isinstance(with_no_session._session, Session)) self.assertTrue( with_no_session.user(user="******")["uri"] == "spotify:user:akx")
def get_artist(sp: Spotify, artist_id: str) -> Dict[str, Any]: """Returns an artist given its ID or URI""" return sp.artist(artist_id)
class Ingestor(): def __init__(self, client_id=None, client_secret=None, dbURl=None, db_user=None, db_password=None): # spotipy Client flow if client_id is None: client_id = CLIENT_ID if client_secret is None: client_secret = CLIENT_SECRET self.client_id = client_id self.client_secret = client_secret self.client_creds = SpotifyClientCredentials( client_id=self.client_id, client_secret=self.client_secret) # creeate spotipy client self.spotipy = Spotify(auth=self.client_creds.get_access_token()) self.connector = DBConnector() def ingest(self): self.ingest_categories() def get_artist_by_name(self, name): """Retrives a list of artist obecjts based on searching for the artist name""" q = 'artist:' + name return self.spotipy.search(q, limit=10, offset=0, type='artist', market=None)['artists']['items'] def ingest_related_artist(self, artist_id, limit=NUM_REL_ARTISTS, _depth=0): """Recursively ingest artist related to a specific artist. Artist must already be in DB.""" # TODO: check if artist DNE and insert if so self.connector.update_artist(artist_id, 'ingested', 'true') ara = self.spotipy.artist_related_artists(artist_id) for i, a in enumerate(ara['artists']): if i > limit: break self.connector.insert_artist(a) self.connector.insert_related_relation(artist_id, a['id']) if _depth > 0: self.ingest_related_artist(a['id'], _depth - 1) def ingest_by_name(self, name): """Ingests the first artist from the search of on artist by name into the database""" res = self.get_artist_by_name(name)[0] self.connector.insert_artist(res) def ingest_by_id(self, artist_id): """Ingest artist by id""" res = self.spotipy.artist(artist_id) self.connector.insert_artist(res) def ingest_categories(self): """Ingest categories from spotifies list of categories""" print("Pull categories from API") categories = self.spotipy.categories()['categories']['items'] for c in tqdm(categories, desc='Inserting categories'): self.connector.insert_category(c) self.ingest_category_playlist(c['id']) def ingest_category_playlist(self, category_id): # This is a list of playlists try: play_lists = self.spotipy.category_playlists( category_id)['playlists']['items'] except SpotifyException as e: print('Category %s play list ingestion failed' % category_id) else: for p in tqdm(play_lists, desc='Insertiing Category playlists'): self.connector.insert_playlist(p) # TODO: insert playlist category relation # category id and p['id'] # TODO: ingest tracks # p['tracks'] def clear_database(self): """Clears the database this ingerstor is connected to.""" # TODO: add warning self.connector.clear_database()
class SpotifyConnection(object): def __init__(self, user_data): self.user_name = user_data['user_name'] token = spotipy.util.prompt_for_user_token( self.user_name, scope='user-read-recently-played', client_id=user_data['client_id'], client_secret=user_data['client_secret'], redirect_uri=user_data['redirect_uri']) self.client = Spotify(auth=token) self.db = self.init_db() def init_db(self): return PostgreSQLConnection() def get_artist(self, artist_id): artist = self.db.session.query(Artist).get(artist_id) if artist: return artist else: artist_response = self.client.artist(artist_id) artist = Artist() artist.artist_id = artist_id artist.artist_data = artist_response self.db.save_instance(artist) print("> Artist {} was not in database.".format( artist.artist_data['name'])) return self.db.session.query(Artist).get(artist_id) def get_album(self, album_id): album = self.db.session.query(Album).get(album_id) if album: return album else: album_response = self.client.album(album_id) album = Album() album.album_data = album_response album.album_id = album_response['id'] # Artists for album_artist_response in album_response['artists']: album.artists.append( self.get_artist(album_artist_response['id'])) self.db.save_instance(album) print("> Album {} was not in database.".format( album.album_data['name'])) return self.db.session.query(Album).get(album_id) def get_track(self, track_id): track = self.db.session.query(Track).get(track_id) if track: return track else: response = self.client.track(track_id) track = Track() track.track_id = track_id track.track_data = response # Album track.album = self.get_album(response['album']['id']) # Artists for artist_response in response['artists']: track.artists.append(self.get_artist(artist_response['id'])) # Audio feature audio_feature_response = self.client.audio_features(track_id)[0] if audio_feature_response: # Some tracks do not have audio features track.audio_feature_data = audio_feature_response print("> Track {} was not in database.".format( track.track_data['name'])) self.db.save_instance(track) return self.db.session.query(Track).get(track_id) def get_play_from_played_at_utc_and_track_id(self, played_at_utc, track_id): played_at_utc = convert_played_at_from_response_to_datetime( played_at_utc) played_at_utc = set_timezone_to_datetime(played_at_utc, timezone='UTC') played_at_cet = convert_datetime_from_timezone_to_timezone( played_at_utc, from_tz_code='UTC', to_tz_code='CET') # Play play = Play() play.user_name = self.user_name play.played_at_utc_timestamp = played_at_utc.timestamp() * 1000 play.played_at_utc = played_at_utc play.played_at_cet = played_at_cet play.day = played_at_cet.day play.month = played_at_cet.month play.year = played_at_cet.year play.hour = played_at_cet.hour play.minute = played_at_cet.minute play.second = played_at_cet.second play.day_of_week = played_at_cet.weekday() play.week_of_year = played_at_cet.date().isocalendar()[1] # Track track = self.get_track(track_id) play.track = track play.track_id = track_id return play def _get_play_tuples_from_response(self, response): plays = [] for item in response['items']: play_tuple = (item['played_at'], item['track']['id']) plays.append(play_tuple) return plays def _get_play_tuples(self, limit=50, after=None): play_tuples = [] response = self.client._get('me/player/recently-played', after=after, limit=limit) play_tuples.extend(self._get_play_tuples_from_response(response)) while response and 'next' in response: response = self.client.next(response) if response: play_tuples.extend( self._get_play_tuples_from_response(response)) return play_tuples def extract_plays(self): print("* Extracting latest plays of {}.".format(self.user_name)) play_tuples = self._get_play_tuples() for played_at, track_id in play_tuples: play = self.get_play_from_played_at_utc_and_track_id( played_at, track_id) self.db.save_play(play)