from datetime import datetime from utils import spotify_credentials import concurrent.futures import requests from playlister import config def get_headers(): return { 'Authorization': 'Bearer ' + spotify_credentials.get_access_token() } def get_spotify_playlist_endpoint(user_id, playlist_id, extra=''): return (config.SPOTIFY_PLAYLIST_URL.format( user_id=user_id, playlist_id=playlist_id, extra=extra), get_headers()) def get_spotify_track_isrc_endpoint(isrc): return (config.SPOTIFY_TRACK_ISRC_URL.format(isrc=isrc)) def get_track_by_isrc(isrc): url = get_spotify_track_isrc_endpoint(isrc) r = requests.get(url) track_info = {} if r.status_code == 200: response = r.json() track_info = { 'name': response['tracks']['items'][0]['name'], 'image': response['tracks']['items'][0]['album']['images'][1][ 'url'], 'artist': response['tracks']['items'][0]['artists'][0]['name'], 'isrc': isrc, 'album': response['tracks']['items'][0]['album']['name'], 'popularity': response['tracks']['items'][0]['popularity'] } return track_info def get_spotify_playlist_tracks(user_id, playlist_id): tracks_per_page = 100 total_tracks, playlist_info = get_track_count(user_id, playlist_id) playlist_tracks = [] if total_tracks: offsets = range(0, total_tracks, tracks_per_page) with concurrent.futures.ThreadPoolExecutor( max_workers=len(offsets) ) as executor: threads = {} for index, offset in enumerate(offsets): future = executor.submit( get_track_page, user_id, playlist_id, offset, tracks_per_page) # indexing threads for later use threads.update({future: index}) # Prefill the resulting list results = [None] * len(offsets) for future in concurrent.futures.as_completed(threads): track_page = future.result() try: # retrieving the index for that future index = threads.get(future) # Filling in the resulting list at the right index results[index] = track_page except Exception: print( 'Could not retrieve page{page}' + ' offset {offset}'.format( page=index, offset=index * tracks_per_page)) del track_page playlist_tracks = [ item for track_page in results for item in track_page] return (playlist_tracks, playlist_info) def get_track_page(user_id, playlist_id, offset=0, limit=100): url, headers = get_spotify_playlist_endpoint( user_id, playlist_id, '/tracks') if url: r = requests.get(url, { 'fields': 'next,items(track(popularity,external_ids.isrc,' + 'name,external_urls.spotify,album.name,artists))', 'offset': offset, 'limit': limit }, headers=headers) if r.status_code == 200: response = r.json() return response.get('items', []) else: return [] def get_playlists_by_isrc(user_id, playlist_id, isrc, streams=0): playlist_tracks, playlist_info = get_spotify_playlist_tracks( user_id, playlist_id) orchard_track_info = filter_orchard_item_from_items(playlist_tracks, isrc) orchard_track_info.update({'stream_count': streams}) orchard_track_info.update(playlist_info) return orchard_track_info def get_track_count(user_id, playlist_id): url, headers = get_spotify_playlist_endpoint( user_id, playlist_id, '/tracks') r = requests.get(url, {'fields': 'total'}, headers=headers) response = r.json() total = response.get('total', 0) if r.status_code == 200: url, headers = get_spotify_playlist_endpoint( user_id, playlist_id) r = requests.get( url, { 'fields': 'followers,name,tracks,images,external_urls' }, headers=headers) playlist_json = r.json() if playlist_json['tracks']['items'][0]['added_at']: d = datetime.strptime(playlist_json['tracks']['items'][0]['added_at'], '%Y-%m-%dT%H:%M:%SZ') date_added = d.strftime('%Y/%m/%d') else: date_added = 'n/a' playlist_info = { 'date_added': date_added, 'followers': playlist_json['followers']['total'], 'playlist_name': playlist_json['name'], 'playlist_image_url': playlist_json['images'][0]['url'], 'playlist_url': playlist_json['external_urls']['spotify'] } return (total, playlist_info) else: return (0, {}) def filter_orchard_item_from_items(items, isrc): orchard_tracks = [] track_count = 1 for item in items: if item.get('track').get('external_ids').get('isrc') == isrc: item['track']['track_number'] = track_count orchard_tracks.append(item) track_count += 1 if len(orchard_tracks): track = orchard_tracks[0] flat_json = {} isrc = track['track']['external_ids'] flat_json.update(isrc) track['track'].pop('external_ids') artist_pop = track['track'].pop('artists') flat_json['artist_name'] = artist_pop[0]['name'] album_pop = track['track'].pop('album') flat_json['album_name'] = album_pop['name'] track_name_pop = track['track'].pop('name') flat_json['track_name'] = track_name_pop external_url_pop = track['track'].pop('external_urls') flat_json['track_url'] = external_url_pop['spotify'] for k, v in track['track'].items(): flat_json.update({k: v}) return flat_json return {'track_number': '(No longer on playlist)'}