def __init__(self, session: spotipy.Spotify, album_id: str) -> None: source: Dict[str, str] = session.album(album_id) self._id: str = source["id"] self._release_date: str = str(source["release_date"]) self._release_date_precision: str = source["release_date_precision"] self._session = session
def get_album_information_from_track(sp_api: Spotify, base_track: dict): album_data: SpotifyAlbumDoc = object.__new__(SpotifyAlbumDoc) try: base_album: dict = base_track.get("album") album: dict = sp_api.album(album_id=base_album.get("id")) album_data: SpotifyAlbumDoc = SpotifyAlbumDoc(album=album) except Exception as e: logger.error(e) return album_data
class Login: def __init__(self, token): self.spo = Spotify(generate_token()) self.req = Session() self.req.cookies['arl'] = token user_id = (self.req.get("https://www.deezer.com/").text.split( "'deezer_user_id': ")[1].split(",")[0]) if user_id == "0": raise exceptions.BadCredentials("Wrong token: %s :(" % token) def get_api(self, method, api_token="null", json=None): params = { "api_version": "1.0", "api_token": api_token, "input": "3", "method": method } try: return self.req.post(api_link, params=params, json=json).json()['results'] except: return self.req.post(api_link, params=params, json=json).json()['results'] def download(self, link, name, quality, recursive_quality, recursive_download, datas, not_interface, directory, zips=False): if not quality in qualities: raise exceptions.QualityNotFound( "The qualities have to be FLAC or MP3_320 or MP3_256 or MP3_128" ) self.token = self.get_api("deezer.getUserData")['checkForm'] def get_infos(method, json): infos = None while not "MD5_ORIGIN" in str(infos): infos = self.get_api(method, self.token, json) return infos def ultimatum(infos, datas, name, quality): extension = ".mp3" ids = infos['SNG_ID'] key = "FILESIZE_" + quality if int(infos[key]) > 0 and quality == "FLAC": quality = "9" extension = ".flac" qualit = "FLAC" elif int(infos[key]) > 0 and quality == "MP3_320": quality = "3" qualit = "320" elif int(infos[key]) > 0 and quality == "MP3_256": quality = "5" qualit = "256" elif int(infos[key]) > 0 and quality == "MP3_128": quality = "1" qualit = "128" else: if not recursive_quality: raise exceptions.QualityNotFound( "The quality chosen can't be downloaded") for a in qualities: if int(infos['FILESIZE_' + a]) > 0: quality = qualities[a]['quality'] extension = qualities[a]['extension'] qualit = qualities[a]['qualit'] break else: if a == "MP3_128": raise exceptions.TrackNotFound( "There isn't any quality avalaible for download this song: %s" % name) name += " ({}){}".format(qualit, extension) if os.path.isfile(name): if recursive_download: return name ans = input( "Track %s already exists, do you want to redownload it?(y or n):" % name) if not ans in answers: return name try: md5 = infos['FALLBACK']['MD5_ORIGIN'] except KeyError: md5 = infos['MD5_ORIGIN'] hashs = genurl(md5, quality, ids, infos['MEDIA_VERSION']) try: crypt = request( "https://e-cdns-proxy-{}.dzcdn.net/mobile/1/{}".format( md5[0], hashs)) except IndexError: raise exceptions.TrackNotFound("Track: %s not found:(" % name) if len(crypt.content) == 0: raise exceptions.TrackNotFound( "Something is wrong with %s :(" % name) encry = open(name, "wb") encry.write(crypt.content) encry.close() decry = open(name, "wb") decryptfile(crypt.iter_content(2048), calcbfkey(ids), decry) write_tags(name, add_more_tags(datas, infos, ids)) return name def add_more_tags(datas, infos, ids): json = {"sng_id": ids} try: datas['author'] = " & ".join( infos['SNG_CONTRIBUTORS']['author']) except: datas['author'] = "" try: datas['composer'] = " & ".join( infos['SNG_CONTRIBUTORS']['composer']) except: datas['composer'] = "" try: datas['lyricist'] = " & ".join( infos['SNG_CONTRIBUTORS']['lyricist']) except: datas['lyricist'] = "" try: datas['version'] = infos['VERSION'] except KeyError: datas['version'] = "" need = self.get_api("song.getLyrics", self.token, json) try: datas['lyric'] = need['LYRICS_TEXT'] datas['copyright'] = need['LYRICS_COPYRIGHTS'] datas['lyricist'] = need['LYRICS_WRITERS'] except KeyError: datas['lyric'] = "" datas['copyright'] = "" datas['lyricist'] = "" return datas ids = link.split("/")[-1] if "track" in link: json = {"sng_id": ids} infos = get_infos(method_get_track, json) image = choose_img(infos['ALB_PICTURE']) datas['image'] = image song = "{} - {}".format(datas['music'], datas['artist']) if not not_interface: print("Downloading: %s" % song) try: nams = ultimatum(infos, datas, name, quality) except exceptions.TrackNotFound: url = request( "https://api.deezer.com/search/track/?q=%s" % song.replace("#", ""), True).json() try: for b in range(url['total'] + 1): if url['data'][b]['title'] == datas['music'] or datas[ 'music'] in url['data'][b]['title_short']: URL = url['data'][b]['link'] break except IndexError: raise exceptions.TrackNotFound("Track not found: %s" % song) json = {"sng_id": URL.split("/")[-1]} infos = get_infos(method_get_track, json) nams = ultimatum(infos, datas, name, quality) return nams nams = [] detas = {} zip_name = "" quali = "" json = {"alb_id": ids, "nb": -1} infos = get_infos(method_get_album, json)['data'] image = choose_img(infos[0]['ALB_PICTURE']) detas['image'] = image detas['album'] = datas['album'] detas['year'] = datas['year'] detas['genre'] = datas['genre'] detas['ar_album'] = datas['ar_album'] detas['label'] = datas['label'] for a in tqdm(range(len(name)), disable=not_interface): detas['music'] = datas['music'][a] detas['artist'] = datas['artist'][a] detas['tracknum'] = datas['tracknum'][a] detas['discnum'] = datas['discnum'][a] detas['bpm'] = datas['bpm'][a] detas['gain'] = datas['gain'][a] detas['duration'] = datas['duration'][a] detas['isrc'] = datas['isrc'][a] song = "{} - {}".format(detas['music'], detas['artist']) try: nams.append(ultimatum(infos[a], detas, name[a], quality)) except exceptions.TrackNotFound: try: url = request( "https://api.deezer.com/search/track/?q=%s" % song.replace("#", ""), True).json() for b in range(url['total'] + 1): if url['data'][b]['title'] == detas['music'] or detas[ 'music'] in url['data'][b]['title_short']: URL = url['data'][b]['link'] break json = {"sng_id": URL.split("/")[-1]} nams.append( ultimatum(get_infos(method_get_track, json), detas, name[a], quality)) except (exceptions.TrackNotFound, IndexError, exceptions.InvalidLink): nams.append(name[a]) print("Track not found: %s :(" % song) continue quali = (nams[a].split("(")[-1].split(")")[0]) if zips: zip_name = ("%s%s (%s).zip" % (directory, directory.split("/")[-2], quali)) create_zip(zip_name, nams) return nams, zip_name def download_trackdee(self, URL, output=stock_output + "/", quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface): datas = {} URL = URL.split("?utm")[0] URL1 = "https://www.deezer.com/track/%s" % URL.split("/")[-1] URL2 = "https://api.deezer.com/track/%s" % URL.split("/")[-1] url = request(URL2, True).json() url1 = request("http://api.deezer.com/album/%d" % url['album']['id'], True).json() datas['music'] = url['title'] array = [] for a in url['contributors']: if a['name'] != "": array.append(a['name']) array.append(url['artist']['name']) datas['artist'] = artist_sort(array) datas['album'] = url1['title'] datas['tracknum'] = str(url['track_position']) datas['discnum'] = str(url['disk_number']) datas['year'] = url['release_date'] datas['genre'] = [] try: for a in url1['genres']['data']: datas['genre'].append(a['name']) except KeyError: pass datas['genre'] = " & ".join(datas['genre']) datas['ar_album'] = [] for a in url1['contributors']: if a['role'] == "Main": datas['ar_album'].append(a['name']) datas['ar_album'] = " & ".join(datas['ar_album']) datas['label'] = url1['label'] datas['bpm'] = str(url['bpm']) datas['gain'] = str(url['gain']) datas['duration'] = str(url['duration']) datas['isrc'] = url['isrc'] album = var_excape(datas['album']) directory = ("%s%s %s/" % (output, album, url1['upc'])) check_dir(directory) name = ("%s%s CD %s TRACK %s" % (directory, album, datas['discnum'], datas['tracknum'])) name = self.download(URL, name, quality, recursive_quality, recursive_download, datas, not_interface, directory) return name def download_albumdee(self, URL, output=stock_output + "/", quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, zips=stock_zip): datas = {} datas['music'] = [] datas['artist'] = [] datas['tracknum'] = [] datas['discnum'] = [] datas['bpm'] = [] datas['gain'] = [] datas['duration'] = [] datas['isrc'] = [] names = [] array = [] URL = URL.split("?utm")[0] URL1 = "https://www.deezer.com/album/%s" % URL.split("/")[-1] URL2 = "https://api.deezer.com/album/%s" % URL.split("/")[-1] url = request(URL2, True).json() datas['album'] = url['title'] datas['label'] = url['label'] datas['year'] = url['release_date'] datas['genre'] = [] try: for a in url['genres']['data']: datas['genre'].append(a['name']) except KeyError: pass datas['genre'] = " & ".join(datas['genre']) datas['ar_album'] = [] for a in url['contributors']: if a['role'] == "Main": datas['ar_album'].append(a['name']) datas['ar_album'] = " & ".join(datas['ar_album']) album = var_excape(datas['album']) directory = ("%s%s %s/" % (output, album, url['upc'])) for a in url['tracks']['data']: del array[:] datas['music'].append(a['title']) ur = request("https://api.deezer.com/track/%d" % a['id'], True).json() discnum = str(ur['disk_number']) tracknum = str(ur['track_position']) names.append("%s%s CD %s TRACK %s" % (directory, album, discnum, tracknum)) datas['tracknum'].append(tracknum) datas['discnum'].append(discnum) datas['bpm'].append(str(ur['bpm'])) datas['gain'].append(str(ur['gain'])) datas['duration'].append(str(ur['duration'])) datas['isrc'].append(ur['isrc']) for a in ur['contributors']: if a['name'] != "": array.append(a['name']) array.append(ur['artist']['name']) datas['artist'].append(artist_sort(array)) check_dir(directory) names, zip_name = self.download(URL, names, quality, recursive_quality, recursive_download, datas, not_interface, directory, zips) if zips: return names, zip_name return names def download_playlistdee(self, URL, output=stock_output + "/", quality=stock_quality, recursive_quality=True, recursive_download=True, not_interface=stock_not_interface, zips=stock_zip): array = [] URL = URL.split("?utm")[0] ids = URL.split("/")[-1] url = request("https://api.deezer.com/playlist/%s" % ids, True).json() for a in url['tracks']['data']: try: array.append( self.download_trackdee(a['link'], output, quality, recursive_quality, recursive_download, not_interface)) except (exceptions.TrackNotFound, exceptions.NoDataApi): song = "{} - {}".format(a['title'], a['artist']['name']) print("Track not found: %s" % song) array.append(song) if zips: zip_name = "{}playlist {}.zip".format(output, ids) create_zip(zip_name, array) return array, zip_name return array def download_trackspo(self, URL, output=stock_output + "/", quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface): URL = URL.split("?")[0] try: url = self.spo.track(URL) except Exception as a: if not "The access token expired" in str(a): raise exceptions.InvalidLink("Invalid link ;)") self.spo = Spotify(generate_token()) url = self.spo.track(URL) isrc = url['external_ids']['isrc'] url = request("https://api.deezer.com/track/isrc:%s" % isrc, True).json() name = self.download_trackdee(url['link'], output, quality, recursive_quality, recursive_download, not_interface) return name def download_albumspo(self, URL, output=stock_output + "/", quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, zips=stock_zip): URL = URL.split("?")[0] try: tracks = self.spo.album(URL) except Exception as a: if not "The access token expired" in str(a): raise exceptions.InvalidLink("Invalid link ;)") self.spo = Spotify(generate_token()) tracks = self.spo.album(URL) tot = tracks['total_tracks'] try: upc = tracks['external_ids']['upc'] while upc[0] == "0": upc = upc[1:] url = request("https://api.deezer.com/album/upc:%s" % upc).json() names = self.download_albumdee(url['link'], output, quality, recursive_quality, recursive_download, not_interface, zips) except KeyError: search = tot // 5 try: url = self.spo.track(tracks['tracks']['items'][search] ['external_urls']['spotify']) except: self.spo = Spotify(generate_token()) url = self.spo.track(tracks['tracks']['items'][search] ['external_urls']['spotify']) isrc = url['external_ids']['isrc'] try: ids = request("https://api.deezer.com/track/isrc:%s" % isrc, True).json()['album']['id'] tracks = request("https://api.deezer.com/album/%d" % ids, True).json() if tot != tracks['nb_tracks']: raise exceptions.TrackNotFound("") names = self.download_albumdee(tracks['link'], output, quality, recursive_quality, recursive_download, not_interface, zips) except (exceptions.TrackNotFound, exceptions.NoDataApi): raise exceptions.AlbumNotFound("Album %s not found :(" % tracks['name']) return names def download_playlistspo(self, URL, output=stock_output + "/", quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, zips=stock_zip): array = [] URL = URL.split("?")[0].split("/") try: tracks = self.spo.user_playlist_tracks(URL[-3], playlist_id=URL[-1]) except Exception as a: if not "The access token expired" in str(a): raise exceptions.InvalidLink("Invalid link ;)") self.spo = Spotify(generate_token()) tracks = self.spo.user_playlist_tracks(URL[-3], playlist_id=URL[-1]) for a in tracks['items']: try: array.append( self.download_trackspo( a['track']['external_urls']['spotify'], output, quality, recursive_quality, recursive_download, not_interface)) except: print("Track not found :(") array.append("None") if tracks['total'] != 100: for a in range(tracks['total'] // 100): try: tracks = self.spo.next(tracks) except: self.spo = Spotify(generate_token()) tracks = self.spo.next(tracks) for a in tracks['items']: try: array.append( self.download_trackspo( a['track']['external_urls']['spotify'], output, quality, recursive_quality, recursive_download, not_interface)) except: print("Track not found :(") array.append("None") if zips: zip_name = "{}playlist {}.zip".format(output, URL[-1]) create_zip(zip_name, array) return array, zip_name return array def download_name(self, artist, song, output=stock_output + "/", quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface): query = "track:{} artist:{}".format(song, artist) try: search = self.spo.search(query) except: self.spo = Spotify(generate_token()) search = self.spo.search(query) try: return self.download_trackspo( search['tracks']['items'][0]['external_urls']['spotify'], output, quality, recursive_quality, recursive_download, not_interface) except IndexError: raise exceptions.TrackNotFound("Track not found: :(")
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
def Link(link, chat_id, quality, message_id): global spo global del1 del1 += 1 done = 0 quali = quality.split("MP3_")[-1] link = link.split("?")[0] ids = link.split("/")[-1] try: if "track/" in link: if "spotify" in link: try: url = spo.track(link) except Exception as a: if not "The access token expired" in str(a): sendMessage(chat_id, "Invalid link %s ;)" % link, reply_to_message_id=message_id) delete(chat_id) return spo = Spotify(generate_token()) url = spo.track(link) try: image1 = url['album']['images'][0]['url'] except IndexError: image1 = song_default_image name = url['name'] artist = url['album']['artists'][0]['name'] album = url['album']['name'] date = url['album']['release_date'] elif "deezer" in link: kind = "track" api_link = api_track % ids try: url = reque(api_link, chat_id, True).json() except AttributeError: delete(chat_id) return image1 = check_image(url['album']['cover_xl'], ids, kind) name = url['title'] artist = url['artist']['name'] album = url['album']['title'] date = url['album']['release_date'] if any(a in link for a in services_supported): sendPhoto(chat_id, image1, caption=(send_image_track_query % (name, artist, album, date))) track(link, chat_id, quality) else: sendMessage(chat_id, not_supported_links % link) elif "album/" in link: links = [] count = [0] if "spotify" in link: try: tracks = spo.album(link) except Exception as a: if not "The access token expired" in str(a): sendMessage(chat_id, "Invalid link %s ;)" % link, reply_to_message_id=message_id) delete(chat_id) return spo = Spotify(generate_token()) tracks = spo.album(link) try: image3 = tracks['images'][2]['url'] image1 = tracks['images'][0]['url'] except IndexError: image3 = image_resize(song_default_image, 90) image1 = song_default_image name = tracks['name'] artist = tracks['artists'][0]['name'] date = tracks['release_date'] tot = tracks['total_tracks'] def lazy(a): count[0] += a['duration_ms'] links.append(a['external_urls']['spotify']) for a in tracks['tracks']['items']: lazy(a) tracks = tracks['tracks'] for a in range(tot // 50 - 1): try: tracks = spo.next(tracks) except: spo = Spotify(generate_token()) tracks = spo.next(tracks) for a in tracks['items']: lazy(a) count[0] //= 1000 mode = downloa.download_albumspo elif "deezer" in link: api_link = api_album % ids kind = "album" try: url = reque(api_link, chat_id, True).json() except AttributeError: delete(chat_id) return count[0] = url['duration'] image1 = check_image(url['cover_xl'], ids, kind) image3 = image_resize(image1, 90) tot = url['nb_tracks'] links = [a['link'] for a in url['tracks']['data']] name = url['title'] artist = url['artist']['name'] date = url['release_date'] mode = downloa.download_albumdee if any(a in link for a in services_supported): if count[0] > seconds_limits_album: sendMessage( chat_id, "If you do this again I will come to your home and I will ddos your ass :)" ) delete(chat_id) return message_id = sendPhoto( chat_id, image1, caption=(send_image_album_query % (name, artist, date, tot)))['message_id'] conn = connect(db_file) c = conn.cursor() exists = [] for a in links: ids = a.split("/")[-1] lins = "track/%s" % ids exist = c.execute(where_query.format(lins, quali)).fetchone() if exist: exists.append(exist) if len(exists) < len(links) // 3: z = mode(link, quality=quality, recursive_quality=True, recursive_download=True, not_interface=not_interface) image3 = get_image(image3) for a in range(len(z)): sendAudio(chat_id, z[a], links[a], image3) else: for a in links: track(a, chat_id, quality) done = 1 else: sendMessage(chat_id, not_supported_links % link) elif "playlist/" in link: links = [] if "spotify" in link: musi = link.split("/") try: tracks = spo.user_playlist(musi[-3], musi[-1]) except Exception as a: if not "The access token expired" in str(a): sendMessage(chat_id, "Invalid link ;)", reply_to_message_id=message_id) delete(chat_id) return spo = Spotify(generate_token()) tracks = spo.user_playlist(musi[-3], musi[-1]) try: image1 = tracks['images'][0]['url'] except IndexError: image1 = song_default_image def lazy(a): try: links.append(a['track']['external_urls']['spotify']) except (KeyError, TypeError): links.append("Error :(") for a in tracks['tracks']['items']: lazy(a) added = tracks['tracks']['items'][0]['added_at'] owner = tracks['owner']['display_name'] tot = tracks['tracks']['total'] tracks = tracks['tracks'] for a in range(tot // 100 - 1): try: tracks = spo.next(tracks) except: spo = Spotify(generate_token()) tracks = spo.next(tracks) for a in tracks['items']: lazy(a) elif "deezer" in link: api_link = api_playlist % ids try: url = reque(api_link, chat_id, True).json() except AttributeError: delete(chat_id) return links = [a['link'] for a in url['tracks']['data']] image1 = url['picture_xl'] tot = url['nb_tracks'] added = url['creation_date'] owner = url['creator']['name'] if any(a in link for a in services_supported): if tot > max_songs: sendMessage(chat_id, "F**k you") delete(chat_id) return sendPhoto(chat_id, image1, caption=(send_image_playlist_query % (added, owner, tot))) for a in links: if a.startswith("http"): try: track(a, chat_id, quality) except: sendMessage(chat_id, "Cannot download %s:(" % a) else: sendMessage(chat_id, a) done = 1 else: sendMessage(chat_id, not_supported_links % link) elif "artist/" in link: if "deezer" in link: api_link = api_artist % ids try: url = reque(api_link, chat_id, True).json() except AttributeError: delete(chat_id) return keyboard = [[ InlineKeyboardButton( queries['top']['text'], callback_data=queries['top']['query'] % api_link), InlineKeyboardButton( queries['albums']['text'], callback_data=queries['albums']['query'] % api_link) ], [ InlineKeyboardButton( queries['radio']['text'], callback_data=queries['radio']['query'] % api_link), InlineKeyboardButton( queries['related']['text'], callback_data=queries['related']['query'] % api_link) ]] image1 = url['picture_xl'] artist = url['name'] albums = url['nb_album'] fans = url['nb_fan'] if any(a in link for a in services_supported[1:]): sendPhoto(chat_id, image1, caption=(send_image_artist_query % (artist, albums, fans)), reply_markup=InlineKeyboardMarkup(keyboard)) else: sendMessage(chat_id, not_supported_links % link) else: sendMessage(chat_id, not_supported_links % link) except FileNotFoundError: sendMessage(chat_id, "Resend link please...", reply_to_message_id=message_id) except error.TimedOut: sendMessage(chat_id, "Retry after a few minutes") except exceptions.QuotaExceeded: sendMessage(chat_id, "Please send the link %s again :(" % link) except exceptions.AlbumNotFound: sendMessage(chat_id, "Album %s didn't find on Deezer :(" % link) sendMessage( chat_id, "Try to search it throught inline mode or search the link on Deezer" ) except Exception as a: logging.error(a) logging.error(quality) logging.error(link) sendMessage( chat_id, "OPS :( Something went wrong please send to @AmineSoukara this link: {} {}, if this happens again" .format(link, quality)) if done == 1: sendMessage(chat_id, end_message, reply_to_message_id=message_id, reply_markup=InlineKeyboardMarkup(end_keyboard)) delete(chat_id)
def Link(link, chat_id, quality, msg): global spo global del1 del1 += 1 done = 0 links1 = [] links2 = [] quali = quality.split("MP3_")[-1] link = link.split("?")[0] try: if "spotify" in link: if "track/" in link: try: url = spo.track(link) except Exception as a: if not "The access token expired" in str(a): sendMessage( chat_id, "Invalid link %s ;)" % link, reply_to_message_id = msg['message_id'] ) delete(chat_id) return spo = Spotify( generate_token() ) url = spo.track(link) try: image1 = url['album']['images'][0]['url'] except IndexError: image1 = "https://e-cdns-images.dzcdn.net/images/cover/1000x1000-000000-80-0-0.jpg" sendPhoto( chat_id, image1, caption = ( send_image_track_query % ( url['name'], url['album']['artists'][0]['name'], url['album']['name'], url['album']['release_date'] ) ) ) track(link, chat_id, quality) elif "album/" in link: try: tracks = spo.album(link) except Exception as a: if not "The access token expired" in str(a): sendMessage( chat_id, "Invalid link %s ;)" % link, reply_to_message_id = msg['message_id'] ) delete(chat_id) return spo = Spotify( generate_token() ) tracks = spo.album(link) try: image3 = tracks['images'][2]['url'] image2 = tracks['images'][1]['url'] image1 = tracks['images'][0]['url'] except IndexError: image3 = "https://e-cdns-images.dzcdn.net/images/cover/90x90-000000-80-0-0.jpg" image2 = "https://e-cdns-images.dzcdn.net/images/cover/320x320-000000-80-0-0.jpg" image1 = "https://e-cdns-images.dzcdn.net/images/cover/1000x1000-000000-80-0-0.jpg" tot = tracks['total_tracks'] conn = connect(db_file) c = conn.cursor() lin = "album/%s" % link.split("/")[-1] count = [0] sendPhoto( chat_id, image1, caption = ( send_image_album_query % ( tracks['name'], tracks['artists'][0]['name'], tracks['release_date'], tot ) ) ) def lazy(a): count[0] += a['duration_ms'] lin = "track/%s" % a['external_urls']['spotify'].split("/")[-1] c.execute( where_query.format(lin, quali) ) links2.append(lin) if c.fetchone(): links1.append(lin) for a in tracks['tracks']['items']: lazy(a) tracks = tracks['tracks'] if tot != 50: for a in range(tot // 50): try: tracks = spo.next(tracks) except: spo = Spotify( generate_token() ) tracks = spo.next(tracks) for a in tracks['items']: lazy(a) conn.close() if (count[0] / 1000) > 40000: sendMessage(chat_id, "If you do this again I will come to your home and I will ddos your ass :)") delete(chat_id) return if len(links1) != tot: z = downloa.download_albumspo( link, quality = quality, recursive_quality = True, recursive_download = True, not_interface = True ) else: for a in links2: track(a, chat_id, quality) done = 1 elif "playlist/" in link: musi = link.split("/") try: tracks = spo.user_playlist(musi[-3], musi[-1]) except Exception as a: if not "The access token expired" in str(a): sendMessage( chat_id, "Invalid link ;)", reply_to_message_id = msg['message_id'] ) delete(chat_id) return spo = Spotify( generate_token() ) tracks = spo.user_playlist(musi[-3], musi[-1]) try: image1 = tracks['images'][0]['url'] except IndexError: image1 = "https://e-cdns-images.dzcdn.net/images/cover/1000x1000-000000-80-0-0.jpg" tot = tracks['tracks']['total'] if tot > 400: sendMessage(chat_id, "F**k you") delete(chat_id) return sendPhoto( chat_id, image1, caption = ( send_image_playlist_query % ( tracks['tracks']['items'][0]['added_at'], tracks['owner']['display_name'], tot ) ) ) def lazy(a): try: track( a['track']['external_urls']['spotify'], chat_id, quality ) except: try: sendMessage(chat_id, "%s Not found :(" % a['track']['name']) except: sendMessage(chat_id, "Error :(") for a in tracks['tracks']['items']: lazy(a) tot = tracks['tracks']['total'] tracks = tracks['tracks'] if tot != 100: for a in range(tot // 100): try: tracks = spo.next(tracks) except: spo = Spotify( generate_token() ) tracks = spo.next(tracks) for a in tracks['items']: lazy(a) done = 1 else: sendMessage(chat_id, "Sorry :( The bot doesn't support this link") elif "deezer" in link: ids = link.split("/")[-1] if "track/" in link: try: url = request( "https://api.deezer.com/track/%s" % ids, chat_id, True ).json() except AttributeError: delete(chat_id) return image1 = check_image( url['album']['cover_xl'], ids ) sendPhoto( chat_id, image1, caption = ( send_image_track_query % ( url['title'], url['artist']['name'], url['album']['title'], url['album']['release_date'] ) ) ) track(link, chat_id, quality) elif "album/" in link: try: url = request( "https://api.deezer.com/album/%s" % ids, chat_id, True ).json() except AttributeError: delete(chat_id) return if url['duration'] > 40000: sendMessage(chat_id, "If you do this again I will come to your home and I will ddos your ass :)") delete(chat_id) return image1 = url['cover_xl'] if not image1: URL = "https://www.deezer.com/album/%s" % ids image1 = request(URL).text image1 = ( BeautifulSoup(image1, "html.parser") .find("img", class_ = "img_main") .get("src") .replace("200x200", "1000x1000") ) ima = request(image1).content if len(ima) == 13: image1 = "https://e-cdns-images.dzcdn.net/images/cover/1000x1000-000000-80-0-0.jpg" image2 = image1.replace("1000x1000", "320x320") image3 = image1.replace("1000x1000", "90x90") conn = connect(db_file) c = conn.cursor() lin = "album/%s" % ids for a in url['tracks']['data']: lin = "track/%s" % a['link'].split("/")[-1] c.execute( where_query.format(lin, quali) ) links2.append(lin) if c.fetchone(): links1.append(lin) conn.close() tot = url['nb_tracks'] sendPhoto( chat_id, image1, caption = ( send_image_album_query % ( url['title'], url['artist']['name'], url['release_date'], tot ) ) ) if len(links1) != tot: z = downloa.download_albumdee( link, quality = quality, recursive_quality = True, recursive_download = True, not_interface = True ) else: for a in links2: track(a, chat_id, quality) done = 1 elif "playlist/" in link: try: url = request( "https://api.deezer.com/playlist/%s" % ids, chat_id, True ).json() except AttributeError: delete(chat_id) return tot = url['nb_tracks'] if tot > 400: sendMessage(chat_id, "F**k you") delete(chat_id) return sendPhoto( chat_id, url['picture_xl'], caption = ( send_image_playlist_query % ( url['creation_date'], url['creator']['name'], tot ) ) ) for a in url['tracks']['data']: try: track(a['link'], chat_id, quality) except: song = "{} - {}".format(a['title'], a['artist']['name']) sendMessage(chat_id, "Cannot download %s :(" % song) done = 1 elif "artist/" in link: link = "https://api.deezer.com/artist/%s" % ids try: url = request(link, chat_id, True).json() except AttributeError: delete(chat_id) return sendPhoto( chat_id, url['picture_xl'], caption = ( "👤 Artist: %s \n💽 Album numbers: %d \n👥 Fans on Deezer: %d" % ( url['name'], url['nb_album'], url['nb_fan'] ) ), reply_markup = InlineKeyboardMarkup( inline_keyboard = [ [ InlineKeyboardButton( text = "TOP 30 🔝", callback_data = "%s/top?limit=30" % link ), InlineKeyboardButton( text = "ALBUMS 💽", callback_data = "%s/albums" % link ) ], [ InlineKeyboardButton( text = "RADIO 📻", callback_data = "%s/radio" % link ), InlineKeyboardButton( text = "RELATED 🗣", callback_data = "%s/related" % link ) ] ] ) ) else: sendMessage(chat_id, "Sorry :( The bot doesn't support this link %s :(" % link) else: sendMessage(chat_id, "Sorry :( The bot doesn't support this link %s :(" % link) try: image3 = request(image3).content for a in range( len(z) ): sendAudio(chat_id, z[a], links2[a], image3) except NameError: pass except exceptions.QuotaExceeded: sendMessage(chat_id, "Please send the link %s again :(" % link) except exceptions.AlbumNotFound: sendMessage(chat_id, "Album %s didn't find on Deezer :(" % link) sendMessage(chat_id, "Try to search it throught inline mode or search the link on Deezer") except Exception as a: logging.warning(a) logging.warning(quality) logging.warning(link) sendMessage( chat_id, "OPS :( Something went wrong please send to @An0nimia this link: {} {}, if this happens again".format(link, quality) ) if done == 1: sendMessage( chat_id, "FINISHED :) Rate me here https://t.me/BotsArchive/298", reply_to_message_id = msg['message_id'], reply_markup = InlineKeyboardMarkup( inline_keyboard = [ [ InlineKeyboardButton( text = "SHARE", url = "tg://msg?text=Start @%s for download all the songs which you want ;)" % bot_name ) ] ] ) ) delete(chat_id)
def get_album(sp: Spotify, album_id: str) -> Dict[str, Any]: """Returns an album given its ID or URI""" return sp.album(album_id)
def main(): clientRedirect = "http://localhost/" username = "******" scope = "playlist-read-collaborative " \ "playlist-read-private " \ "user-library-read " \ "playlist-modify-public " \ "playlist-modify-private" token = util.prompt_for_user_token(username, scope, clientID, clientSecret, clientRedirect) spotify = Spotify(auth=token) result = spotify.current_user_saved_tracks(offset=0, limit=50) data = {} songs = {} exceptions = ("Depeche Mode", "Grant Miller", "Madonna", "Ministry", "The Beach Boys", "Mickey & Sylvia", "The Clovers", "Village People", "Frank Sinatra", "Rodríguez", "The Bangles", "U2", "UB40", "Tom Petty", "Faces", "Bobby McFerrin", "Dion", "Fancy", "Eddy Huntington", "Michael Jackson", "OutKast", "Gorillaz", "Diddy", "Lipps Inc.", "Chuck Berry", "Marvin Gaye", "The Kinks", "Count Basie", "Player", "Steve Lawrence", "Nelly", "The Killers", "Billy Idol", "Haddaway", "Blondie") dontwant = ("Emile Van Krieken") '''while result["next"]: for track in result["items"]: songs.update(track["track"]["name"]) result = spotify.next(result) data = {username: songs}''' num = 0 playlist_id = "" for playlist in spotify.current_user_playlists()["items"]: if playlist["name"] == "Computer Generated Old 2": playlist_id = playlist["id"] exceptions_list = [] while result["next"]: for track in result["items"]: num = num + 1 print(num) track = track["track"] '''songs.update({track["uri"]: {"track": track["name"], "artist": track["artists"][0]["name"], "artist uri": track["artists"][0]["uri"], "album": track["album"]["name"], "album uri": track["album"]["uri"] } })''' album = spotify.album(track["album"]["id"]) '''if (int(album["release_date"][0:4]) < 2000 or track["artists"][0]["name"] in exceptions): #and int(album["release_date"][0:4]) > 2006)\ #print(track["uri"]) print(track["id"]) print(track["name"]) spotify.user_playlist_add_tracks("karan.arora.28", playlist_id, [track["uri"]])''' if (int(album["release_date"][0:4]) < 2006) or track["artists"][0]["name"] in exceptions: spotify.user_playlist_add_tracks("karan.arora.28", playlist_id, [track["uri"]]) if track["artists"][0]["name"] not in exceptions_list: exceptions_list.append(track["artists"][0]["name"]) print(exceptions_list) '''else: #pid = getPlaylistIDByName(spotify, "Old??") pid = "2qSyS6sDfEGSS38cn4GR8U" if trackInPlaylist(spotify, track["name"], pid): print(track["name"]) print(track["artists"][0]["name"]) num = num +1 print(num)''' result = spotify.next(result) #spotify. #spotify.user_playlist_create(clientID, "Python Old", False, "") #albumuri #artist Name and URI #when track was added #track name and URI #From this data, get when album was released, get genres, #username -> playlists -> songs -> songs contain all the data about genres and artists, etc. '''data = songs
class Login: def __init__(self, mail, password, token=None): self.spo = Spotify(auth=generate_token()) self.req = requests.Session() check = self.get_api("deezer.getUserData")['checkFormLogin'] post_data = { "type": "login", "mail": mail, "password": password, "checkFormLogin": check } end = self.req.post("https://www.deezer.com/ajax/action.php", post_data).text if "success" == end: print("Success, you are in :)") else: if not token: raise BadCredentials(end + ", and no token provided") self.req.cookies["arl"] = token if self.req.get("https://www.deezer.com/").text.split( "'deezer_user_id': ")[1].split(",")[0] == "0": raise BadCredentials("Wrong token :(") def get_api(self, method=None, api_token="null", json=None): params = { "api_version": "1.0", "api_token": api_token, "input": "3", "method": method } try: return self.req.post("http://www.deezer.com/ajax/gw-light.php", params=params, json=json).json()['results'] except: return self.req.post("http://www.deezer.com/ajax/gw-light.php", params=params, json=json).json()['results'] def download(self, link, name, quality, recursive_quality, recursive_download, datas, create_zip=False): if not quality in qualities: raise QualityNotFound( "The qualities have to be FLAC or MP3_320 or MP3_256 or MP3_128" ) def login(method, json): infos = "" while not "MD5_ORIGIN" in str(infos): self.token = self.get_api("deezer.getUserData")['checkForm'] infos = self.get_api(method, self.token, json) return infos def ultimatum(infos, name, datas, quality, recursive_download, recursive_quality): extension = ".mp3" ids = infos['SNG_ID'] if int(infos['FILESIZE_' + quality]) > 0 and quality == "FLAC": quality = "9" extension = ".flac" qualit = "FLAC" elif int( infos['FILESIZE_' + quality]) > 0 and quality == "MP3_320": quality = "3" qualit = "320" elif int( infos['FILESIZE_' + quality]) > 0 and quality == "MP3_256": quality = "5" qualit = "256" elif int( infos['FILESIZE_' + quality]) > 0 and quality == "MP3_128": quality = "1" qualit = "128" else: if recursive_quality: raise QualityNotFound( "The quality chosen can't be downloaded") for a in qualities: if int(infos['FILESIZE_' + a]) > 0: quality = qualities[a]['quality'] extension = qualities[a]['extension'] qualit = qualities[a]['qualit'] break else: if a == "MP3_128": raise TrackNotFound( "There isn't any quality avalaible for download this song" ) name += " (" + qualit + ")" + extension if os.path.isfile(name): if not recursive_download: return name ans = input( "Track " + name + " already exists, do you want to redownload it?(y or n):") if ans != "y": return name try: md5 = infos['FALLBACK']['MD5_ORIGIN'] except KeyError: md5 = infos['MD5_ORIGIN'] hashs = genurl(md5, quality, ids, infos['MEDIA_VERSION']) try: crypt = request( "https://e-cdns-proxy-%s.dzcdn.net/mobile/1/%s" % (md5[0], hashs)) except IndexError: raise TrackNotFound("Track not found :(") if len(crypt.content) == 0: raise TrackNotFound("Error with this track :(") open(name, "wb").write(crypt.content) decry = open(name, "wb") decryptfile(crypt.iter_content(2048), calcbfkey(ids), decry) datas = add_more_tags(datas, infos, ids) write_tags(name, datas) return name def add_more_tags(datas, infos, ids): try: datas['author'] = " & ".join( infos['SNG_CONTRIBUTORS']['author']) except: datas['author'] = "" try: datas['composer'] = " & ".join( infos['SNG_CONTRIBUTORS']['composer']) except: datas['composer'] = "" try: datas['lyricist'] = " & ".join( infos['SNG_CONTRIBUTORS']['lyricist']) except: datas['lyricist'] = "" try: datas['version'] = infos['VERSION'] except KeyError: datas['version'] = "" need = self.get_api("song.getLyrics", self.token, {"sng_id": ids}) try: datas['lyric'] = need['LYRICS_TEXT'] datas['copyright'] = need['LYRICS_COPYRIGHTS'] datas['lyricist'] = need['LYRICS_WRITERS'] except KeyError: datas['lyric'] = "" datas['copyright'] = "" datas['lyricist'] = "" return datas ids = link.split("/")[-1] zip_name = "" quali = "" if "track" in link: method = "song.getData" json = {"sng_id": ids} infos = login(method, json) image = request("https://e-cdns-images.dzcdn.net/images/cover/" + infos['ALB_PICTURE'] + "/1200x1200-000000-80-0-0.jpg").content if len(image) == 13: image = request( "https://e-cdns-images.dzcdn.net/images/cover/1200x1200-000000-80-0-0.jpg" ).content datas['image'] = image song = datas['music'] + " - " + datas['artist'] song = var_excape(song) print("\nDownloading:" + song) try: nams = ultimatum(infos, name, datas, quality, recursive_download, recursive_quality) except TrackNotFound: url = request( "https://api.deezer.com/search/track/?q=" + datas['music'].replace("#", "") + " + " + datas['artist'].replace("#", ""), True).json() try: for b in range(url['total'] + 1): if url['data'][b]['title'] == datas['music'] or datas[ 'music'] in url['data'][b]['title_short']: URL = url['data'][b]['link'] break except IndexError: raise TrackNotFound("Track not found: " + song) json = {"sng_id": URL.split("/")[-1]} infos = login(method, json) nams = ultimatum(infos, name, datas, quality, recursive_download, recursive_quality) else: nams = [] detas = {} method = "song.getListByAlbum" json = {"alb_id": ids, "nb": -1} infos = login(method, json)['data'] image = request("https://e-cdns-images.dzcdn.net/images/cover/" + infos[0]['ALB_PICTURE'] + "/1200x1200-000000-80-0-0.jpg").content if len(image) == 13: image = request( "https://e-cdns-images.dzcdn.net/images/cover/1200x1200-000000-80-0-0.jpg" ).content detas['image'] = image detas['album'] = datas['album'] detas['year'] = datas['year'] detas['genre'] = datas['genre'] detas['ar_album'] = datas['ar_album'] detas['label'] = datas['label'] for a in tqdm(range(len(name))): detas['music'] = datas['music'][a] detas['artist'] = datas['artist'][a] detas['tracknum'] = datas['tracknum'][a] detas['discnum'] = datas['discnum'][a] detas['bpm'] = datas['bpm'][a] detas['gain'] = datas['gain'][a] detas['duration'] = datas['duration'][a] detas['isrc'] = datas['isrc'][a] try: nams.append( ultimatum(infos[a], name[a], detas, quality, recursive_download, recursive_quality)) except TrackNotFound: url = request( "https://api.deezer.com/search/track/?q=" + detas['music'].replace("#", "") + " + " + detas['artist'].replace("#", ""), True).json() try: for b in range(url['total'] + 1): if url['data'][b]['title'] == detas[ 'music'] or detas['music'] in url['data'][ b]['title_short']: URL = url['data'][b]['link'] break except IndexError: nams.append(name[a]) print("\nTrack not found: " + detas['music'] + " - " + detas['artist']) continue try: method = "song.getData" json = {"sng_id": URL.split("/")[-1]} nams.append( ultimatum(login(method, json), name[a], detas, quality, recursive_download, recursive_quality)) except TrackNotFound: nams.append(name[a]) print("\nTrack not found: " + detas['music'] + " - " + detas['artist']) continue quali = nams[a].split("(")[-1].split(")")[0] if create_zip: dir = "/".join(name[a].split("/")[:-1]) + "/" if len(nams) > 0: zip_name = dir + dir.split( "/")[-2] + " (" + quali + ").zip" z = zipfile.ZipFile(zip_name, "w", zipfile.ZIP_DEFLATED) for a in nams: b = a.split("/")[-1] try: z.write(a, b) except FileNotFoundError: pass z.close() return nams, zip_name def download_trackdee(self, URL, output=localdir + "/Songs/", quality="MP3_320", recursive_quality=True, recursive_download=True): datas = {} if "?utm" in URL: URL, a = URL.split("?utm") URL1 = "https://www.deezer.com/track/" + URL.split("/")[-1] URL2 = "https://api.deezer.com/track/" + URL.split("/")[-1] url = request(URL2, True).json() url1 = request( "http://api.deezer.com/album/" + str(url['album']['id']), True).json() datas['music'] = url['title'] array = [] for a in url['contributors']: array.append(a['name']) array.append(url['artist']['name']) if len(array) > 1: for a in array: for b in array: if a in b and a != b: array.remove(b) datas['artist'] = ", ".join(OrderedDict.fromkeys(array)) datas['album'] = url1['title'] datas['tracknum'] = str(url['track_position']) datas['discnum'] = str(url['disk_number']) datas['year'] = url['release_date'] datas['genre'] = [] try: for a in url1['genres']['data']: datas['genre'].append(a['name']) except KeyError: pass datas['genre'] = " & ".join(datas['genre']) datas['ar_album'] = [] for a in url1['contributors']: if a['role'] == "Main": datas['ar_album'].append(a['name']) datas['ar_album'] = " & ".join(datas['ar_album']) datas['label'] = url1['label'] datas['bpm'] = str(url['bpm']) datas['gain'] = str(url['gain']) datas['duration'] = str(url['duration']) datas['isrc'] = url['isrc'] album = var_excape(datas['album']) dir = output + album + " " + url1['upc'] + "/" try: os.makedirs(dir) except FileExistsError: pass name = dir + album + " CD " + datas['discnum'] + " TRACK " + datas[ 'tracknum'] name, a = self.download(URL, name, quality, recursive_quality, recursive_download, datas) return name def download_albumdee(self, URL, output=localdir + "/Songs/", quality="MP3_320", recursive_quality=True, recursive_download=True, create_zip=False): datas = {} datas['music'] = [] datas['artist'] = [] datas['tracknum'] = [] datas['discnum'] = [] datas['bpm'] = [] datas['gain'] = [] datas['duration'] = [] datas['isrc'] = [] names = [] array = [] if "?utm" in URL: URL, a = URL.split("?utm") URL1 = "https://www.deezer.com/album/" + URL.split("/")[-1] URL2 = "https://api.deezer.com/album/" + URL.split("/")[-1] url = request(URL2, True).json() datas['album'] = url['title'] datas['label'] = url['label'] datas['year'] = url['release_date'] datas['genre'] = [] try: for a in url['genres']['data']: datas['genre'].append(a['name']) except KeyError: pass datas['genre'] = " & ".join(datas['genre']) datas['ar_album'] = [] for a in url['contributors']: if a['role'] == "Main": datas['ar_album'].append(a['name']) datas['ar_album'] = " & ".join(datas['ar_album']) album = var_excape(datas['album']) dir = output + "/" + album + " " + url['upc'] + "/" for a in url['tracks']['data']: del array[:] datas['music'].append(a['title']) ur = request("https://api.deezer.com/track/" + str(a['id']), True).json() discnum = str(ur['disk_number']) tracknum = str(ur['track_position']) names.append(dir + album + " CD " + discnum + " TRACK " + tracknum) datas['tracknum'].append(tracknum) datas['discnum'].append(discnum) datas['bpm'].append(str(ur['bpm'])) datas['gain'].append(str(ur['gain'])) datas['duration'].append(str(ur['duration'])) datas['isrc'].append(ur['isrc']) for a in ur['contributors']: array.append(a['name']) array.append(ur['artist']['name']) if len(array) > 1: for a in array: for b in array: if a in b and a != b: array.remove(b) datas['artist'].append(", ".join(OrderedDict.fromkeys(array))) try: os.makedirs(dir) except FileExistsError: pass names, zip_name = self.download(URL, names, quality, recursive_quality, recursive_download, datas, create_zip) if create_zip: return names, zip_name return names def download_playlistdee(self, URL, output=localdir + "/Songs/", quality="MP3_320", recursive_quality=True, recursive_download=True): array = [] if "?utm" in URL: URL, a = URL.split("?utm") url = request("https://api.deezer.com/playlist/" + URL.split("/")[-1], True).json() for a in url['tracks']['data']: try: array.append( self.download_trackdee(a['link'], output, quality, recursive_quality, recursive_download)) except TrackNotFound: print("\nTrack not found " + a['title']) array.append("None") return array def download_trackspo(self, URL, output=localdir + "/Songs/", quality="MP3_320", recursive_quality=True, recursive_download=True): if "?" in URL: URL, a = URL.split("?") try: url = self.spo.track(URL) except Exception as a: if not "The access token expired" in str(a): raise InvalidLink("Invalid link ;)") self.spo = Spotify(auth=generate_token()) url = self.spo.track(URL) isrc = url['external_ids']['isrc'] url = request("https://api.deezer.com/track/isrc:" + isrc, True).json() name = self.download_trackdee(url['link'], output, quality, recursive_quality, recursive_download) return name def download_albumspo(self, URL, output=localdir + "/Songs/", quality="MP3_320", recursive_quality=True, recursive_download=True, create_zip=False): if "?" in URL: URL, a = URL.split("?") try: tracks = self.spo.album(URL) except Exception as a: if not "The access token expired" in str(a): raise InvalidLink("Invalid link ;)") self.spo = Spotify(auth=generate_token()) tracks = self.spo.album(URL) try: upc = tracks['external_ids']['upc'] while upc[0] == "0": upc = upc[1:] url = request("https://api.deezer.com/album/upc:" + upc).json() names = self.download_albumdee(url['link'], output, quality, recursive_quality, recursive_download, create_zip) except KeyError: search = len(tracks['tracks']['items']) // 8 try: url = self.spo.track(tracks['tracks']['items'][search] ['external_urls']['spotify']) except: self.spo = Spotify(auth=generate_token()) url = self.spo.track(tracks['tracks']['items'][search] ['external_urls']['spotify']) isrc = url['external_ids']['isrc'] try: url = request("https://api.deezer.com/track/isrc:" + isrc, True).json() names = self.download_albumdee(url['album']['link'], output, quality, recursive_quality, recursive_download, create_zip) except TrackNotFound: raise AlbumNotFound("Album not found :(") return names def download_playlistspo(self, URL, output=localdir + "/Songs/", quality="MP3_320", recursive_quality=True, recursive_download=True): array = [] if "?" in URL: URL, a = URL.split("?") URL = URL.split("/") try: tracks = self.spo.user_playlist_tracks(URL[-3], playlist_id=URL[-1]) except Exception as a: if not "The access token expired" in str(a): raise InvalidLink("Invalid link ;)") self.spo = Spotify(auth=generate_token()) tracks = self.spo.user_playlist_tracks(URL[-3], playlist_id=URL[-1]) for a in tracks['items']: try: array.append( self.download_trackspo( a['track']['external_urls']['spotify'], output, quality, recursive_quality, recursive_download)) except: print("\nTrack not found :(") array.append("None") if tracks['total'] != 100: for a in range(tracks['total'] // 100): try: tracks = self.spo.next(tracks) except: self.spo = Spotify(auth=generate_token()) tracks = self.spo.next(tracks) for a in tracks['items']: try: array.append( self.download_trackspo( a['track']['external_urls']['spotify'], output, quality, recursive_quality, recursive_download)) except: print("\nTrack not found :(") array.append("None") return array def download_name(self, artist, song, output=localdir + "/Songs/", quality="MP3_320", recursive_quality=True, recursive_download=True): try: search = self.spo.search(q="track:" + song + " artist:" + artist) except: self.spo = Spotify(auth=generate_token()) search = self.spo.search(q="track:" + song + " artist:" + artist) try: return self.download_trackspo( search['tracks']['items'][0]['external_urls']['spotify'], output, quality, recursive_quality, recursive_download) except IndexError: raise TrackNotFound("Track not found: " + artist + " - " + song)
class Login: def __init__(self, token): self.spo = Spotify(utils.generate_token()) self.req = Session() self.req.cookies["arl"] = token self.get_user_data = methods.method_get_user_data self.private_api_link = deezer_settings.private_api_link user_id = self.get_api(self.get_user_data)["USER"]["USER_ID"] if user_id == 0: raise exceptions.BadCredentials("Wrong token: %s :(" % token) self.qualities = deezer_settings.qualities self.songs_server = deezer_settings.songs_server self.get_song_data = methods.method_get_song_data self.get_lyric = methods.method_get_lyric self.get_album = methods.method_get_album self.get_album_data = methods.method_get_album_data self.api_track = deezer_settings.api_track self.api_album = deezer_settings.api_album self.api_playlist = deezer_settings.api_playlist def get_api(self, method, api_token="null", json_data=None): params = { "api_version": "1.0", "api_token": api_token, "input": "3", "method": method, } try: return self.req.post( self.private_api_link, params=params, json=json_data ).json()["results"] except: return self.req.post( self.private_api_link, params=params, json=json_data ).json()["results"] def download( self, link, details, recursive_quality=None, recursive_download=None, not_interface=None, zips=False, ): if not details["quality"] in self.qualities: raise exceptions.QualityNotFound( "The qualities have to be FLAC or MP3_320 or MP3_256 or MP3_128" ) self.token = self.get_api(self.get_user_data)["checkForm"] ids = utils.get_ids(link) datas = details["datas"] quality = details["quality"] output = details["output"] def get_infos(method, json_data): infos = self.get_api(method, self.token, json_data) return infos def check_quality_song(infos, datas): ids = infos["SNG_ID"] num_quality = self.qualities[quality]["n_quality"] file_format = self.qualities[quality]["f_format"] song_quality = self.qualities[quality]["s_quality"] song_md5, version = utils.check_md5_song(infos) song_hash = download_utils.genurl(song_md5, num_quality, ids, version) try: crypted_audio = utils.song_exist(song_md5[0], song_hash) except (IndexError, exceptions.TrackNotFound): if not recursive_quality: raise exceptions.QualityNotFound( "The quality chosen can't be downloaded" ) for a in self.qualities: if details["quality"] == a: continue num_quality = self.qualities[a]["n_quality"] file_format = self.qualities[a]["f_format"] song_quality = self.qualities[a]["s_quality"] song_hash = download_utils.genurl( song_md5, num_quality, ids, infos["MEDIA_VERSION"] ) try: crypted_audio = utils.song_exist(song_md5[0], song_hash) except exceptions.TrackNotFound: raise exceptions.TrackNotFound("Error with this song %s" % link) album = utils.var_excape(datas["album"]) directory = "%s%s %s/" % ("%s/" % output, album, datas["upc"]) name = "%s%s CD %s TRACK %s" % ( directory, album, datas["discnum"], datas["tracknum"], ) utils.check_dir(directory) name += " ({}){}".format(song_quality, file_format) if isfile(name): if recursive_download: return name ans = input( "Track %s already exists, do you want to redownload it? (y or n):" % name ) if not ans in answers: return name decrypted_audio = open(name, "wb") download_utils.decryptfile( crypted_audio.iter_content(2048), download_utils.calcbfkey(ids), decrypted_audio, ) utils.write_tags(name, add_more_tags(datas, infos, ids)) return name def add_more_tags(datas, infos, ids): json_data = {"sng_id": ids} try: datas["author"] = " & ".join(infos["SNG_CONTRIBUTORS"]["author"]) except: datas["author"] = "" try: datas["composer"] = " & ".join(infos["SNG_CONTRIBUTORS"]["composer"]) except: datas["composer"] = "" try: datas["lyricist"] = " & ".join(infos["SNG_CONTRIBUTORS"]["lyricist"]) except: datas["lyricist"] = "" try: datas["version"] = infos["VERSION"] except KeyError: datas["version"] = "" need = get_infos(self.get_lyric, json_data) try: datas["lyric"] = need["LYRICS_TEXT"] datas["copyright"] = need["LYRICS_COPYRIGHTS"] datas["lyricist"] = need["LYRICS_WRITERS"] except KeyError: datas["lyric"] = "" datas["copyright"] = "" datas["lyricist"] = "" return datas def tracking2(infos, datas): image = utils.choose_img(infos["ALB_PICTURE"]) datas["image"] = image song = "{} - {}".format(datas["music"], datas["artist"]) if not not_interface: print("Downloading: %s" % song) try: nams = check_quality_song(infos, datas) except exceptions.TrackNotFound: try: ids = utils.not_found(song, datas["music"]) except IndexError: raise exceptions.TrackNotFound("Track not found: %s" % song) json_data = {"sng_id": ids} infos = get_infos(self.get_song_data, json_data) nams = check_quality_song(infos, datas) return nams if "track" in link: json_data = {"sng_id": ids} infos = get_infos(self.get_song_data, json_data) nams = tracking2(infos, datas) return nams zip_name = "" if "album" in link: nams = [] detas = {} quali = "" json_data = {"alb_id": ids, "nb": -1} infos = get_infos(self.get_album, json_data)["data"] image = utils.choose_img(infos[0]["ALB_PICTURE"]) detas["image"] = image detas["album"] = datas["album"] detas["year"] = datas["year"] detas["genre"] = datas["genre"] detas["ar_album"] = datas["ar_album"] detas["label"] = datas["label"] detas["upc"] = datas["upc"] t = tqdm(range(len(infos)), desc=detas["album"], disable=not_interface) for a in t: detas["music"] = datas["music"][a] detas["artist"] = datas["artist"][a] detas["tracknum"] = datas["tracknum"][a] detas["discnum"] = datas["discnum"][a] detas["bpm"] = datas["bpm"][a] detas["duration"] = datas["duration"][a] detas["isrc"] = datas["isrc"][a] song = "{} - {}".format(detas["music"], detas["artist"]) t.set_description_str(song) try: nams.append(check_quality_song(infos[a], detas)) except exceptions.TrackNotFound: try: ids = utils.not_found(song, detas["music"]) json = {"sng_id": ids} nams.append( check_quality_song( get_infos(self.get_song_data, json), detas ) ) except (exceptions.TrackNotFound, IndexError): nams.append(song) print("Track not found: %s :(" % song) continue quali = nams[a].split("(")[-1].split(")")[0] if zips: album = utils.var_excape(datas["album"]) directory = "%s%s %s/" % ("%s/" % output, album, datas["upc"]) zip_name = "%s%s (%s).zip" % (directory, album, quali) try: utils.create_zip(zip_name, nams) except FileNotFoundError: raise exceptions.QualityNotFound( 'Can\'t download album "{}" in {} quality'.format( album, details["quality"] ) ) elif "playlist" in link: json_data = {"playlist_id": ids, "nb": -1} infos = get_infos(methods.method_get_playlist_data, json_data)["data"] nams = [] for a in range(len(infos)): try: nams.append(tracking2(infos[a], datas[a])) except TypeError: c = infos[a] song = "{} - {}".format(c["SNG_TITLE"], c["ART_NAME"]) nams.append("Track not found") quali = "ALL" if zips: zip_name = "%s %s (%s).zip" % ("%s/playlist" % output, ids, quali) utils.create_zip(zip_name, nams) return nams, zip_name def download_trackdee( self, URL, output=stock_output, quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, ): datas = {} ids = utils.get_ids(URL) URL2 = self.api_track % ids datas = utils.tracking(URL2) details = {"datas": datas, "quality": quality, "output": output} name = self.download( URL2, details, recursive_quality, recursive_download, not_interface ) return name def download_albumdee( self, URL, output=stock_output, quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, zips=stock_zip, ): datas = {} datas["music"] = [] datas["artist"] = [] datas["tracknum"] = [] datas["discnum"] = [] datas["bpm"] = [] datas["duration"] = [] datas["isrc"] = [] names = [] ids = utils.get_ids(URL) URL2 = self.api_album % ids album_json = utils.request(URL2, True).json() datas["album"] = album_json["title"] datas["label"] = album_json["label"] datas["year"] = album_json["release_date"] datas["upc"] = album_json["upc"] datas["genre"] = [] try: for a in album_json["genres"]["data"]: datas["genre"].append(a["name"]) except KeyError: pass datas["genre"] = " & ".join(datas["genre"]) datas["ar_album"] = [] for a in album_json["contributors"]: if a["role"] == "Main": datas["ar_album"].append(a["name"]) datas["ar_album"] = " & ".join(datas["ar_album"]) for a in album_json["tracks"]["data"]: URL3 = self.api_track % str(a["id"]) detas = utils.tracking(URL3, True) datas["music"].append(detas["music"]) discnum = detas["discnum"] tracknum = detas["tracknum"] datas["tracknum"].append(tracknum) datas["discnum"].append(discnum) datas["bpm"].append(detas["bpm"]) datas["duration"].append(detas["duration"]) datas["isrc"].append(detas["isrc"]) datas["artist"].append(detas["artist"]) details = {"datas": datas, "quality": quality, "output": output} names, zip_name = self.download( URL2, details, recursive_quality, recursive_download, not_interface, zips ) if zips: return names, zip_name return names def download_playlistdee( self, URL, output=stock_output, quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, zips=stock_zip, ): datas = [] ids = utils.get_ids(URL) URL2 = self.api_playlist % ids playlist_json = utils.request(URL2, True).json()["tracks"]["data"] for a in playlist_json: URL3 = self.api_track % str(a["id"]) try: detas = utils.tracking(URL3) datas.append(detas) except exceptions.NoDataApi: datas.append(None) details = {"datas": datas, "quality": quality, "output": output} names, zip_name = self.download( URL2, details, recursive_quality, recursive_download, not_interface, zips ) if zips: return names, zip_name return names def download_trackspo( self, URL, output=stock_output, quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, ): URL = URL.split("?")[0] try: url = self.spo.track(URL) except Exception as a: if not "The access token expired" in str(a): raise exceptions.InvalidLink("Invalid link ;)") self.spo = Spotify(utils.generate_token()) url = self.spo.track(URL) isrc = "isrc:%s" % url["external_ids"]["isrc"] url = utils.request(self.api_track % isrc, True).json() name = self.download_trackdee( url["link"], output, quality, recursive_quality, recursive_download, not_interface, ) return name def download_albumspo( self, URL, output=stock_output, quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, zips=stock_zip, ): URL = URL.split("?")[0] try: tracks = self.spo.album(URL) except Exception as a: if not "The access token expired" in str(a): raise exceptions.InvalidLink("Invalid link ;)") self.spo = Spotify(utils.generate_token()) tracks = self.spo.album(URL) try: upc = "0%s" % tracks["external_ids"]["upc"] while upc[0] == "0": upc = upc[1:] try: upc = "upc:%s" % upc url = utils.request(self.api_album % upc, True).json() names = self.download_albumdee( url["link"], output, quality, recursive_quality, recursive_download, not_interface, zips, ) break except exceptions.NoDataApi: if upc[0] != "0": raise KeyError except KeyError: tot = tracks["total_tracks"] for a in tracks["tracks"]["items"]: try: isrc = self.spo.track(a["external_urls"]["spotify"])[ "external_ids" ]["isrc"] except: self.spo = Spotify(utils.generate_token()) isrc = self.spo.track(a["external_urls"]["spotify"])[ "external_ids" ]["isrc"] try: isrc = "isrc:%s" % isrc ids = utils.request(self.api_track % isrc, True).json()["album"][ "id" ] tracks = utils.request(self.api_album % str(ids), True).json() if tot == tracks["nb_tracks"]: break except exceptions.NoDataApi: pass try: if tot != tracks["nb_tracks"]: raise KeyError names = self.download_albumdee( tracks["link"], output, quality, recursive_quality, recursive_download, not_interface, zips, ) except KeyError: raise exceptions.AlbumNotFound("Album not found :(") return names def download_playlistspo( self, URL, output=stock_output, quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, zips=stock_zip, ): array = [] URL = URL.split("?")[0].split("/") try: tracks = self.spo.user_playlist_tracks(URL[-3], URL[-1]) except Exception as a: if not "The access token expired" in str(a): raise exceptions.InvalidLink("Invalid link ;)") self.spo = Spotify(utils.generate_token()) tracks = self.spo.user_playlist_tracks(URL[-3], URL[-1]) def lazy(tracks): for a in tracks["items"]: try: array.append( self.download_trackspo( a["track"]["external_urls"]["spotify"], output, quality, recursive_quality, recursive_download, not_interface, ) ) except: print("Track not found :(") array.append("None") lazy(tracks) tot = tracks["total"] for a in range(tot // 100 - 1): try: tracks = self.spo.next(tracks) except: self.spo = Spotify(utils.generate_token()) tracks = self.spo.next(tracks) lazy(tracks) if zips: zip_name = "{}playlist {}.zip".format(output, URL[-1]) utils.create_zip(zip_name, array) return array, zip_name return array def download_name( self, artist, song, output=stock_output, quality=stock_quality, recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, ): query = "track:{} artist:{}".format(song, artist) try: search = self.spo.search(query) except: self.spo = Spotify(utils.generate_token()) search = self.spo.search(query) try: return self.download_trackspo( search["tracks"]["items"][0]["external_urls"]["spotify"], output, quality, recursive_quality, recursive_download, not_interface, ) except IndexError: raise exceptions.TrackNotFound("Track not found")
def main(): scope = "user-read-playback-state,user-modify-playback-state" sp = Spotify(client_credentials_manager=SpotifyClientCredentials(), auth_manager=SpotifyOAuth(scope=scope)) allchars = 'qwertyuiopasdfghjklzxcvbnm' market = "CA" # start with a canadian market (this will change later) while True: try: # normally get a ReadTimeoutError but I don't actually care what the error is - I just want it to power through until I stop it manually # initiate random query char = random.choice(allchars) n = 10000 offset = random.randint(0, n - 1) # random spot on the list try: results = sp.search( q='%' + char + '%', type='track', offset=offset, market=market ) # start a query with the letter somewhere in the middle - results ordered by popularity except: # most queries don't return n results continue # parse query result = results['tracks']['items'][ 0] # select the "first" song (offset by up to n) album_id = result['album']['id'] album_ = sp.album(album_id) markets = album_['available_markets'] market = random.choice(markets) # choose new market artists = result['artists'] # filter if result['explicit']: # skip explicit continue skip_artist = False for artist in artists: if artist['name'] in [ 'Daddy Yankee', 'J Balvin', 'Don Omar', 'Bad Bunny', 'KAROL G', 'Wisin & Yandel' ]: # skip reggaeton skip_artist = True break if skip_artist: continue # play track sp.start_playback(uris=['spotify:track:' + result['id'] ]) # play track sleep(0.5) # wait for track to start pprint(result) # simplest event listener while True: # start next track when current one finishes while True: if sp.current_playback( )['progress_ms']: # playback started break sleep(0.1) # don't consume too much CPU while True: if not sp.current_playback( )['progress_ms']: # playback stopped # Triggers at end of track (a simple method for which I didn't find) # Doesn't trigger if paused as long as progress is nonzero # In theory, can trigger if track is set back to start while playing (progress = 0), but unlikely since the intepreter only checks this condition every 100 milliseconds or so, while the track begins to play much more quickly than that (making nonzero progress) # DOES trigger if track is set back to zero while paused break sleep(0.1) # don't consume too much CPU break print('Changing track') except Exception as e: print(e) continue # send the interpreter back to the top of the loop to ensure the current track keeps playing
def download_albumspo(URL, output=stock_output + "/", recursive_download=stock_recursive_download, not_interface=stock_not_interface, zips=stock_zip): global spo datas = {} detas = {} datas['music'] = [] datas['artist'] = [] datas['tracknum'] = [] datas['discnum'] = [] datas['duration'] = [] names = [] nams = [] try: url = spo.album(URL) except Exception as a: if not "The access token expired" in str(a): raise exceptions.InvalidLink("Invalid link ;)") spo = Spotify(generate_token()) url = spo.album(URL) detas['image'] = request(url['images'][0]['url']).content detas['album'] = url['name'] detas['year'] = url['release_date'] detas['genre'] = " & ".join(url['genres']) array = [a['name'] for a in url['artists']] detas['ar_album'] = ", ".join(array) detas['label'] = url['label'] detas['bpm'] = "" detas['gain'] = "0" detas['isrc'] = "" album = var_excape(detas['album']) directory = ("%s%s %s/" % (output, album, url['external_ids']['upc'])) check_dir(directory) tot = url['total_tracks'] def lazy(a): datas['music'].append(a['name']) discnum = str(a['disc_number']) tracknum = str(a['track_number']) names.append("%s%s CD %s TRACK %s" % (directory, album, discnum, tracknum)) datas['tracknum'].append(tracknum) datas['discnum'].append(discnum) datas['duration'].append(str(a['duration_ms'] * 1000)) array = [b['name'] for b in a['artists']] datas['artist'].append(", ".join(array)) for a in url['tracks']['items']: lazy(a) for a in range(tot // 50 - 1): try: url = spo.next(url['tracks']) except: spo = Spotify(generate_token()) url = spo.next(url['tracks']) for a in url['items']: lazy(a) for a in tqdm(range(len(names)), disable=not_interface): detas['music'] = datas['music'][a] detas['artist'] = datas['artist'][a] detas['tracknum'] = datas['tracknum'][a] detas['discnum'] = datas['discnum'][a] detas['duration'] = datas['duration'][a] song = "{} - {}".format(detas['music'], detas['artist']) try: nams.append( download(directory, names[a], recursive_download, not_interface, detas)) except exceptions.TrackNotFound: nams.append(names[a]) print("Track not found: %s :(" % song) continue if zips: zip_name = "{}{}.zip".format(directory, directory.split("/")[-2]) create_zip(zip_name, nams) return nams, zip_name return nams
def download_trackspo(URL, output=stock_output + "/", recursive_download=stock_recursive_download, not_interface=stock_not_interface): global spo datas = {} URL = URL.split("?")[0] try: url = spo.track(URL) except Exception as a: if not "The access token expired" in str(a): raise exceptions.InvalidLink("Invalid link ;)") spo = Spotify(generate_token()) url = spo.track(URL) URL1 = url['album']['external_urls']['spotify'] try: url1 = spo.album(URL1) except Exception as a: if not "The access token expired" in str(a): raise exceptions.InvalidLink("Invalid link ;)") spo = Spotify(generate_token()) url1 = spo.album(URL1) datas['image'] = request(url1['images'][0]['url']).content datas['music'] = url['name'] array = [a['name'] for a in url['artists']] datas['artist'] = ", ".join(array) datas['album'] = url1['name'] datas['tracknum'] = str(url['track_number']) datas['discnum'] = str(url['disc_number']) datas['year'] = url1['release_date'] datas['genre'] = " & ".join(url1['genres']) array = [a['name'] for a in url1['artists']] datas['ar_album'] = ", ".join(array) datas['label'] = url1['label'] datas['bpm'] = "" datas['gain'] = "0" datas['duration'] = str(url['duration_ms'] * 1000) datas['isrc'] = url['external_ids']['isrc'] album = var_excape(datas['album']) directory = ("%s%s %s/" % (output, album, url1['external_ids']['upc'])) check_dir(directory) name = ("%s%s CD %s TRACK %s" % (directory, album, datas['discnum'], datas['tracknum'])) out = download(directory, name, recursive_download, not_interface, datas) return out
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")
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 SpotifyClient: def __init__(self): token = self.get_token() self.sp = Spotify(auth=token) def get_token(self): scope = 'playlist-modify-private' return util.prompt_for_user_token( SPOTIFY_AUTH['USERNAME'], scope, client_id=SPOTIFY_AUTH['CLIENT_ID'], client_secret=SPOTIFY_AUTH['CLIENT_SECRET'], redirect_uri=SPOTIFY_AUTH['REDIRECT_URI']) def search_album(self, album_name, artist_name): results = self.sp.search(q=album_name, limit=20, type="album") for album in results["albums"]["items"]: if 'GB' in album['available_markets']: return album def get_album(self, album_name, artist_name): album_id = self.search_album(album_name, artist_name) try: return self.sp.album(album_id['uri']) except TypeError: return {"tracks": []} def get_album_tracks(self, album_name, artist_name): try: return self.get_album(album_name, artist_name)['tracks'] except TypeError: return None def list_track_ids(self, album_name, artist_name): track_ids = [] album_items = self.get_album_tracks(album_name, artist_name) if album_items: for track in album_items['items']: track_ids.append(track['id']) return track_ids def get_playlist(self): return self.sp.user_playlist(SPOTIFY_AUTH['USERNAME'], TARGET_PLAYLIST) def get_playlist_track_ids(self): track_ids = [] offset = 0 tracks = self.sp.user_playlist_tracks( SPOTIFY_AUTH['USERNAME'], TARGET_PLAYLIST, None, 100, offset) track_items = tracks['items'] while tracks['next']: # Paginate offset = offset + 100 tracks = self.sp.user_playlist_tracks( SPOTIFY_AUTH['USERNAME'], TARGET_PLAYLIST, None, 100, offset) track_items = track_items + tracks['items'] if len(track_items) > 0: for track in track_items: track_ids.append(track["track"]['id']) return track_ids def add_tracks(self, track_id_list): playlist_id = self.get_playlist()['id'] self.sp.user_playlist_add_tracks(SPOTIFY_AUTH['USERNAME'], playlist_id, track_id_list)
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)