def __init__(self, username, password, log_level=1): self.global_lock = Lock() self.api = SpotifyAPI(log_level=log_level) self.api.connect(username, password) if self.api.is_logged_in: self.tunigo = Tunigo(region=self.api.country)
class Spotify(): AUTOREPLACE_TRACKS = True def __init__(self, username, password, log_level=1): self.global_lock = Lock() self.api = SpotifyAPI(log_level=log_level) self.api.connect(username, password) if self.api.is_logged_in: self.tunigo = Tunigo(region=self.api.country) def logged_in(self): return self.api.is_logged_in and not self.api.disconnecting def logout(self): self.api.disconnect() def restart(self, username, password): result = self.api.reconnect(username, password) if result and self.api.is_logged_in: self.tunigo = Tunigo(region=self.api.country) return result def shutdown(self): self.api.shutdown() @Cache def getMyMusic(self, type="albums"): uris = [] collection = self.api.my_music_request(type) for item in collection: uris.append(item['uri']) return self.objectFromURI(uris, asArray=True) @Cache def getPlaylists(self, username=None): username = self.api.username if username is None else username playlist_uris = [] if username == self.api.username: playlist_uris += ["spotify:user:"******":starred"] playlists = self.api.playlists_request(username) for playlist in playlists.contents.items: uri_parts = playlist.uri.split(':') if len(uri_parts) < 2: continue # TODO support playlist folders properly if uri_parts[1] in ['start-group', 'end-group']: continue playlist_uris.append(playlist.uri) return self.objectFromURI(playlist_uris, asArray=True) def newPlaylist(self, name): self._Cache__cache = {} uri = self.api.new_playlist(name) return SpotifyPlaylist(self, uri=uri) def removePlaylist(self, playlist): self._Cache__cache = {} return self.api.remove_playlist(playlist.getURI()) def getUserToplist(self, toplist_content_type="track", username=None): return SpotifyToplist(self, toplist_content_type, "user", username, None) def getRegionToplist(self, toplist_content_type="track", region=None): return SpotifyToplist(self, toplist_content_type, "region", None, region) def getFeaturedPlaylists(self): return self.parse_tunigo_playlists(self.tunigo.getFeaturedPlaylists()) def getTopPlaylists(self): return self.parse_tunigo_playlists(self.tunigo.getTopPlaylists()) def getNewReleases(self): return self.parse_tunigo_albums(self.tunigo.getNewReleases()) def getGenres(self): return self.parse_tunigo_genres(self.tunigo.getGenres()) def getPlaylistsByGenre(self, genre_name): return self.parse_tunigo_playlists(self.tunigo.getPlaylistsByGenre(genre_name)) def discover(self): stories = [] result = self.api.discover_request() n = 0 for story in result.stories: stories.append(SpotifyStory(self, story)) n = n + 1 if n >= 50: break return stories def getRadioStations(self): stations = [] result = self.api.radio_stations_request() for station in result.stations: stations.append(SpotifyRadioStation(self, station)) return stations def getRadioGenres(self): genres = [] result = self.api.radio_genres_request() for genre in result.genres: genres.append(SpotifyRadioGenre(self, genre)) return genres def newRadioStation(self, uri): title = 'Radio %s' if 'spotify:genre:' in uri: title = title % uri.replace('spotify:genre:', '') else: item = self.objectFromURI(uri, asArray=False) if item: title = title % item.getName() else: title = title % '' return SpotifyRadioCustom(self, title, uri) def search(self, query, query_type="all", max_results=50, offset=0): return SpotifySearch(self, query, query_type=query_type, max_results=max_results, offset=offset) def objectFromInternalObj(self, object_type, objs, nameOnly=False): if nameOnly: return ", ".join([obj.name for obj in objs]) try: uris = [SpotifyUtil.gid2uri(object_type, obj.gid) for obj in objs] except: uris = SpotifyUtil.gid2uri(object_type, objs.gid) return self.objectFromURI(uris, asArray=True) def objectFromID(self, object_type, ids): try: uris = [SpotifyUtil.id2uri(object_type, id) for id in ids] except: uris = SpotifyUtil.id2uri(object_type, ids) return self.objectFromURI(uris, asArray=True) @Cache def objectFromURI(self, uris, asArray=False): with self.global_lock: if not self.logged_in(): return False uris = [uris] if type(uris) != list else uris if len(uris) == 0: return [] if asArray else None uri_type = SpotifyUtil.get_uri_type(uris[0]) if not uri_type: return [] if asArray else None elif uri_type == "playlist": if len(uris) == 1: obj = self.api.playlist_request(uris[0]) results = [SpotifyPlaylist(self, uri=uris[0], obj=obj)] if False != obj else [] else: thread_results = {} jobs = [] for index in range(0, len(uris)): jobs.append((self, uris[index], thread_results, index)) def work_function(spotify, uri, results, index): obj = self.api.playlist_request(uri) if False != obj: results[index] = SpotifyPlaylist(self, uri=uri, obj=obj) Spotify.doWorkerQueue(work_function, jobs) results = [v for k, v in thread_results.items()] elif uri_type in ["track", "album", "artist"]: results = [] uris = [uri for uri in uris if not SpotifyUtil.is_local(uri)] start = 0 finish = 100 uris_to_ask = uris[start:finish] while len(uris_to_ask) > 0: objs = self.api.metadata_request(uris_to_ask) objs = [objs] if type(objs) != list else objs failed_requests = len([obj for obj in objs if obj == False or obj == None]) if failed_requests > 0: print failed_requests, "metadata requests failed" objs = [obj for obj in objs if obj != False and obj != None] if uri_type == "track": tracks = [SpotifyTrack(self, obj=obj) for obj in objs] results.extend([track for track in tracks if False == self.AUTOREPLACE_TRACKS or track.isAvailable()]) elif uri_type == "album": results.extend([SpotifyAlbum(self, obj=obj) for obj in objs]) elif uri_type == "artist": results.extend([SpotifyArtist(self, obj=obj) for obj in objs]) start = finish finish = finish + 100 uris_to_ask = uris[start:finish] else: return [] if asArray else None if not asArray: if len(results) == 1: results = results[0] elif len(results) == 0: return [] if asArray else None return results def is_track_uri_valid(self, track_uri): return SpotifyUtil.is_track_uri_valid(track_uri) def parse_tunigo_playlists(self, pl_json): playlists = [] try: for item_json in pl_json['items']: playlist_uri = item_json['playlist']['uri'] uri_parts = playlist_uri.split(':') if len(uri_parts) < 2: continue # TODO support playlist folders properly if uri_parts[1] in ['start-group', 'end-group']: continue playlists.append(playlist_uri) return self.objectFromURI(playlists, asArray=True) except Exception, e: Logging.debug("Tunigo - parse_tunigo_playlists error: " + str(e)) return playlists
#!/usr/bin/python import sys from spotify import SpotifyAPI, SpotifyUtil def track_callback(sp, tracks): for track in tracks: print track.name sp.disconnect() def album_callback(sp, album): print album.name+"\n" uris = [] for track in album.disc[0].track: uris.append(SpotifyUtil.gid2uri("track", track.gid)) sp.metadata_request(uris, track_callback) def login_callback(sp): uri = sys.argv[1] if len(sys.argv) > 1 else "spotify:album:3OmHoatMS34vM7ZKb4WCY3" sp.metadata_request(uri, album_callback) sp = SpotifyAPI(login_callback) sp.connect()
class Spotify(): AUTOREPLACE_TRACKS = True def __init__(self, username, password, log_level=1): self.global_lock = Lock() self.api = SpotifyAPI(log_level=log_level) self.api.connect(username, password) if self.api.is_logged_in: self.tunigo = Tunigo(region=self.api.country) def logged_in(self): return self.api.is_logged_in and not self.api.disconnecting def logout(self): self.api.disconnect() def restart(self, username, password): result = self.api.reconnect(username, password) if result and self.api.is_logged_in: self.tunigo = Tunigo(region=self.api.country) return result def shutdown(self): self.api.shutdown() @Cache def getMyMusic(self, type="albums"): uris = [] collection = self.api.my_music_request(type) for item in collection: uris.append(item['uri']) return self.objectFromURI(uris, asArray=True) @Cache def getPlaylists(self, username=None): username = self.api.username if username is None else username playlist_uris = [] if username == self.api.username: playlist_uris += ["spotify:user:"******":starred"] playlists = self.api.playlists_request(username) for playlist in playlists.contents.items: uri_parts = playlist.uri.split(':') if len(uri_parts) < 2: continue # TODO support playlist folders properly if uri_parts[1] in ['start-group', 'end-group']: continue playlist_uris.append(playlist.uri) return self.objectFromURI(playlist_uris, asArray=True) def newPlaylist(self, name): self._Cache__cache = {} uri = self.api.new_playlist(name) return SpotifyPlaylist(self, uri=uri) def removePlaylist(self, playlist): self._Cache__cache = {} return self.api.remove_playlist(playlist.getURI()) def getUserToplist(self, toplist_content_type="track", username=None): return SpotifyToplist(self, toplist_content_type, "user", username, None) def getRegionToplist(self, toplist_content_type="track", region=None): return SpotifyToplist(self, toplist_content_type, "region", None, region) def getFeaturedPlaylists(self): return self.parse_tunigo_playlists(self.tunigo.getFeaturedPlaylists()) def getTopPlaylists(self): return self.parse_tunigo_playlists(self.tunigo.getTopPlaylists()) def getNewReleases(self): return self.parse_tunigo_albums(self.tunigo.getNewReleases()) def getGenres(self): return self.parse_tunigo_genres(self.tunigo.getGenres()) def getPlaylistsByGenre(self, genre_name): return self.parse_tunigo_playlists( self.tunigo.getPlaylistsByGenre(genre_name)) def discover(self): stories = [] result = self.api.discover_request() n = 0 for story in result.stories: stories.append(SpotifyStory(self, story)) n = n + 1 if n >= 50: break return stories def getRadioStations(self): stations = [] result = self.api.radio_stations_request() for station in result.stations: stations.append(SpotifyRadioStation(self, station)) return stations def getRadioGenres(self): genres = [] result = self.api.radio_genres_request() for genre in result.genres: genres.append(SpotifyRadioGenre(self, genre)) return genres def newRadioStation(self, uri): title = 'Radio %s' if 'spotify:genre:' in uri: title = title % uri.replace('spotify:genre:', '') else: item = self.objectFromURI(uri, asArray=False) if item: title = title % item.getName() else: title = title % '' return SpotifyRadioCustom(self, title, uri) def search(self, query, query_type="all", max_results=50, offset=0): return SpotifySearch(self, query, query_type=query_type, max_results=max_results, offset=offset) def objectFromInternalObj(self, object_type, objs, nameOnly=False): if nameOnly: return ", ".join([obj.name for obj in objs]) try: uris = [SpotifyUtil.gid2uri(object_type, obj.gid) for obj in objs] except: uris = SpotifyUtil.gid2uri(object_type, objs.gid) return self.objectFromURI(uris, asArray=True) def objectFromID(self, object_type, ids): try: uris = [SpotifyUtil.id2uri(object_type, id) for id in ids] except: uris = SpotifyUtil.id2uri(object_type, ids) return self.objectFromURI(uris, asArray=True) @Cache def objectFromURI(self, uris, asArray=False): with self.global_lock: if not self.logged_in(): return False uris = [uris] if type(uris) != list else uris if len(uris) == 0: return [] if asArray else None uri_type = SpotifyUtil.get_uri_type(uris[0]) if not uri_type: return [] if asArray else None elif uri_type == "playlist": if len(uris) == 1: obj = self.api.playlist_request(uris[0]) results = [SpotifyPlaylist(self, uri=uris[0], obj=obj) ] if False != obj else [] else: thread_results = {} jobs = [] for index in range(0, len(uris)): jobs.append((self, uris[index], thread_results, index)) def work_function(spotify, uri, results, index): obj = self.api.playlist_request(uri) if False != obj: results[index] = SpotifyPlaylist(self, uri=uri, obj=obj) Spotify.doWorkerQueue(work_function, jobs) results = [v for k, v in thread_results.items()] elif uri_type in ["track", "album", "artist"]: results = [] uris = [uri for uri in uris if not SpotifyUtil.is_local(uri)] start = 0 finish = 100 uris_to_ask = uris[start:finish] while len(uris_to_ask) > 0: objs = self.api.metadata_request(uris_to_ask) objs = [objs] if type(objs) != list else objs failed_requests = len( [obj for obj in objs if obj == False or obj == None]) if failed_requests > 0: print failed_requests, "metadata requests failed" objs = [ obj for obj in objs if obj != False and obj != None ] if uri_type == "track": tracks = [SpotifyTrack(self, obj=obj) for obj in objs] results.extend([ track for track in tracks if False == self.AUTOREPLACE_TRACKS or track.isAvailable() ]) elif uri_type == "album": results.extend( [SpotifyAlbum(self, obj=obj) for obj in objs]) elif uri_type == "artist": results.extend( [SpotifyArtist(self, obj=obj) for obj in objs]) start = finish finish = finish + 100 uris_to_ask = uris[start:finish] else: return [] if asArray else None if not asArray: if len(results) == 1: results = results[0] elif len(results) == 0: return [] if asArray else None return results def is_track_uri_valid(self, track_uri): return SpotifyUtil.is_track_uri_valid(track_uri) def parse_tunigo_playlists(self, pl_json): playlists = [] try: for item_json in pl_json['items']: playlist_uri = item_json['playlist']['uri'] uri_parts = playlist_uri.split(':') if len(uri_parts) < 2: continue # TODO support playlist folders properly if uri_parts[1] in ['start-group', 'end-group']: continue playlists.append(playlist_uri) return self.objectFromURI(playlists, asArray=True) except Exception, e: Logging.debug("Tunigo - parse_tunigo_playlists error: " + str(e)) return playlists