mirror of
https://github.com/spotipy-dev/spotipy.git
synced 2026-06-19 09:13:53 +00:00
parent
5928981e3b
commit
f54830e272
@ -4,6 +4,7 @@ import spotipy
|
|||||||
''' shows the albums and tracks for a given artist.
|
''' shows the albums and tracks for a given artist.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def get_artist(name):
|
def get_artist(name):
|
||||||
results = sp.search(q='artist:' + name, type='artist')
|
results = sp.search(q='artist:' + name, type='artist')
|
||||||
items = results['artists']['items']
|
items = results['artists']['items']
|
||||||
@ -12,6 +13,7 @@ def get_artist(name):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def show_artist_albums(artist):
|
def show_artist_albums(artist):
|
||||||
albums = []
|
albums = []
|
||||||
results = sp.artist_albums(artist['id'], album_type='album')
|
results = sp.artist_albums(artist['id'], album_type='album')
|
||||||
@ -19,7 +21,7 @@ def show_artist_albums(artist):
|
|||||||
while results['next']:
|
while results['next']:
|
||||||
results = sp.next(results)
|
results = sp.next(results)
|
||||||
albums.extend(results['items'])
|
albums.extend(results['items'])
|
||||||
seen = set() # to avoid dups
|
seen = set() # to avoid dups
|
||||||
albums.sort(key=lambda album: album['name'].lower())
|
albums.sort(key=lambda album: album['name'].lower())
|
||||||
for album in albums:
|
for album in albums:
|
||||||
name = album['name']
|
name = album['name']
|
||||||
@ -27,6 +29,7 @@ def show_artist_albums(artist):
|
|||||||
print((' ' + name))
|
print((' ' + name))
|
||||||
seen.add(name)
|
seen.add(name)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sp = spotipy.Spotify()
|
sp = spotipy.Spotify()
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import spotipy
|
|||||||
''' shows the albums and tracks for a given artist.
|
''' shows the albums and tracks for a given artist.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def get_artist(name):
|
def get_artist(name):
|
||||||
results = sp.search(q='artist:' + name, type='artist')
|
results = sp.search(q='artist:' + name, type='artist')
|
||||||
items = results['artists']['items']
|
items = results['artists']['items']
|
||||||
@ -12,6 +13,7 @@ def get_artist(name):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def show_album_tracks(album):
|
def show_album_tracks(album):
|
||||||
tracks = []
|
tracks = []
|
||||||
results = sp.album_tracks(album['id'])
|
results = sp.album_tracks(album['id'])
|
||||||
@ -24,6 +26,7 @@ def show_album_tracks(album):
|
|||||||
print()
|
print()
|
||||||
print(track)
|
print(track)
|
||||||
|
|
||||||
|
|
||||||
def show_artist_albums(id):
|
def show_artist_albums(id):
|
||||||
albums = []
|
albums = []
|
||||||
results = sp.artist_albums(artist['id'], album_type='album')
|
results = sp.artist_albums(artist['id'], album_type='album')
|
||||||
@ -35,17 +38,19 @@ def show_artist_albums(id):
|
|||||||
unique = set() # skip duplicate albums
|
unique = set() # skip duplicate albums
|
||||||
for album in albums:
|
for album in albums:
|
||||||
name = album['name'].lower()
|
name = album['name'].lower()
|
||||||
if not name in unique:
|
if name not in unique:
|
||||||
print(name)
|
print(name)
|
||||||
unique.add(name)
|
unique.add(name)
|
||||||
show_album_tracks(album)
|
show_album_tracks(album)
|
||||||
|
|
||||||
|
|
||||||
def show_artist(artist):
|
def show_artist(artist):
|
||||||
print('====', artist['name'], '====')
|
print('====', artist['name'], '====')
|
||||||
print('Popularity: ', artist['popularity'])
|
print('Popularity: ', artist['popularity'])
|
||||||
if len(artist['genres']) > 0:
|
if len(artist['genres']) > 0:
|
||||||
print('Genres: ', ','.join(artist['genres']))
|
print('Genres: ', ','.join(artist['genres']))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sp = spotipy.Spotify()
|
sp = spotipy.Spotify()
|
||||||
sp.trace = False
|
sp.trace = False
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import spotipy
|
|||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
sp.trace=False
|
sp.trace = False
|
||||||
|
|
||||||
|
|
||||||
def get_artist(name):
|
def get_artist(name):
|
||||||
results = sp.search(q='artist:' + name, type='artist')
|
results = sp.search(q='artist:' + name, type='artist')
|
||||||
@ -17,11 +18,12 @@ def get_artist(name):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def show_recommendations_for_artist(artist):
|
def show_recommendations_for_artist(artist):
|
||||||
albums = []
|
|
||||||
results = sp.recommendations(seed_artists=[artist['id']])
|
results = sp.recommendations(seed_artists=[artist['id']])
|
||||||
for track in results['tracks']:
|
for track in results['tracks']:
|
||||||
print track['name'], '-', track['artists'][0]['name']
|
print(track['name'], '-', track['artists'][0]['name'])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
@ -32,4 +34,4 @@ if __name__ == '__main__':
|
|||||||
if artist:
|
if artist:
|
||||||
show_recommendations_for_artist(artist)
|
show_recommendations_for_artist(artist)
|
||||||
else:
|
else:
|
||||||
print "Can't find that artist", name
|
print("Can't find that artist", name)
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import sys
|
|||||||
|
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
sp.trace=False
|
sp.trace = False
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
artist_name = ' '.join(sys.argv[1:])
|
artist_name = ' '.join(sys.argv[1:])
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import sys
|
|||||||
|
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
sp.trace=True
|
sp.trace = True
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
tids = sys.argv[1:]
|
tids = sys.argv[1:]
|
||||||
|
|||||||
@ -25,7 +25,7 @@ if len(sys.argv) > 3:
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
print("Usage: %s username playlist_id name [public collaborative "
|
print("Usage: %s username playlist_id name [public collaborative "
|
||||||
"description]" % (sys.argv[0]))
|
"description]" % (sys.argv[0]))
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
scope = 'playlist-modify-public playlist-modify-private'
|
scope = 'playlist-modify-public playlist-modify-private'
|
||||||
@ -37,6 +37,6 @@ if token:
|
|||||||
results = sp.user_playlist_change_details(
|
results = sp.user_playlist_change_details(
|
||||||
username, playlist_id, name=name, public=public,
|
username, playlist_id, name=name, public=public,
|
||||||
collaborative=collaborative, description=description)
|
collaborative=collaborative, description=description)
|
||||||
print results
|
print(results)
|
||||||
else:
|
else:
|
||||||
print "Can't get token for", username
|
print("Can't get token for"), username
|
||||||
|
|||||||
@ -12,7 +12,9 @@ if len(sys.argv) > 2:
|
|||||||
playlist_name = sys.argv[2]
|
playlist_name = sys.argv[2]
|
||||||
playlist_description = sys.argv[3]
|
playlist_description = sys.argv[3]
|
||||||
else:
|
else:
|
||||||
print("Usage: %s username playlist-name playlist-description" % (sys.argv[0],))
|
print(
|
||||||
|
"Usage: %s username playlist-name playlist-description" %
|
||||||
|
(sys.argv[0],))
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
scope = "playlist-modify-public"
|
scope = "playlist-modify-public"
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import spotipy
|
|||||||
|
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
sp.trace=True
|
sp.trace = True
|
||||||
try:
|
try:
|
||||||
print('bad call 0')
|
print('bad call 0')
|
||||||
bad_artist_call = sp.artist('spotify:artist:12341234')
|
bad_artist_call = sp.artist('spotify:artist:12341234')
|
||||||
@ -17,4 +17,3 @@ except spotipy.client.SpotifyException:
|
|||||||
print('bad call 1')
|
print('bad call 1')
|
||||||
bad_artist_call = sp.artist('spotify:artist:12341234')
|
bad_artist_call = sp.artist('spotify:artist:12341234')
|
||||||
print('bad artist', bad_artist_call)
|
print('bad artist', bad_artist_call)
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,6 @@ if token:
|
|||||||
sp.trace = False
|
sp.trace = False
|
||||||
results = sp.current_user_playlists(limit=50)
|
results = sp.current_user_playlists(limit=50)
|
||||||
for i, item in enumerate(results['items']):
|
for i, item in enumerate(results['items']):
|
||||||
print("%d %s" %(i, item['name']))
|
print("%d %s" % (i, item['name']))
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
# Shows the top artists for a user
|
# Shows the top artists for a user
|
||||||
|
|
||||||
import pprint
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
username = sys.argv[1]
|
username = sys.argv[1]
|
||||||
@ -21,10 +19,10 @@ if token:
|
|||||||
sp.trace = False
|
sp.trace = False
|
||||||
ranges = ['short_term', 'medium_term', 'long_term']
|
ranges = ['short_term', 'medium_term', 'long_term']
|
||||||
for range in ranges:
|
for range in ranges:
|
||||||
print ("range:", range)
|
print("range:", range)
|
||||||
results = sp.current_user_top_artists(time_range=range, limit=50)
|
results = sp.current_user_top_artists(time_range=range, limit=50)
|
||||||
for i, item in enumerate(results['items']):
|
for i, item in enumerate(results['items']):
|
||||||
print (i, item['name'])
|
print(i, item['name'])
|
||||||
print ()
|
print()
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
# Shows the top tracks for a user
|
# Shows the top tracks for a user
|
||||||
|
|
||||||
import pprint
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
username = sys.argv[1]
|
username = sys.argv[1]
|
||||||
@ -21,11 +19,11 @@ if token:
|
|||||||
sp.trace = False
|
sp.trace = False
|
||||||
ranges = ['short_term', 'medium_term', 'long_term']
|
ranges = ['short_term', 'medium_term', 'long_term']
|
||||||
for range in ranges:
|
for range in ranges:
|
||||||
print ("range:", range)
|
print("range:", range)
|
||||||
results = sp.current_user_top_tracks(time_range=range, limit=50)
|
results = sp.current_user_top_tracks(time_range=range, limit=50)
|
||||||
for i, item in enumerate(results['items']):
|
for i, item in enumerate(results['items']):
|
||||||
print (i, item['name'], '//', item['artists'][0]['name'])
|
print(i, item['name'], '//', item['artists'][0]['name'])
|
||||||
print ()
|
print()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|||||||
@ -10,4 +10,4 @@ username = uri.split(':')[2]
|
|||||||
playlist_id = uri.split(':')[4]
|
playlist_id = uri.split(':')[4]
|
||||||
|
|
||||||
results = sp.user_playlist(username, playlist_id)
|
results = sp.user_playlist(username, playlist_id)
|
||||||
print (json.dumps(results, indent=4))
|
print(json.dumps(results, indent=4))
|
||||||
|
|||||||
@ -15,7 +15,9 @@ if len(sys.argv) > 3:
|
|||||||
tid, pos = t_pos.split(',')
|
tid, pos = t_pos.split(',')
|
||||||
track_ids.append({"uri": tid, "positions": [int(pos)]})
|
track_ids.append({"uri": tid, "positions": [int(pos)]})
|
||||||
else:
|
else:
|
||||||
print("Usage: %s username playlist_id track_id,pos track_id,pos ..." % (sys.argv[0],))
|
print(
|
||||||
|
"Usage: %s username playlist_id track_id,pos track_id,pos ..." %
|
||||||
|
(sys.argv[0],))
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
scope = 'playlist-modify-public'
|
scope = 'playlist-modify-public'
|
||||||
@ -24,7 +26,8 @@ token = util.prompt_for_user_token(username, scope)
|
|||||||
if token:
|
if token:
|
||||||
sp = spotipy.Spotify(auth=token)
|
sp = spotipy.Spotify(auth=token)
|
||||||
sp.trace = False
|
sp.trace = False
|
||||||
results = sp.user_playlist_remove_specific_occurrences_of_tracks(username, playlist_id, track_ids)
|
results = sp.user_playlist_remove_specific_occurrences_of_tracks(
|
||||||
|
username, playlist_id, track_ids)
|
||||||
pprint.pprint(results)
|
pprint.pprint(results)
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|||||||
@ -20,7 +20,8 @@ token = util.prompt_for_user_token(username, scope)
|
|||||||
if token:
|
if token:
|
||||||
sp = spotipy.Spotify(auth=token)
|
sp = spotipy.Spotify(auth=token)
|
||||||
sp.trace = False
|
sp.trace = False
|
||||||
results = sp.user_playlist_remove_all_occurrences_of_tracks(username, playlist_id, track_ids)
|
results = sp.user_playlist_remove_all_occurrences_of_tracks(
|
||||||
|
username, playlist_id, track_ids)
|
||||||
pprint.pprint(results)
|
pprint.pprint(results)
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|||||||
@ -22,6 +22,5 @@ try:
|
|||||||
print('Related artists for', name)
|
print('Related artists for', name)
|
||||||
for artist in related['artists']:
|
for artist in related['artists']:
|
||||||
print(' ', artist['name'])
|
print(' ', artist['name'])
|
||||||
except:
|
except BaseException:
|
||||||
print("usage show_related.py [artist-name]")
|
print("usage show_related.py [artist-name]")
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,3 @@ if __name__ == '__main__':
|
|||||||
results = sp.tracks(tids[start: start + max_tracks_per_call])
|
results = sp.tracks(tids[start: start + max_tracks_per_call])
|
||||||
for track in results['tracks']:
|
for track in results['tracks']:
|
||||||
print(track['name'] + ' - ' + track['artists'][0]['name'])
|
print(track['name'] + ' - ' + track['artists'][0]['name'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -14,4 +14,3 @@ sp = spotipy.Spotify()
|
|||||||
sp.trace = True
|
sp.trace = True
|
||||||
user = sp.user(username)
|
user = sp.user(username)
|
||||||
pprint.pprint(user)
|
pprint.pprint(user)
|
||||||
|
|
||||||
|
|||||||
@ -14,4 +14,3 @@ while results['next']:
|
|||||||
|
|
||||||
for album in albums:
|
for album in albums:
|
||||||
print((album['name']))
|
print((album['name']))
|
||||||
|
|
||||||
|
|||||||
@ -15,4 +15,3 @@ items = results['artists']['items']
|
|||||||
if len(items) > 0:
|
if len(items) > 0:
|
||||||
artist = items[0]
|
artist = items[0]
|
||||||
print(artist['name'], artist['images'][0]['url'])
|
print(artist['name'], artist['images'][0]['url'])
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import spotipy
|
import spotipy
|
||||||
import random
|
import random
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
generates a list of songs where the first word in each subsequent song
|
generates a list of songs where the first word in each subsequent song
|
||||||
@ -14,13 +13,14 @@ skiplist = set(['dm', 'remix'])
|
|||||||
max_offset = 500
|
max_offset = 500
|
||||||
seen = set()
|
seen = set()
|
||||||
|
|
||||||
|
|
||||||
def find_songs_that_start_with_word(word):
|
def find_songs_that_start_with_word(word):
|
||||||
max_titles = 20
|
max_titles = 20
|
||||||
max_offset = 200
|
max_offset = 200
|
||||||
offset = 0
|
offset = 0
|
||||||
|
|
||||||
out = []
|
out = []
|
||||||
while offset < max_offset and len(out) < max_titles:
|
while offset < max_offset and len(out) < max_titles:
|
||||||
results = sp.search(q=word, type='track', limit=50, offset=offset)
|
results = sp.search(q=word, type='track', limit=50, offset=offset)
|
||||||
if len(results['tracks']['items']) == 0:
|
if len(results['tracks']['items']) == 0:
|
||||||
break
|
break
|
||||||
@ -37,27 +37,29 @@ def find_songs_that_start_with_word(word):
|
|||||||
if '/' in name:
|
if '/' in name:
|
||||||
continue
|
continue
|
||||||
words = name.split()
|
words = name.split()
|
||||||
if len(words) > 1 and words[0] == word and words[-1] not in skiplist:
|
if len(words) > 1 and words[0] == word \
|
||||||
#print " ", name, len(out)
|
and words[-1] not in skiplist:
|
||||||
|
# print " ", name, len(out)
|
||||||
out.append(item)
|
out.append(item)
|
||||||
offset += 50
|
offset += 50
|
||||||
#print "found", len(out), "matches"
|
# print "found", len(out), "matches"
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def make_chain(word):
|
def make_chain(word):
|
||||||
which = 1
|
which = 1
|
||||||
while True:
|
while True:
|
||||||
songs = find_songs_that_start_with_word(word)
|
songs = find_songs_that_start_with_word(word)
|
||||||
if len(songs) > 0:
|
if len(songs) > 0:
|
||||||
song = random.choice(songs)
|
song = random.choice(songs)
|
||||||
print which, song['name'] + " by " + song['artists'][0]['name']
|
print(which, song['name'] + " by " + song['artists'][0]['name'])
|
||||||
which += 1
|
which += 1
|
||||||
word = song['name'].lower().split()[-1]
|
word = song['name'].lower().split()[-1]
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
title = ' '.join(sys.argv[1:])
|
title = ' '.join(sys.argv[1:])
|
||||||
make_chain(sys.argv[1].lower())
|
make_chain(sys.argv[1].lower())
|
||||||
|
|
||||||
|
|||||||
@ -4,10 +4,13 @@ import sys
|
|||||||
import spotipy
|
import spotipy
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
|
|
||||||
|
|
||||||
def show_tracks(results):
|
def show_tracks(results):
|
||||||
for i, item in enumerate(results['items']):
|
for i, item in enumerate(results['items']):
|
||||||
track = item['track']
|
track = item['track']
|
||||||
print(" %d %32.32s %s" % (i, track['artists'][0]['name'], track['name']))
|
print(
|
||||||
|
" %d %32.32s %s" %
|
||||||
|
(i, track['artists'][0]['name'], track['name']))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@ -28,7 +31,8 @@ if __name__ == '__main__':
|
|||||||
print()
|
print()
|
||||||
print(playlist['name'])
|
print(playlist['name'])
|
||||||
print(' total tracks', playlist['tracks']['total'])
|
print(' total tracks', playlist['tracks']['total'])
|
||||||
results = sp.user_playlist(username, playlist['id'], fields="tracks,next")
|
results = sp.user_playlist(
|
||||||
|
username, playlist['id'], fields="tracks,next")
|
||||||
tracks = results['tracks']
|
tracks = results['tracks']
|
||||||
show_tracks(tracks)
|
show_tracks(tracks)
|
||||||
while tracks['next']:
|
while tracks['next']:
|
||||||
@ -36,4 +40,3 @@ if __name__ == '__main__':
|
|||||||
show_tracks(tracks)
|
show_tracks(tracks)
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,13 @@ playlists = sp.user_playlists(user)
|
|||||||
|
|
||||||
while playlists:
|
while playlists:
|
||||||
for i, playlist in enumerate(playlists['items']):
|
for i, playlist in enumerate(playlists['items']):
|
||||||
print("%4d %s %s" % (i + 1 + playlists['offset'], playlist['uri'], playlist['name']))
|
print(
|
||||||
|
"%4d %s %s" %
|
||||||
|
(i +
|
||||||
|
1 +
|
||||||
|
playlists['offset'],
|
||||||
|
playlist['uri'],
|
||||||
|
playlist['name']))
|
||||||
if playlists['next']:
|
if playlists['next']:
|
||||||
playlists = sp.next(playlists)
|
playlists = sp.next(playlists)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import pprint
|
|
||||||
import sys
|
import sys
|
||||||
import json
|
|
||||||
import spotipy
|
import spotipy
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import spotipy
|
|||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
username = sys.argv[1]
|
username = sys.argv[1]
|
||||||
else:
|
else:
|
||||||
|
|||||||
7
setup.py
7
setup.py
@ -1,9 +1,11 @@
|
|||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
|
desc = """### A light weight Python library for the Spotify Web API"""
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='spotipy',
|
name='spotipy',
|
||||||
version='2.5.0',
|
version='2.5.0',
|
||||||
long_description="""### A light weight Python library for the Spotify Web API""",
|
long_description=desc,
|
||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
author="@plamere",
|
author="@plamere",
|
||||||
author_email="paul@echonest.com",
|
author_email="paul@echonest.com",
|
||||||
@ -12,7 +14,6 @@ setup(
|
|||||||
'mock>=2.0.0',
|
'mock>=2.0.0',
|
||||||
'requests>=2.3.0',
|
'requests>=2.3.0',
|
||||||
'six>=1.10.0',
|
'six>=1.10.0',
|
||||||
'simplejson==3.13.2',
|
],
|
||||||
],
|
|
||||||
license='LICENSE.txt',
|
license='LICENSE.txt',
|
||||||
packages=['spotipy'])
|
packages=['spotipy'])
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
from .client import *
|
from .client import * # noqa
|
||||||
from .oauth2 import *
|
from .oauth2 import * # noqa
|
||||||
from .util import *
|
from .util import * # noqa
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import requests
|
|||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SpotifyException(Exception):
|
class SpotifyException(Exception):
|
||||||
def __init__(self, http_status, code, msg, headers=None):
|
def __init__(self, http_status, code, msg, headers=None):
|
||||||
self.http_status = http_status
|
self.http_status = http_status
|
||||||
@ -58,7 +57,8 @@ class Spotify(object):
|
|||||||
max_get_retries = 10
|
max_get_retries = 10
|
||||||
|
|
||||||
def __init__(self, auth=None, requests_session=True,
|
def __init__(self, auth=None, requests_session=True,
|
||||||
client_credentials_manager=None, proxies=None, requests_timeout=None):
|
client_credentials_manager=None, proxies=None,
|
||||||
|
requests_timeout=None):
|
||||||
"""
|
"""
|
||||||
Creates a Spotify API client.
|
Creates a Spotify API client.
|
||||||
|
|
||||||
@ -73,7 +73,8 @@ class Spotify(object):
|
|||||||
:param proxies:
|
:param proxies:
|
||||||
Definition of proxies (optional)
|
Definition of proxies (optional)
|
||||||
:param requests_timeout:
|
:param requests_timeout:
|
||||||
Tell Requests to stop waiting for a response after a given number of seconds
|
Tell Requests to stop waiting for a response after a given
|
||||||
|
number of seconds
|
||||||
"""
|
"""
|
||||||
self.prefix = 'https://api.spotify.com/v1/'
|
self.prefix = 'https://api.spotify.com/v1/'
|
||||||
self._auth = auth
|
self._auth = auth
|
||||||
@ -112,26 +113,33 @@ class Spotify(object):
|
|||||||
|
|
||||||
if self.trace_out:
|
if self.trace_out:
|
||||||
print(url)
|
print(url)
|
||||||
r = self._session.request(method, url, headers=headers, proxies=self.proxies, **args)
|
r = self._session.request(
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
headers=headers,
|
||||||
|
proxies=self.proxies,
|
||||||
|
**args)
|
||||||
|
|
||||||
if self.trace: # pragma: no cover
|
if self.trace: # pragma: no cover
|
||||||
print()
|
print()
|
||||||
print ('headers', headers)
|
print('headers', headers)
|
||||||
print ('http status', r.status_code)
|
print('http status', r.status_code)
|
||||||
print(method, r.url)
|
print(method, r.url)
|
||||||
if payload:
|
if payload:
|
||||||
print("DATA", json.dumps(payload))
|
print("DATA", json.dumps(payload))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
except:
|
except BaseException:
|
||||||
if r.text and len(r.text) > 0 and r.text != 'null':
|
if r.text and len(r.text) > 0 and r.text != 'null':
|
||||||
|
msg = '%s:\n %s' % (r.url, r.json()['error']['message'])
|
||||||
raise SpotifyException(r.status_code,
|
raise SpotifyException(r.status_code,
|
||||||
-1, '%s:\n %s' % (r.url, r.json()['error']['message']),
|
-1, msg,
|
||||||
headers=r.headers)
|
headers=r.headers)
|
||||||
else:
|
else:
|
||||||
raise SpotifyException(r.status_code,
|
raise SpotifyException(r.status_code,
|
||||||
-1, '%s:\n %s' % (r.url, 'error'), headers=r.headers)
|
-1, '%s:\n %s' % (r.url, 'error'),
|
||||||
|
headers=r.headers)
|
||||||
finally:
|
finally:
|
||||||
if hasattr(r, "connection"):
|
if hasattr(r, "connection"):
|
||||||
r.connection.close()
|
r.connection.close()
|
||||||
@ -160,21 +168,22 @@ class Spotify(object):
|
|||||||
if retries < 0:
|
if retries < 0:
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
sleep_seconds = int(e.headers.get('Retry-After', delay))
|
sleep_seconds = int(
|
||||||
print ('retrying ...' + str(sleep_seconds) + 'secs')
|
e.headers.get('Retry-After', delay))
|
||||||
|
print('retrying ...' + str(sleep_seconds) + 'secs')
|
||||||
time.sleep(sleep_seconds + 1)
|
time.sleep(sleep_seconds + 1)
|
||||||
delay += 1
|
delay += 1
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise
|
raise
|
||||||
print ('exception', str(e))
|
print('exception', str(e))
|
||||||
# some other exception. Requests have
|
# some other exception. Requests have
|
||||||
# been know to throw a BadStatusLine exception
|
# been know to throw a BadStatusLine exception
|
||||||
retries -= 1
|
retries -= 1
|
||||||
if retries >= 0:
|
if retries >= 0:
|
||||||
sleep_seconds = int(e.headers.get('Retry-After', delay))
|
sleep_seconds = int(e.headers.get('Retry-After', delay))
|
||||||
print ('retrying ...' + str(delay) + 'secs')
|
print('retrying ...' + str(delay) + 'secs')
|
||||||
time.sleep(sleep_seconds + 1)
|
time.sleep(sleep_seconds + 1)
|
||||||
delay += 1
|
delay += 1
|
||||||
else:
|
else:
|
||||||
@ -233,7 +242,7 @@ class Spotify(object):
|
|||||||
trid = self._get_id('track', track_id)
|
trid = self._get_id('track', track_id)
|
||||||
return self._get('tracks/' + trid)
|
return self._get('tracks/' + trid)
|
||||||
|
|
||||||
def tracks(self, tracks, market = None):
|
def tracks(self, tracks, market=None):
|
||||||
""" returns a list of tracks given a list of track IDs, URIs, or URLs
|
""" returns a list of tracks given a list of track IDs, URIs, or URLs
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -242,7 +251,7 @@ class Spotify(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
tlist = [self._get_id('track', t) for t in tracks]
|
tlist = [self._get_id('track', t) for t in tracks]
|
||||||
return self._get('tracks/?ids=' + ','.join(tlist), market = market)
|
return self._get('tracks/?ids=' + ','.join(tlist), market=market)
|
||||||
|
|
||||||
def artist(self, artist_id):
|
def artist(self, artist_id):
|
||||||
""" returns a single artist given the artist's ID, URI or URL
|
""" returns a single artist given the artist's ID, URI or URL
|
||||||
@ -345,9 +354,11 @@ class Spotify(object):
|
|||||||
- offset - the index of the first item to return
|
- offset - the index of the first item to return
|
||||||
- type - the type of item to return. One of 'artist', 'album',
|
- type - the type of item to return. One of 'artist', 'album',
|
||||||
'track' or 'playlist'
|
'track' or 'playlist'
|
||||||
- market - An ISO 3166-1 alpha-2 country code or the string from_token.
|
- market - An ISO 3166-1 alpha-2 country code or the string
|
||||||
|
from_token.
|
||||||
"""
|
"""
|
||||||
return self._get('search', q=q, limit=limit, offset=offset, type=type, market=market)
|
return self._get('search', q=q, limit=limit,
|
||||||
|
offset=offset, type=type, market=market)
|
||||||
|
|
||||||
def user(self, user):
|
def user(self, user):
|
||||||
""" Gets basic profile information about a Spotify User
|
""" Gets basic profile information about a Spotify User
|
||||||
@ -394,12 +405,12 @@ class Spotify(object):
|
|||||||
Parameters:
|
Parameters:
|
||||||
- playlist - the id of the playlist
|
- playlist - the id of the playlist
|
||||||
- fields - which fields to return
|
- fields - which fields to return
|
||||||
- market - An ISO 3166-1 alpha-2 country code or the string from_token.
|
- market - An ISO 3166-1 alpha-2 country code or the string
|
||||||
|
from_token.
|
||||||
"""
|
"""
|
||||||
plid = self._get_id('playlist', playlist_id)
|
plid = self._get_id('playlist', playlist_id)
|
||||||
return self._get("playlists/%s" % (plid), fields=fields)
|
return self._get("playlists/%s" % (plid), fields=fields)
|
||||||
|
|
||||||
|
|
||||||
def user_playlist_tracks(self, user, playlist_id=None, fields=None,
|
def user_playlist_tracks(self, user, playlist_id=None, fields=None,
|
||||||
limit=100, offset=0, market=None):
|
limit=100, offset=0, market=None):
|
||||||
""" Get full details of the tracks of a playlist owned by a user.
|
""" Get full details of the tracks of a playlist owned by a user.
|
||||||
@ -417,7 +428,6 @@ class Spotify(object):
|
|||||||
limit=limit, offset=offset, fields=fields,
|
limit=limit, offset=offset, fields=fields,
|
||||||
market=market)
|
market=market)
|
||||||
|
|
||||||
|
|
||||||
def user_playlist_create(self, user, name, public=True, description=''):
|
def user_playlist_create(self, user, name, public=True, description=''):
|
||||||
""" Creates a playlist for a user
|
""" Creates a playlist for a user
|
||||||
|
|
||||||
@ -429,7 +439,6 @@ class Spotify(object):
|
|||||||
"""
|
"""
|
||||||
data = {'name': name, 'public': public, 'description': description}
|
data = {'name': name, 'public': public, 'description': description}
|
||||||
|
|
||||||
|
|
||||||
return self._post("users/%s/playlists" % (user,), payload=data)
|
return self._post("users/%s/playlists" % (user,), payload=data)
|
||||||
|
|
||||||
def user_playlist_change_details(
|
def user_playlist_change_details(
|
||||||
@ -465,7 +474,8 @@ class Spotify(object):
|
|||||||
- user - the id of the user
|
- user - the id of the user
|
||||||
- name - the name of the playlist
|
- name - the name of the playlist
|
||||||
"""
|
"""
|
||||||
return self._delete("users/%s/playlists/%s/followers" % (user, playlist_id))
|
return self._delete("users/%s/playlists/%s/followers" %
|
||||||
|
(user, playlist_id))
|
||||||
|
|
||||||
def user_playlist_add_tracks(self, user, playlist_id, tracks,
|
def user_playlist_add_tracks(self, user, playlist_id, tracks,
|
||||||
position=None):
|
position=None):
|
||||||
@ -505,8 +515,10 @@ class Spotify(object):
|
|||||||
- user - the id of the user
|
- user - the id of the user
|
||||||
- playlist_id - the id of the playlist
|
- playlist_id - the id of the playlist
|
||||||
- range_start - the position of the first track to be reordered
|
- range_start - the position of the first track to be reordered
|
||||||
- range_length - optional the number of tracks to be reordered (default: 1)
|
- range_length - optional the number of tracks to be reordered
|
||||||
- insert_before - the position where the tracks should be inserted
|
(default: 1)
|
||||||
|
- insert_before - the position where the tracks should be
|
||||||
|
inserted
|
||||||
- snapshot_id - optional playlist's snapshot ID
|
- snapshot_id - optional playlist's snapshot ID
|
||||||
"""
|
"""
|
||||||
plid = self._get_id('playlist', playlist_id)
|
plid = self._get_id('playlist', playlist_id)
|
||||||
@ -575,9 +587,12 @@ class Spotify(object):
|
|||||||
- playlist_id - the id of the playlist
|
- playlist_id - the id of the playlist
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._put("users/{}/playlists/{}/followers".format(playlist_owner_id, playlist_id))
|
return self._put(
|
||||||
|
"users/{}/playlists/{}/followers".format(playlist_owner_id,
|
||||||
|
playlist_id))
|
||||||
|
|
||||||
def user_playlist_is_following(self, playlist_owner_id, playlist_id, user_ids):
|
def user_playlist_is_following(
|
||||||
|
self, playlist_owner_id, playlist_id, user_ids):
|
||||||
"""
|
"""
|
||||||
Check to see if the given users are following the given playlist
|
Check to see if the given users are following the given playlist
|
||||||
|
|
||||||
@ -588,7 +603,10 @@ class Spotify(object):
|
|||||||
if they follow the playlist. Maximum: 5 ids.
|
if they follow the playlist. Maximum: 5 ids.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._get("users/{}/playlists/{}/followers/contains?ids={}".format(playlist_owner_id, playlist_id, ','.join(user_ids)))
|
endpoint = "users/{}/playlists/{}/followers/contains?ids={}"
|
||||||
|
return self._get(endpoint.format(playlist_owner_id,
|
||||||
|
playlist_id,
|
||||||
|
','.join(user_ids)))
|
||||||
|
|
||||||
def me(self):
|
def me(self):
|
||||||
""" Get detailed profile information about the current user.
|
""" Get detailed profile information about the current user.
|
||||||
@ -623,7 +641,8 @@ class Spotify(object):
|
|||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- limit - the number of artists to return
|
- limit - the number of artists to return
|
||||||
- after - the last artist ID retrieved from the previous request
|
- after - the last artist ID retrieved from the previous
|
||||||
|
request
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._get('me/following', type='artist', limit=limit,
|
return self._get('me/following', type='artist', limit=limit,
|
||||||
@ -858,17 +877,18 @@ class Spotify(object):
|
|||||||
- seed_tracks - a list of track IDs, URIs or URLs
|
- seed_tracks - a list of track IDs, URIs or URLs
|
||||||
|
|
||||||
- seed_genres - a list of genre names. Available genres for
|
- seed_genres - a list of genre names. Available genres for
|
||||||
recommendations can be found by calling recommendation_genre_seeds
|
recommendations can be found by calling
|
||||||
|
recommendation_genre_seeds
|
||||||
|
|
||||||
- country - An ISO 3166-1 alpha-2 country code. If provided, all
|
- country - An ISO 3166-1 alpha-2 country code. If provided,
|
||||||
results will be playable in this country.
|
all results will be playable in this country.
|
||||||
|
|
||||||
- limit - The maximum number of items to return. Default: 20.
|
- limit - The maximum number of items to return. Default: 20.
|
||||||
Minimum: 1. Maximum: 100
|
Minimum: 1. Maximum: 100
|
||||||
|
|
||||||
- min/max/target_<attribute> - For the tuneable track attributes listed
|
- min/max/target_<attribute> - For the tuneable track
|
||||||
in the documentation, these values provide filters and targeting on
|
attributes listed in the documentation, these values
|
||||||
results.
|
provide filters and targeting on results.
|
||||||
"""
|
"""
|
||||||
params = dict(limit=limit)
|
params = dict(limit=limit)
|
||||||
if seed_artists:
|
if seed_artists:
|
||||||
@ -928,23 +948,23 @@ class Spotify(object):
|
|||||||
'''
|
'''
|
||||||
return self._get("me/player/devices")
|
return self._get("me/player/devices")
|
||||||
|
|
||||||
def current_playback(self, market = None):
|
def current_playback(self, market=None):
|
||||||
''' Get information about user's current playback.
|
''' Get information about user's current playback.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- market - an ISO 3166-1 alpha-2 country code.
|
- market - an ISO 3166-1 alpha-2 country code.
|
||||||
'''
|
'''
|
||||||
return self._get("me/player", market = market)
|
return self._get("me/player", market=market)
|
||||||
|
|
||||||
def currently_playing(self, market = None):
|
def currently_playing(self, market=None):
|
||||||
''' Get user's currently playing track.
|
''' Get user's currently playing track.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- market - an ISO 3166-1 alpha-2 country code.
|
- market - an ISO 3166-1 alpha-2 country code.
|
||||||
'''
|
'''
|
||||||
return self._get("me/player/currently-playing", market = market)
|
return self._get("me/player/currently-playing", market=market)
|
||||||
|
|
||||||
def transfer_playback(self, device_id, force_play = True):
|
def transfer_playback(self, device_id, force_play=True):
|
||||||
''' Transfer playback to another device.
|
''' Transfer playback to another device.
|
||||||
Note that the API accepts a list of device ids, but only
|
Note that the API accepts a list of device ids, but only
|
||||||
actually supports one.
|
actually supports one.
|
||||||
@ -960,7 +980,8 @@ class Spotify(object):
|
|||||||
}
|
}
|
||||||
return self._put("me/player", payload=data)
|
return self._put("me/player", payload=data)
|
||||||
|
|
||||||
def start_playback(self, device_id = None, context_uri = None, uris = None, offset = None):
|
def start_playback(self, device_id=None,
|
||||||
|
context_uri=None, uris=None, offset=None):
|
||||||
''' Start or resume user's playback.
|
''' Start or resume user's playback.
|
||||||
|
|
||||||
Provide a `context_uri` to start playback or a album,
|
Provide a `context_uri` to start playback or a album,
|
||||||
@ -991,9 +1012,10 @@ class Spotify(object):
|
|||||||
data['uris'] = uris
|
data['uris'] = uris
|
||||||
if offset is not None:
|
if offset is not None:
|
||||||
data['offset'] = offset
|
data['offset'] = offset
|
||||||
return self._put(self._append_device_id("me/player/play", device_id), payload=data)
|
return self._put(self._append_device_id(
|
||||||
|
"me/player/play", device_id), payload=data)
|
||||||
|
|
||||||
def pause_playback(self, device_id = None):
|
def pause_playback(self, device_id=None):
|
||||||
''' Pause user's playback.
|
''' Pause user's playback.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -1001,7 +1023,7 @@ class Spotify(object):
|
|||||||
'''
|
'''
|
||||||
return self._put(self._append_device_id("me/player/pause", device_id))
|
return self._put(self._append_device_id("me/player/pause", device_id))
|
||||||
|
|
||||||
def next_track(self, device_id = None):
|
def next_track(self, device_id=None):
|
||||||
''' Skip user's playback to next track.
|
''' Skip user's playback to next track.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -1009,15 +1031,16 @@ class Spotify(object):
|
|||||||
'''
|
'''
|
||||||
return self._post(self._append_device_id("me/player/next", device_id))
|
return self._post(self._append_device_id("me/player/next", device_id))
|
||||||
|
|
||||||
def previous_track(self, device_id = None):
|
def previous_track(self, device_id=None):
|
||||||
''' Skip user's playback to previous track.
|
''' Skip user's playback to previous track.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- device_id - device target for playback
|
- device_id - device target for playback
|
||||||
'''
|
'''
|
||||||
return self._post(self._append_device_id("me/player/previous", device_id))
|
return self._post(self._append_device_id(
|
||||||
|
"me/player/previous", device_id))
|
||||||
|
|
||||||
def seek_track(self, position_ms, device_id = None):
|
def seek_track(self, position_ms, device_id=None):
|
||||||
''' Seek to position in current track.
|
''' Seek to position in current track.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -1027,9 +1050,10 @@ class Spotify(object):
|
|||||||
if not isinstance(position_ms, int):
|
if not isinstance(position_ms, int):
|
||||||
self._warn('position_ms must be an integer')
|
self._warn('position_ms must be an integer')
|
||||||
return
|
return
|
||||||
return self._put(self._append_device_id("me/player/seek?position_ms=%s" % position_ms, device_id))
|
return self._put(self._append_device_id(
|
||||||
|
"me/player/seek?position_ms=%s" % position_ms, device_id))
|
||||||
|
|
||||||
def repeat(self, state, device_id = None):
|
def repeat(self, state, device_id=None):
|
||||||
''' Set repeat mode for playback.
|
''' Set repeat mode for playback.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -1039,9 +1063,12 @@ class Spotify(object):
|
|||||||
if state not in ['track', 'context', 'off']:
|
if state not in ['track', 'context', 'off']:
|
||||||
self._warn('invalid state')
|
self._warn('invalid state')
|
||||||
return
|
return
|
||||||
self._put(self._append_device_id("me/player/repeat?state=%s" % state, device_id))
|
self._put(
|
||||||
|
self._append_device_id(
|
||||||
|
"me/player/repeat?state=%s" %
|
||||||
|
state, device_id))
|
||||||
|
|
||||||
def volume(self, volume_percent, device_id = None):
|
def volume(self, volume_percent, device_id=None):
|
||||||
''' Set playback volume.
|
''' Set playback volume.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -1054,9 +1081,12 @@ class Spotify(object):
|
|||||||
if volume_percent < 0 or volume_percent > 100:
|
if volume_percent < 0 or volume_percent > 100:
|
||||||
self._warn('volume must be between 0 and 100, inclusive')
|
self._warn('volume must be between 0 and 100, inclusive')
|
||||||
return
|
return
|
||||||
self._put(self._append_device_id("me/player/volume?volume_percent=%s" % volume_percent, device_id))
|
self._put(
|
||||||
|
self._append_device_id(
|
||||||
|
"me/player/volume?volume_percent=%s" %
|
||||||
|
volume_percent, device_id))
|
||||||
|
|
||||||
def shuffle(self, state, device_id = None):
|
def shuffle(self, state, device_id=None):
|
||||||
''' Toggle playback shuffling.
|
''' Toggle playback shuffling.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -1067,7 +1097,10 @@ class Spotify(object):
|
|||||||
self._warn('state must be a boolean')
|
self._warn('state must be a boolean')
|
||||||
return
|
return
|
||||||
state = str(state).lower()
|
state = str(state).lower()
|
||||||
self._put(self._append_device_id("me/player/shuffle?state=%s" % state, device_id))
|
self._put(
|
||||||
|
self._append_device_id(
|
||||||
|
"me/player/shuffle?state=%s" %
|
||||||
|
state, device_id))
|
||||||
|
|
||||||
def _append_device_id(self, path, device_id):
|
def _append_device_id(self, path, device_id):
|
||||||
''' Append device ID to API path.
|
''' Append device ID to API path.
|
||||||
|
|||||||
@ -27,7 +27,11 @@ class SpotifyOauthError(Exception):
|
|||||||
|
|
||||||
|
|
||||||
def _make_authorization_headers(client_id, client_secret):
|
def _make_authorization_headers(client_id, client_secret):
|
||||||
auth_header = base64.b64encode(six.text_type(client_id + ':' + client_secret).encode('ascii'))
|
auth_header = base64.b64encode(
|
||||||
|
six.text_type(
|
||||||
|
client_id +
|
||||||
|
':' +
|
||||||
|
client_secret).encode('ascii'))
|
||||||
return {'Authorization': 'Basic %s' % auth_header.decode('ascii')}
|
return {'Authorization': 'Basic %s' % auth_header.decode('ascii')}
|
||||||
|
|
||||||
|
|
||||||
@ -77,12 +81,14 @@ class SpotifyClientCredentials(object):
|
|||||||
|
|
||||||
def _request_access_token(self):
|
def _request_access_token(self):
|
||||||
"""Gets client credentials access token """
|
"""Gets client credentials access token """
|
||||||
payload = { 'grant_type': 'client_credentials'}
|
payload = {'grant_type': 'client_credentials'}
|
||||||
|
|
||||||
headers = _make_authorization_headers(self.client_id, self.client_secret)
|
headers = _make_authorization_headers(
|
||||||
|
self.client_id, self.client_secret)
|
||||||
|
|
||||||
response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
|
response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
|
||||||
headers=headers, verify=True, proxies=self.proxies)
|
headers=headers, verify=True,
|
||||||
|
proxies=self.proxies)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
raise SpotifyOauthError(response.reason)
|
raise SpotifyOauthError(response.reason)
|
||||||
token_info = response.json()
|
token_info = response.json()
|
||||||
@ -109,7 +115,7 @@ class SpotifyOAuth(object):
|
|||||||
OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token'
|
OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token'
|
||||||
|
|
||||||
def __init__(self, client_id, client_secret, redirect_uri,
|
def __init__(self, client_id, client_secret, redirect_uri,
|
||||||
state=None, scope=None, cache_path=None, proxies=None):
|
state=None, scope=None, cache_path=None, proxies=None):
|
||||||
'''
|
'''
|
||||||
Creates a SpotifyOAuth object
|
Creates a SpotifyOAuth object
|
||||||
|
|
||||||
@ -125,9 +131,9 @@ class SpotifyOAuth(object):
|
|||||||
self.client_id = client_id
|
self.client_id = client_id
|
||||||
self.client_secret = client_secret
|
self.client_secret = client_secret
|
||||||
self.redirect_uri = redirect_uri
|
self.redirect_uri = redirect_uri
|
||||||
self.state=state
|
self.state = state
|
||||||
self.cache_path = cache_path
|
self.cache_path = cache_path
|
||||||
self.scope=self._normalize_scope(scope)
|
self.scope = self._normalize_scope(scope)
|
||||||
self.proxies = proxies
|
self.proxies = proxies
|
||||||
|
|
||||||
def get_cached_token(self):
|
def get_cached_token(self):
|
||||||
@ -142,11 +148,13 @@ class SpotifyOAuth(object):
|
|||||||
token_info = json.loads(token_info_string)
|
token_info = json.loads(token_info_string)
|
||||||
|
|
||||||
# if scopes don't match, then bail
|
# if scopes don't match, then bail
|
||||||
if 'scope' not in token_info or not self._is_scope_subset(self.scope, token_info['scope']):
|
if 'scope' not in token_info or not self._is_scope_subset(
|
||||||
|
self.scope, token_info['scope']):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if self.is_token_expired(token_info):
|
if self.is_token_expired(token_info):
|
||||||
token_info = self.refresh_access_token(token_info['refresh_token'])
|
token_info = self.refresh_access_token(
|
||||||
|
token_info['refresh_token'])
|
||||||
|
|
||||||
except IOError:
|
except IOError:
|
||||||
pass
|
pass
|
||||||
@ -164,7 +172,8 @@ class SpotifyOAuth(object):
|
|||||||
|
|
||||||
def _is_scope_subset(self, needle_scope, haystack_scope):
|
def _is_scope_subset(self, needle_scope, haystack_scope):
|
||||||
needle_scope = set(needle_scope.split()) if needle_scope else set()
|
needle_scope = set(needle_scope.split()) if needle_scope else set()
|
||||||
haystack_scope = set(haystack_scope.split()) if haystack_scope else set()
|
haystack_scope = set(
|
||||||
|
haystack_scope.split()) if haystack_scope else set()
|
||||||
return needle_scope <= haystack_scope
|
return needle_scope <= haystack_scope
|
||||||
|
|
||||||
def is_token_expired(self, token_info):
|
def is_token_expired(self, token_info):
|
||||||
@ -222,7 +231,8 @@ class SpotifyOAuth(object):
|
|||||||
headers = self._make_authorization_headers()
|
headers = self._make_authorization_headers()
|
||||||
|
|
||||||
response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
|
response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
|
||||||
headers=headers, verify=True, proxies=self.proxies)
|
headers=headers, verify=True,
|
||||||
|
proxies=self.proxies)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
raise SpotifyOauthError(response.reason)
|
raise SpotifyOauthError(response.reason)
|
||||||
token_info = response.json()
|
token_info = response.json()
|
||||||
@ -232,30 +242,29 @@ class SpotifyOAuth(object):
|
|||||||
|
|
||||||
def _normalize_scope(self, scope):
|
def _normalize_scope(self, scope):
|
||||||
if scope:
|
if scope:
|
||||||
scopes = scope.split()
|
scopes = sorted(scope.split())
|
||||||
scopes.sort()
|
|
||||||
return ' '.join(scopes)
|
return ' '.join(scopes)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def refresh_access_token(self, refresh_token):
|
def refresh_access_token(self, refresh_token):
|
||||||
payload = { 'refresh_token': refresh_token,
|
payload = {'refresh_token': refresh_token,
|
||||||
'grant_type': 'refresh_token'}
|
'grant_type': 'refresh_token'}
|
||||||
|
|
||||||
headers = self._make_authorization_headers()
|
headers = self._make_authorization_headers()
|
||||||
|
|
||||||
response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
|
response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
|
||||||
headers=headers, proxies=self.proxies)
|
headers=headers, proxies=self.proxies)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
if False: # debugging code
|
if False: # debugging code
|
||||||
print('headers', headers)
|
print('headers', headers)
|
||||||
print('request', response.url)
|
print('request', response.url)
|
||||||
self._warn("couldn't refresh token: code:%d reason:%s" \
|
self._warn("couldn't refresh token: code:%d reason:%s"
|
||||||
% (response.status_code, response.reason))
|
% (response.status_code, response.reason))
|
||||||
return None
|
return None
|
||||||
token_info = response.json()
|
token_info = response.json()
|
||||||
token_info = self._add_custom_values_to_token_info(token_info)
|
token_info = self._add_custom_values_to_token_info(token_info)
|
||||||
if not 'refresh_token' in token_info:
|
if 'refresh_token' not in token_info:
|
||||||
token_info['refresh_token'] = refresh_token
|
token_info['refresh_token'] = refresh_token
|
||||||
self._save_token_info(token_info)
|
self._save_token_info(token_info)
|
||||||
return token_info
|
return token_info
|
||||||
@ -271,4 +280,3 @@ class SpotifyOAuth(object):
|
|||||||
|
|
||||||
def _warn(self, msg):
|
def _warn(self, msg):
|
||||||
print('warning:' + msg, file=sys.stderr)
|
print('warning:' + msg, file=sys.stderr)
|
||||||
|
|
||||||
|
|||||||
@ -22,8 +22,10 @@ CLIENT_CREDS_ENV_VARS = {
|
|||||||
'redirect_uri': 'SPOTIPY_REDIRECT_URI'
|
'redirect_uri': 'SPOTIPY_REDIRECT_URI'
|
||||||
}
|
}
|
||||||
|
|
||||||
def prompt_for_user_token(username, scope=None, client_id = None,
|
|
||||||
client_secret = None, redirect_uri = None, cache_path = None):
|
def prompt_for_user_token(username, scope=None, client_id=None,
|
||||||
|
client_secret=None, redirect_uri=None,
|
||||||
|
cache_path=None):
|
||||||
''' prompts the user to login if necessary and returns
|
''' prompts the user to login if necessary and returns
|
||||||
the user token suitable for use with the spotipy.Spotify
|
the user token suitable for use with the spotipy.Spotify
|
||||||
constructor
|
constructor
|
||||||
@ -64,7 +66,7 @@ def prompt_for_user_token(username, scope=None, client_id = None,
|
|||||||
|
|
||||||
cache_path = cache_path or ".cache-" + username
|
cache_path = cache_path or ".cache-" + username
|
||||||
sp_oauth = oauth2.SpotifyOAuth(client_id, client_secret, redirect_uri,
|
sp_oauth = oauth2.SpotifyOAuth(client_id, client_secret, redirect_uri,
|
||||||
scope=scope, cache_path=cache_path)
|
scope=scope, cache_path=cache_path)
|
||||||
|
|
||||||
# try to get a valid token for this user, from the cache,
|
# try to get a valid token for this user, from the cache,
|
||||||
# if not in the cache, the create a new (this will send
|
# if not in the cache, the create a new (this will send
|
||||||
@ -87,7 +89,7 @@ def prompt_for_user_token(username, scope=None, client_id = None,
|
|||||||
import webbrowser
|
import webbrowser
|
||||||
webbrowser.open(auth_url)
|
webbrowser.open(auth_url)
|
||||||
print("Opened %s in your browser" % auth_url)
|
print("Opened %s in your browser" % auth_url)
|
||||||
except:
|
except BaseException:
|
||||||
print("Please navigate here: %s" % auth_url)
|
print("Please navigate here: %s" % auth_url)
|
||||||
|
|
||||||
print()
|
print()
|
||||||
|
|||||||
@ -14,27 +14,23 @@ following environment variables
|
|||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import os
|
|
||||||
from pprint import pprint
|
|
||||||
import sys
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.abspath(os.pardir))
|
|
||||||
|
|
||||||
from spotipy import (
|
from spotipy import (
|
||||||
CLIENT_CREDS_ENV_VARS as CCEV,
|
CLIENT_CREDS_ENV_VARS as CCEV,
|
||||||
prompt_for_user_token,
|
prompt_for_user_token,
|
||||||
Spotify,
|
Spotify,
|
||||||
SpotifyException,
|
SpotifyException,
|
||||||
)
|
)
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath(os.pardir))
|
||||||
|
|
||||||
|
|
||||||
class AuthTestSpotipy(unittest.TestCase):
|
class AuthTestSpotipy(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
These tests require user authentication - provide client credentials using the
|
These tests require user authentication - provide client credentials using
|
||||||
following environment variables
|
the following environment variables
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -47,30 +43,32 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
|
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
|
||||||
playlist_new_id = "spotify:playlist:7GlxpQjjxRjmbb3RP2rDqI"
|
playlist_new_id = "spotify:playlist:7GlxpQjjxRjmbb3RP2rDqI"
|
||||||
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||||
"spotify:track:7IHOIqZUUInxjVkko181PB",
|
"spotify:track:7IHOIqZUUInxjVkko181PB",
|
||||||
"4VrWlk8IQxevMvERoX08iC",
|
"4VrWlk8IQxevMvERoX08iC",
|
||||||
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
|
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
|
||||||
|
|
||||||
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||||
"spotify:track:7IHOIqZUUInxjVkko181PB"]
|
"spotify:track:7IHOIqZUUInxjVkko181PB"]
|
||||||
|
|
||||||
other_tracks=["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
|
other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
|
||||||
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
|
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
|
||||||
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
|
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
|
||||||
|
|
||||||
album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU",
|
album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU",
|
||||||
"spotify:album:6RTzC0rDbvagTSJLlY7AKl"]
|
"spotify:album:6RTzC0rDbvagTSJLlY7AKl"]
|
||||||
|
|
||||||
bad_id = 'BAD_ID'
|
bad_id = 'BAD_ID'
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(self):
|
def setUpClass(self):
|
||||||
|
|
||||||
missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))
|
missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))
|
||||||
|
|
||||||
if missing:
|
if missing:
|
||||||
raise Exception('Please set the client credentials for the test application using the following environment variables: {}'.format(CCEV.values()))
|
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.username = os.getenv(CCEV['client_username'])
|
||||||
|
|
||||||
@ -121,14 +119,12 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
results = self.spotify.user_playlist_tracks(user, pid)
|
results = self.spotify.user_playlist_tracks(user, pid)
|
||||||
self.assertTrue(len(results['items']) >= 0)
|
self.assertTrue(len(results['items']) >= 0)
|
||||||
|
|
||||||
def user_playlist_tracks(self, user, playlist_id = None, fields=None,
|
# known API issue currently causes this test to fail
|
||||||
limit=100, offset=0):
|
# the issue is that the API doesn't currently respect the
|
||||||
|
# limit parameter
|
||||||
# known API issue currently causes this test to fail
|
# def user_playlist_tracks(self, user, playlist_id=None, fields=None,
|
||||||
# the issue is that the API doesn't currently respect the
|
# limit=100, offset=0):
|
||||||
# limit parameter
|
# self.assertTrue(len(playlists['items']) == 5)
|
||||||
|
|
||||||
self.assertTrue(len(playlists['items']) == 5)
|
|
||||||
|
|
||||||
def test_current_user_saved_albums(self):
|
def test_current_user_saved_albums(self):
|
||||||
# List
|
# List
|
||||||
@ -139,7 +135,10 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
self.spotify.current_user_saved_albums_add(self.album_ids)
|
self.spotify.current_user_saved_albums_add(self.album_ids)
|
||||||
|
|
||||||
# Contains
|
# Contains
|
||||||
self.assertTrue(self.spotify.current_user_saved_albums_contains(self.album_ids) == [True, True])
|
self.assertTrue(
|
||||||
|
self.spotify.current_user_saved_albums_contains(
|
||||||
|
self.album_ids) == [
|
||||||
|
True, True])
|
||||||
|
|
||||||
# Remove
|
# Remove
|
||||||
self.spotify.current_user_saved_albums_delete(self.album_ids)
|
self.spotify.current_user_saved_albums_delete(self.album_ids)
|
||||||
@ -152,14 +151,20 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
self.assertTrue(len(playlists['items']) == 10)
|
self.assertTrue(len(playlists['items']) == 10)
|
||||||
|
|
||||||
def test_user_playlist_follow(self):
|
def test_user_playlist_follow(self):
|
||||||
self.spotify.user_playlist_follow_playlist('plamere', '4erXB04MxwRAVqcUEpu30O')
|
self.spotify.user_playlist_follow_playlist(
|
||||||
follows = self.spotify.user_playlist_is_following('plamere', '4erXB04MxwRAVqcUEpu30O', [self.spotify.current_user()['id']])
|
'plamere', '4erXB04MxwRAVqcUEpu30O')
|
||||||
|
follows = self.spotify.user_playlist_is_following(
|
||||||
|
'plamere', '4erXB04MxwRAVqcUEpu30O', [
|
||||||
|
self.spotify.current_user()['id']])
|
||||||
|
|
||||||
self.assertTrue(len(follows) == 1, 'proper follows length')
|
self.assertTrue(len(follows) == 1, 'proper follows length')
|
||||||
self.assertTrue(follows[0], 'is following')
|
self.assertTrue(follows[0], 'is following')
|
||||||
self.spotify.user_playlist_unfollow('plamere', '4erXB04MxwRAVqcUEpu30O')
|
self.spotify.user_playlist_unfollow(
|
||||||
|
'plamere', '4erXB04MxwRAVqcUEpu30O')
|
||||||
|
|
||||||
follows = self.spotify.user_playlist_is_following('plamere', '4erXB04MxwRAVqcUEpu30O', [self.spotify.current_user()['id']])
|
follows = self.spotify.user_playlist_is_following(
|
||||||
|
'plamere', '4erXB04MxwRAVqcUEpu30O', [
|
||||||
|
self.spotify.current_user()['id']])
|
||||||
self.assertTrue(len(follows) == 1, 'proper follows length')
|
self.assertTrue(len(follows) == 1, 'proper follows length')
|
||||||
self.assertFalse(follows[0], 'is no longer following')
|
self.assertFalse(follows[0], 'is no longer following')
|
||||||
|
|
||||||
@ -176,7 +181,8 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
new_total = tracks['total']
|
new_total = tracks['total']
|
||||||
self.assertTrue(new_total - total == len(self.four_tracks))
|
self.assertTrue(new_total - total == len(self.four_tracks))
|
||||||
|
|
||||||
tracks = self.spotify.current_user_saved_tracks_delete(self.four_tracks)
|
tracks = self.spotify.current_user_saved_tracks_delete(
|
||||||
|
self.four_tracks)
|
||||||
tracks = self.spotify.current_user_saved_tracks()
|
tracks = self.spotify.current_user_saved_tracks()
|
||||||
new_total = tracks['total']
|
new_total = tracks['total']
|
||||||
self.assertTrue(new_total == total)
|
self.assertTrue(new_total == total)
|
||||||
@ -224,37 +230,45 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
if item['name'] == playlist_name:
|
if item['name'] == playlist_name:
|
||||||
return item['id']
|
return item['id']
|
||||||
playlists = self.spotify.next(playlists)
|
playlists = self.spotify.next(playlists)
|
||||||
playlist = self.spotify.user_playlist_create(self.username, playlist_name)
|
playlist = self.spotify.user_playlist_create(
|
||||||
|
self.username, playlist_name)
|
||||||
playlist_id = playlist['uri']
|
playlist_id = playlist['uri']
|
||||||
return playlist_id
|
return playlist_id
|
||||||
|
|
||||||
def test_user_playlist_ops(self):
|
def test_user_playlist_ops(self):
|
||||||
|
sp = self.spotify
|
||||||
# create empty playlist
|
# create empty playlist
|
||||||
playlist_id = self.get_or_create_spotify_playlist('spotipy-testing-playlist-1')
|
playlist_id = self.get_or_create_spotify_playlist(
|
||||||
|
'spotipy-testing-playlist-1')
|
||||||
|
|
||||||
# remove all tracks from it
|
# remove all tracks from it
|
||||||
self.spotify.user_playlist_replace_tracks(self.username, playlist_id,[])
|
sp.user_playlist_replace_tracks(
|
||||||
playlist = self.spotify.user_playlist(self.username, playlist_id)
|
self.username, playlist_id, [])
|
||||||
|
playlist = sp.user_playlist(self.username, playlist_id)
|
||||||
self.assertTrue(playlist['tracks']['total'] == 0)
|
self.assertTrue(playlist['tracks']['total'] == 0)
|
||||||
self.assertTrue(len(playlist['tracks']['items']) == 0)
|
self.assertTrue(len(playlist['tracks']['items']) == 0)
|
||||||
|
|
||||||
# add tracks to it
|
# add tracks to it
|
||||||
self.spotify.user_playlist_add_tracks(self.username, playlist_id, self.four_tracks)
|
sp.user_playlist_add_tracks(
|
||||||
playlist = self.spotify.user_playlist(self.username, playlist_id)
|
self.username, playlist_id, self.four_tracks)
|
||||||
|
playlist = sp.user_playlist(self.username, playlist_id)
|
||||||
self.assertTrue(playlist['tracks']['total'] == 4)
|
self.assertTrue(playlist['tracks']['total'] == 4)
|
||||||
self.assertTrue(len(playlist['tracks']['items']) == 4)
|
self.assertTrue(len(playlist['tracks']['items']) == 4)
|
||||||
|
|
||||||
# remove two tracks from it
|
# remove two tracks from it
|
||||||
self.spotify.user_playlist_remove_all_occurrences_of_tracks (self.username,
|
|
||||||
playlist_id, self.two_tracks)
|
sp.user_playlist_remove_all_occurrences_of_tracks(self.username,
|
||||||
playlist = self.spotify.user_playlist(self.username, playlist_id)
|
playlist_id,
|
||||||
|
self.two_tracks)
|
||||||
|
playlist = sp.user_playlist(self.username, playlist_id)
|
||||||
self.assertTrue(playlist['tracks']['total'] == 2)
|
self.assertTrue(playlist['tracks']['total'] == 2)
|
||||||
self.assertTrue(len(playlist['tracks']['items']) == 2)
|
self.assertTrue(len(playlist['tracks']['items']) == 2)
|
||||||
|
|
||||||
# replace with 3 other tracks
|
# replace with 3 other tracks
|
||||||
self.spotify.user_playlist_replace_tracks(self.username,
|
sp.user_playlist_replace_tracks(self.username,
|
||||||
playlist_id, self.other_tracks)
|
playlist_id,
|
||||||
playlist = self.spotify.user_playlist(self.username, playlist_id)
|
self.other_tracks)
|
||||||
|
playlist = sp.user_playlist(self.username, playlist_id)
|
||||||
self.assertTrue(playlist['tracks']['total'] == 3)
|
self.assertTrue(playlist['tracks']['total'] == 3)
|
||||||
self.assertTrue(len(playlist['tracks']['items']) == 3)
|
self.assertTrue(len(playlist['tracks']['items']) == 3)
|
||||||
|
|
||||||
@ -293,5 +307,6 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
# Unfollow these 2 users
|
# Unfollow these 2 users
|
||||||
self.spotify.user_unfollow_users(users)
|
self.spotify.user_unfollow_users(users)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@ -12,25 +12,21 @@ following environment variables
|
|||||||
'SPOTIPY_REDIRECT_URI'
|
'SPOTIPY_REDIRECT_URI'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
|
||||||
import pprint
|
|
||||||
import sys
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.abspath(os.pardir))
|
|
||||||
|
|
||||||
from spotipy import (
|
from spotipy import (
|
||||||
Spotify,
|
Spotify,
|
||||||
SpotifyClientCredentials,
|
SpotifyClientCredentials,
|
||||||
)
|
)
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath(os.pardir))
|
||||||
|
|
||||||
|
|
||||||
class AuthTestSpotipy(unittest.TestCase):
|
class AuthTestSpotipy(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
These tests require user authentication - provide client credentials using the
|
These tests require user authentication - provide client credentials using
|
||||||
following environment variables
|
the following environment variables
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -42,22 +38,23 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
|
|
||||||
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
|
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
|
||||||
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||||
"spotify:track:7IHOIqZUUInxjVkko181PB",
|
"spotify:track:7IHOIqZUUInxjVkko181PB",
|
||||||
"4VrWlk8IQxevMvERoX08iC",
|
"4VrWlk8IQxevMvERoX08iC",
|
||||||
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
|
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
|
||||||
|
|
||||||
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||||
"spotify:track:7IHOIqZUUInxjVkko181PB"]
|
"spotify:track:7IHOIqZUUInxjVkko181PB"]
|
||||||
|
|
||||||
other_tracks=["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
|
other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
|
||||||
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
|
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
|
||||||
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
|
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
|
||||||
|
|
||||||
bad_id = 'BAD_ID'
|
bad_id = 'BAD_ID'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(self):
|
def setUpClass(self):
|
||||||
self.spotify = Spotify(client_credentials_manager=SpotifyClientCredentials())
|
self.spotify = Spotify(
|
||||||
|
client_credentials_manager=SpotifyClientCredentials())
|
||||||
self.spotify.trace = False
|
self.spotify.trace = False
|
||||||
|
|
||||||
def test_audio_analysis(self):
|
def test_audio_analysis(self):
|
||||||
@ -77,15 +74,18 @@ class AuthTestSpotipy(unittest.TestCase):
|
|||||||
results = self.spotify.audio_features(input)
|
results = self.spotify.audio_features(input)
|
||||||
self.assertTrue(len(results) == len(input))
|
self.assertTrue(len(results) == len(input))
|
||||||
for track in results[:-1]:
|
for track in results[:-1]:
|
||||||
if track != None:
|
if track is not None:
|
||||||
assert('speechiness' in track)
|
assert('speechiness' in track)
|
||||||
self.assertTrue(results[-1] == None)
|
self.assertTrue(results[-1] is None)
|
||||||
|
|
||||||
def test_recommendations(self):
|
def test_recommendations(self):
|
||||||
results = self.spotify.recommendations(seed_tracks=self.four_tracks, min_danceability=0, max_loudness=0, target_popularity=50)
|
results = self.spotify.recommendations(
|
||||||
|
seed_tracks=self.four_tracks,
|
||||||
|
min_danceability=0,
|
||||||
|
max_loudness=0,
|
||||||
|
target_popularity=50)
|
||||||
self.assertTrue(len(results['tracks']) == 20)
|
self.assertTrue(len(results['tracks']) == 20)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@ -2,22 +2,21 @@
|
|||||||
|
|
||||||
""" Client Credentials Requests Tests """
|
""" Client Credentials Requests Tests """
|
||||||
|
|
||||||
|
from spotipy import (
|
||||||
|
Spotify,
|
||||||
|
SpotifyClientCredentials,
|
||||||
|
)
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
sys.path.insert(0, os.path.abspath(os.pardir))
|
sys.path.insert(0, os.path.abspath(os.pardir))
|
||||||
|
|
||||||
from spotipy import (
|
|
||||||
Spotify,
|
|
||||||
SpotifyClientCredentials,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ClientCredentialsTestSpotipy(unittest.TestCase):
|
class ClientCredentialsTestSpotipy(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
These tests require user authentication - provide client credentials using the
|
These tests require user authentication - provide client credentials using
|
||||||
following environment variables
|
the following environment variables
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -29,7 +28,8 @@ class ClientCredentialsTestSpotipy(unittest.TestCase):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(self):
|
def setUpClass(self):
|
||||||
self.spotify = Spotify(client_credentials_manager=SpotifyClientCredentials())
|
self.spotify = Spotify(
|
||||||
|
client_credentials_manager=SpotifyClientCredentials())
|
||||||
self.spotify.trace = False
|
self.spotify.trace = False
|
||||||
|
|
||||||
muse_urn = 'spotify:artist:12Chz98pHFMPJEknJQMWvI'
|
muse_urn = 'spotify:artist:12Chz98pHFMPJEknJQMWvI'
|
||||||
@ -40,5 +40,4 @@ class ClientCredentialsTestSpotipy(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import six.moves.urllib.parse as urllibparse
|
||||||
|
from spotipy import SpotifyOAuth
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
@ -8,13 +10,11 @@ import unittest
|
|||||||
|
|
||||||
sys.path.insert(0, os.path.abspath(os.pardir))
|
sys.path.insert(0, os.path.abspath(os.pardir))
|
||||||
|
|
||||||
from spotipy import SpotifyOAuth
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import unittest.mock as mock
|
import unittest.mock as mock
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import mock
|
import mock
|
||||||
import six.moves.urllib.parse as urllibparse
|
|
||||||
|
|
||||||
patch = mock.patch
|
patch = mock.patch
|
||||||
DEFAULT = mock.DEFAULT
|
DEFAULT = mock.DEFAULT
|
||||||
|
|||||||
@ -1,27 +1,25 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import os
|
|
||||||
import pprint
|
|
||||||
import sys
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.abspath(os.pardir))
|
|
||||||
|
|
||||||
from spotipy import (
|
from spotipy import (
|
||||||
CLIENT_CREDS_ENV_VARS as CCEV,
|
CLIENT_CREDS_ENV_VARS as CCEV,
|
||||||
prompt_for_user_token,
|
prompt_for_user_token,
|
||||||
Spotify,
|
Spotify,
|
||||||
SpotifyException,
|
SpotifyException,
|
||||||
)
|
)
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath(os.pardir))
|
||||||
|
|
||||||
|
|
||||||
class TestSpotipy(unittest.TestCase):
|
class TestSpotipy(unittest.TestCase):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
These tests require user authentication - provide client credentials using the
|
These tests require user authentication - provide client credentials using
|
||||||
following environment variables
|
the following environment variables
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
@ -42,7 +40,6 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb'
|
radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb'
|
||||||
angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM'
|
angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM'
|
||||||
|
|
||||||
|
|
||||||
bad_id = 'BAD_ID'
|
bad_id = 'BAD_ID'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -50,7 +47,10 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))
|
missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))
|
||||||
|
|
||||||
if missing:
|
if missing:
|
||||||
raise Exception('Please set the client credentials for the test application using the following environment variables: {}'.format(CCEV.values()))
|
raise Exception(
|
||||||
|
('Please set the client credentials for the test '
|
||||||
|
'the following environment variables: {}').format(
|
||||||
|
CCEV.values()))
|
||||||
|
|
||||||
self.username = os.getenv(CCEV['client_username'])
|
self.username = os.getenv(CCEV['client_username'])
|
||||||
|
|
||||||
@ -82,14 +82,16 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
tracks = results['items']
|
tracks = results['items']
|
||||||
total, received = results['total'], len(tracks)
|
total, received = results['total'], len(tracks)
|
||||||
while received < total:
|
while received < total:
|
||||||
results = self.spotify.album_tracks(self.angeles_haydn_urn, offset=received)
|
results = self.spotify.album_tracks(
|
||||||
|
self.angeles_haydn_urn, offset=received)
|
||||||
tracks.extend(results['items'])
|
tracks.extend(results['items'])
|
||||||
received = len(tracks)
|
received = len(tracks)
|
||||||
|
|
||||||
self.assertEqual(received, total)
|
self.assertEqual(received, total)
|
||||||
|
|
||||||
def test_albums(self):
|
def test_albums(self):
|
||||||
results = self.spotify.albums([self.pinkerton_urn, self.pablo_honey_urn])
|
results = self.spotify.albums(
|
||||||
|
[self.pinkerton_urn, self.pablo_honey_urn])
|
||||||
self.assertTrue('albums' in results)
|
self.assertTrue('albums' in results)
|
||||||
self.assertTrue(len(results['albums']) == 2)
|
self.assertTrue(len(results['albums']) == 2)
|
||||||
|
|
||||||
@ -107,7 +109,7 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
|
|
||||||
def test_track_bad_urn(self):
|
def test_track_bad_urn(self):
|
||||||
try:
|
try:
|
||||||
track = self.spotify.track(self.el_scorcho_bad_urn)
|
self.spotify.track(self.el_scorcho_bad_urn)
|
||||||
self.assertTrue(False)
|
self.assertTrue(False)
|
||||||
except SpotifyException:
|
except SpotifyException:
|
||||||
self.assertTrue(True)
|
self.assertTrue(True)
|
||||||
@ -158,17 +160,17 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
def test_search_timeout(self):
|
def test_search_timeout(self):
|
||||||
sp = Spotify(auth=self.token, requests_timeout=.01)
|
sp = Spotify(auth=self.token, requests_timeout=.01)
|
||||||
try:
|
try:
|
||||||
results = sp.search(q='my*', type='track')
|
sp.search(q='my*', type='track')
|
||||||
self.assertTrue(False, 'unexpected search timeout')
|
self.assertTrue(False, 'unexpected search timeout')
|
||||||
except requests.Timeout:
|
except requests.Timeout:
|
||||||
self.assertTrue(True, 'expected search timeout')
|
self.assertTrue(True, 'expected search timeout')
|
||||||
|
|
||||||
|
|
||||||
def test_album_search(self):
|
def test_album_search(self):
|
||||||
results = self.spotify.search(q='weezer pinkerton', type='album')
|
results = self.spotify.search(q='weezer pinkerton', type='album')
|
||||||
self.assertTrue('albums' in results)
|
self.assertTrue('albums' in results)
|
||||||
self.assertTrue(len(results['albums']['items']) > 0)
|
self.assertTrue(len(results['albums']['items']) > 0)
|
||||||
self.assertTrue(results['albums']['items'][0]['name'].find('Pinkerton') >= 0)
|
self.assertTrue(results['albums']['items'][0]
|
||||||
|
['name'].find('Pinkerton') >= 0)
|
||||||
|
|
||||||
def test_track_search(self):
|
def test_track_search(self):
|
||||||
results = self.spotify.search(q='el scorcho weezer', type='track')
|
results = self.spotify.search(q='el scorcho weezer', type='track')
|
||||||
@ -182,34 +184,34 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
|
|
||||||
def test_track_bad_id(self):
|
def test_track_bad_id(self):
|
||||||
try:
|
try:
|
||||||
track = self.spotify.track(self.bad_id)
|
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)
|
self.assertTrue(False)
|
||||||
except SpotifyException:
|
except SpotifyException:
|
||||||
self.assertTrue(True)
|
self.assertTrue(True)
|
||||||
|
|
||||||
def test_unauthenticated_post_fails(self):
|
def test_unauthenticated_post_fails(self):
|
||||||
with self.assertRaises(SpotifyException) as cm:
|
with self.assertRaises(SpotifyException) as cm:
|
||||||
self.spotify.user_playlist_create("spotify", "Best hits of the 90s")
|
self.spotify.user_playlist_create(
|
||||||
|
"spotify", "Best hits of the 90s")
|
||||||
self.assertTrue(cm.exception.http_status == 401 or
|
self.assertTrue(cm.exception.http_status == 401 or
|
||||||
cm.exception.http_status == 403)
|
cm.exception.http_status == 403)
|
||||||
|
|
||||||
def test_custom_requests_session(self):
|
def test_custom_requests_session(self):
|
||||||
sess = requests.Session()
|
sess = requests.Session()
|
||||||
sess.headers["user-agent"] = "spotipy-test"
|
sess.headers["user-agent"] = "spotipy-test"
|
||||||
with_custom_session = Spotify(auth=self.token, requests_session=sess)
|
with_custom_session = Spotify(auth=self.token, requests_session=sess)
|
||||||
self.assertTrue(with_custom_session.user(user="akx")["uri"] == "spotify:user:akx")
|
self.assertTrue(
|
||||||
|
with_custom_session.user(
|
||||||
|
user="akx")["uri"] == "spotify:user:akx")
|
||||||
|
|
||||||
def test_force_no_requests_session(self):
|
def test_force_no_requests_session(self):
|
||||||
with_no_session = Spotify(auth=self.token, requests_session=False)
|
with_no_session = Spotify(auth=self.token, requests_session=False)
|
||||||
self.assertFalse(isinstance(with_no_session._session, requests.Session))
|
self.assertFalse(
|
||||||
self.assertTrue(with_no_session.user(user="akx")["uri"] == "spotify:user:akx")
|
isinstance(
|
||||||
|
with_no_session._session,
|
||||||
|
requests.Session))
|
||||||
|
self.assertTrue(with_no_session.user(user="akx")
|
||||||
|
["uri"] == "spotify:user:akx")
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -220,5 +222,4 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user