diff --git a/examples/collaborations.py b/examples/collaborations.py new file mode 100644 index 0000000..bde387c --- /dev/null +++ b/examples/collaborations.py @@ -0,0 +1,73 @@ +import sys +import spotipy +import pprint + +sp = None +max_artists = 100 +artist_queue = [] +queued = set() + +''' + This example generates a collaboration network suitable for plotting with graphviz + Typical usage: + + % python collaborations.py 32 deadmau5 > deadmau5.gv + % graphviz deadmau5.gv +''' + +def add_artists_from_albums(name, spid): + offset = 0 + limit = 50 + while True: + try: + response = sp.artist_albums(spid, limit=limit, offset=offset) + except spotipy.SpotifyException: + # a known issue with the API occasionally yields an error when retrieving albums + sys.stderr.write('trouble getting albums for %s' % (name,)) + return + for album in response['albums']: + for artist in album['artists']: + add_artist(name, album['name'], artist) + offset += limit + + if not response['paging']['next']: + break + +def fn(name): + return name.replace('"', '').encode('utf-8') + +def add_artist(name, album_name, artist): + if not artist['spotify_uri'] in queued: + if name: + print(' "%s" -> "%s" [label="%s"];' % (fn(name), fn(artist['name']), fn(album_name))) + queued.add(artist['spotify_uri']) + artist_queue.append( ( artist['name'], artist['spotify_uri']) ) + +def process_artists(): + done = set() + while len(artist_queue) > 0: + name, spid = artist_queue.pop(0) + if spid not in done: + done.add(spid) + if len(queued) > max_artists: + break + else: + add_artists_from_albums(name, spid) + +if __name__ == '__main__': + if len(sys.argv) < 3: + print('Usage: %s max_artists artist name' % (sys.argv[0])) + print('Example: %s 100 Rihanna' % (sys.argv[0])) + else: + max_artists = int(sys.argv[1]) + artist = ' '.join(sys.argv[2:]) + sp = spotipy.Spotify() + + results = sp.search(artist, type='artist') + artists = results['artists'] + if len(artists) > 0: + add_artist(None, None, artists[0]) + print('digraph G {') + process_artists() + print('}') + diff --git a/examples/deadmau5.gv b/examples/deadmau5.gv new file mode 100644 index 0000000..b5873ca --- /dev/null +++ b/examples/deadmau5.gv @@ -0,0 +1,31 @@ +digraph G { + "deadmau5" -> "Billy Newton-Davis" [label="All U Ever Want"]; + "deadmau5" -> "Melleefresh" [label="Afterhours (The Remixes)"]; + "deadmau5" -> "Imogen Heap" [label="Telemiscommunications (Remixes)"]; + "deadmau5" -> "Kaskade" [label="DJ Hero EP"]; + "Billy Newton-Davis" -> "Spekrfreks" [label="Back It Up"]; + "Billy Newton-Davis" -> "Cajjmere Wray" [label="Fuk Chat"]; + "Billy Newton-Davis" -> "Nino Anthony" [label="Everything I Wanna Do Remixes"]; + "Melleefresh" -> "Wutam" [label="Do You Wannit Now"]; + "Melleefresh" -> "Stereo Scum" [label="How Dangerous"]; + "Melleefresh" -> "Tyler Michaud" [label="Kisses Remixes"]; + "Imogen Heap" -> "Ron van den Beuken" [label="Headlock"]; + "Spekrfreks" -> "SpekrFreks Feat. Michelle Ericsson" [label="Tears of Blood"]; + "Spekrfreks" -> "Michelle Ericsson" [label="Voyager EP"]; + "Nino Anthony" -> "Mr. Eyez" [label="Night Muzik"]; + "Tyler Michaud" -> "Interstate" [label="Junkie"]; + "Tyler Michaud" -> "Moonbeam" [label="Openhearted"]; + "Ron van den Beuken" -> "Simon Demillo" [label="Chaos"]; + "Ron van den Beuken" -> "Tatana" [label="United Music"]; + "Ron van den Beuken" -> "Fidde Stiggson" [label="Visions"]; + "Ron van den Beuken" -> "Tom Pulse" [label="Time"]; + "Michelle Ericsson" -> "Alex Torn" [label="Electro Avenue"]; + "Mr. Eyez" -> "John Joshua feat. Mr Eyez" [label="Way of Life"]; + "Mr. Eyez" -> "Doug Smuggler" [label="Sukka MC's"]; + "Mr. Eyez" -> "New Vegas" [label="Hard Funk"]; + "Interstate" -> "Hammer & Bennett" [label="Coldharbour Selections Part 8"]; + "Tom Pulse" -> "Tom Pulse feat. Fit4Funk" [label="Flying Through the Air"]; + "Hammer & Bennett" -> "Lens" [label="Coldharbour Selections Part 10"]; + "Lens" -> "Santiago Nino" [label="Coldharbour Selections Part 6"]; + "Santiago Nino" -> "Hammer" [label="Coldharbour Selections Part 19"]; +} diff --git a/examples/deadmau5.png b/examples/deadmau5.png new file mode 100644 index 0000000..7343e63 Binary files /dev/null and b/examples/deadmau5.png differ diff --git a/examples/show_album.py b/examples/show_album.py new file mode 100644 index 0000000..2ec7b8f --- /dev/null +++ b/examples/show_album.py @@ -0,0 +1,17 @@ + +# shows artist info for a URN or URL + +import spotipy +import sys +import pprint + +if len(sys.argv) > 1: + urn = sys.argv[1] +else: + urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu' + + +sp = spotipy.Spotify() +artist = sp.artist(urn) +pprint.pprint(artist) + diff --git a/setup.py b/setup.py index 922dbff..e45fd58 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from setuptools import setup setup( name='spotipy', - version='0.9', + version='0.931', description='simple client for the Spotify Web API', author="@plamere", author_email="paul@echonest.com", diff --git a/spotipy.py b/spotipy.py index 60e5663..168dcc8 100644 --- a/spotipy.py +++ b/spotipy.py @@ -1,3 +1,4 @@ +from __future__ import print_function import requests ''' A simple and thin Python library for the Spotify Web API @@ -23,10 +24,8 @@ class Spotify(object): url = self.prefix + method args = dict(params=params) r = requests.request(verb, url, **args) - if r.status_code >= 400 and r.status_code < 500: - self._error(u'ERROR {0} {1}'.format(r.status_code, r.url)) if r.status_code != 200: - raise SpotifyException(r.status_code, -1, u'the requested resource could not be found') + raise SpotifyException(r.status_code, -1, u'the requested resource could not be found: ' + r.url) return r.json() def get(self, method, args=None, **kwargs): @@ -34,11 +33,8 @@ class Spotify(object): kwargs.update(args) return self._internal_call('GET', method, kwargs) - def _error(self, msg): - print('ERROR - ' + msg) - def _warn(self, msg): - print('warning:' + msg) + print('warning:' + msg, file=sys.stderr) def track(self, track_id): ''' returns a single track given the track's ID, URN or URL @@ -61,6 +57,12 @@ class Spotify(object): trid = self._get_id('artist', artist_id) return self.get('artists/' + trid) + def artist_albums(self, artist_id, album_type=None, limit=20, offset=0): + ''' Get Spotify catalog information about an artist’s albums + ''' + trid = self._get_id('artist', artist_id) + return self.get('artists/' + trid + '/albums', album_type=album_type, limit=limit, offset=offset) + def artists(self, artists): ''' returns a list of artists given the artist IDs, URNs, or URLs ''' diff --git a/tests/tests.py b/tests/tests.py index 53b9d72..0bc4e8e 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -60,6 +60,12 @@ class TestSpotipy(unittest.TestCase): self.assertTrue(len(results['artists']) > 0) self.assertTrue(results['artists'][0]['name'] == 'Weezer') + def test_artist_albums(self): + results = self.spotify.artist_albums(self.weezer_urn) + self.assertTrue('albums' in results) + self.assertTrue(len(results['albums']) > 0) + self.assertTrue(results['albums'][0]['artists'][0]['name'] == 'Weezer') + def test_album_search(self): results = self.spotify.search(q='weezer pinkerton', type='album') self.assertTrue('albums' in results)