apis.audio

   1VERSION = 2026.1 
   2
   3try
   4    import utilities
   5    utilities.modify_system_path()
   6except
   7    pass
   8import os
   9import requests
  10import base64
  11import time
  12import json
  13import random
  14import pickle
  15from urllib.parse import quote
  16
  17try
  18    from apis import secret_tokens
  19    LASTFM_KEY = secret_tokens.LASTFM_KEY
  20except
  21    print("LAST.FM not available. See Prof Bain or post on edSTEM.")
  22
  23SPOTIFY_JSON = "spotify_token.json"
  24SPOTIFY_CACHE = "spotify_cache.pkl"
  25__docformat__ = "google"
  26
  27__all__ = [
  28    "get_genres",
  29    "search_for_artists",
  30    "search_for_tracks",
  31    "search_for_playlists",
  32    "search_for_albums",
  33    "get_top_tracks_by_artist",
  34    "get_playlist_tracks",
  35    "get_playlists_by_user",
  36    "get_albums_by_artist",
  37    "get_new_releases",
  38    "generate_tracks_table",
  39    "generate_artists_table",
  40    "generate_albums_table",
  41    "generate_mixtape"
  42]
  43
  44
  45def get_genres(debug = True):
  46    """
  47    Asks Spotify for a list of available genres. There are actually 6000+ valid
  48    genres on Spotify [all of which can be found here](https://everynoise.com/everynoise1d.html)
  49    but for our purposes it might be wise to limit yourself to just these.
  50
  51    Args:
  52        debug (`bool`): whether or not you want the debug messages to be printed.
  53
  54    Returns:
  55        a `list` of `str` representing valid genres.
  56    """
  57    return [
  58        "alternative", "ambient", "blues",
  59        "chill", "country", "dance", "electronic", "folk",
  60        "funk", "happy", "hip-hop", "indie-pop", "jazz", "k-pop", "metal",
  61        "new-release", "pop", "punk", "reggae", "rock",
  62        "soul", "study", "trance", "work-out", "world-music"
  63    ]
  64
  65
  66def search_for_tracks(search_term , debug = True, simplify  = True):
  67    """
  68    Retrieves a list of Spotify tracks, given the search term passed in.
  69
  70    Args:
  71        search_term (`str`): A search term (for a song), represented as a string.
  72        debug (`bool`): Whether or not you want debug text to be printed.
  73        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
  74
  75    Returns:
  76        a `list` of tracks.
  77    """
  78    url = "https://api.spotify.com/v1/search?q=" + search_term + "&type=track"
  79    data = _issue_get_request(url, debug=debug)
  80    if not simplify
  81        return data
  82    return _simplify_tracks(data["tracks"]["items"], debug=debug)
  83
  84def _search_by_genres(genres , debug = True, simplify=True):
  85    """
  86    Retrieves a list of Spotify tracks, given some genre.
  87
  88    Args:
  89        genres (`list`): A list of valid spotify genres
  90        debug (`bool`): Whether or not you want debug text to be printed.
  91        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
  92
  93    Returns:
  94        a `list` of tracks.
  95    """
  96    url = f"https://api.spotify.com/v1/search?q=genre%3A{",".join(genres)}&type=track"
  97    data = _issue_get_request(url, debug=debug)
  98    if not simplify
  99        return data
 100    return _simplify_tracks(data["tracks"]["items"], debug=debug)
 101
 102
 103def get_top_tracks_by_artist(artist_id , debug = True, simplify  = True):
 104    """
 105    Retrieves a list of Spotify "top tracks" by an artist
 106
 107    Args:a
 108        artist_id (`str`): The Spotify id of the artist.
 109        debug (`bool`): Whether or not you want debug text to be printed.
 110        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
 111
 112    Returns:
 113        a `list` of tracks.
 114    """
 115    if len(artist_id) != 22
 116        raise TypeError(f"This function expects an Artist ID but you gave it {artist_id}.")
 117    
 118    url = "https://api.spotify.com/v1/artists/" + \
 119        artist_id + "/top-tracks?market=US"
 120    data = _issue_get_request(url, debug=debug)
 121    if not simplify
 122        return data
 123    return _simplify_tracks(data["tracks"], debug=debug)
 124
 125
 126def _get_top_tracks_by_artist(artist_id , debug = True, simplify  = True):
 127    """
 128    Only exists to allow for mock testing of underlying 
 129    """
 130    return get_top_tracks_by_artist(artist_id, debug, simplify)
 131
 132
 133def get_playlist_tracks(playlist_id , debug = True, simplify  = True):
 134    """
 135    Retrieves a list of the tracks associated with a playlist_id.
 136
 137    Args:
 138        playlist_id (`str`): The id of the Spotify playlist.
 139        debug (`bool`): Whether or not you want debug text to be printed.
 140        simplify (`bool`):  Whether you want to simplify the data that is returned.
 141
 142    Returns:
 143        a `list` of tracks.
 144    """
 145    url = "https://api.spotify.com/v1/playlists/" + playlist_id + "/tracks"
 146    data = _issue_get_request(url, debug=debug)
 147    if not simplify
 148        return data
 149
 150    def get_track(item):
 151        return item["track"]
 152    tracks = (map(get_track, data["items"]))
 153    return _simplify_tracks(tracks, debug=debug)
 154
 155
 156def search_for_artists(search_term , debug = True, simplify  = True):
 157    """
 158    Retrieves a list of Spotify artists, given the search term passed in.
 159
 160    Args:
 161        search_term (`str`): A search term (for an artist), represented as a string.
 162        debug (`bool`): Whether or not you want debug text to be printed.
 163        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
 164
 165    Returns:
 166        a `list` of artists.
 167    """
 168    url = "https://api.spotify.com/v1/search?q=" + search_term + "&type=artist&market=US"
 169    data = _issue_get_request(url, debug=debug)
 170    if not simplify
 171        return data
 172    return _simplify_artists(data["artists"]["items"], debug=debug)
 173
 174
 175def search_for_albums(search_term , debug = True, simplify  = True):
 176    """
 177    Retrieves a list of Spotify albums, given the search term passed in.
 178
 179    Args:
 180        search_term (`str`): A search term (for an album), represented as a string.
 181        debug (`bool`): Whether or not you want debug text to be printed.
 182        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
 183
 184    Returns:
 185        * a `list` of albums.
 186    """
 187    url = "https://api.spotify.com/v1/search?q=" + search_term + "&type=album&market=US"
 188    data = _issue_get_request(url, debug=debug)
 189    if not simplify
 190        return data
 191    return _simplify_albums(data["albums"]["items"], debug=debug)
 192
 193
 194def search_for_playlists(search_term , debug = True, simplify  = True):
 195    """
 196    Retrieves a list of Spotify playlists, given the search term passed in.
 197
 198    Args:
 199        search_term (`str`): A search term (for a song), represented as a string.
 200        debug (`bool`): Whether or not you want debug text to be printed.
 201        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
 202
 203    Returns:
 204        a `list` of playlists.
 205    """
 206    url = "https://api.spotify.com/v1/search?q=" + search_term + "&type=playlist"
 207    data = _issue_get_request(url, debug=debug)
 208    if not simplify
 209        return data
 210    return _simplify_playlists(data["playlists"]["items"], debug=debug)
 211
 212
 213def get_new_releases(debug = True, simplify = True):
 214    """
 215    Retrieves a list of Spotify albums that are newly released.
 216
 217    Args:
 218        debug (`bool`): Whether or not you want debug text to be printed.
 219        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
 220
 221    Returns:
 222        * a `list` of albums.
 223    """
 224    
 225    url = f"https://api.spotify.com/v1/search?q=tag:new&type=album&market=US&offset=0"
 226    data = _issue_get_request(url, debug=debug)
 227    if not simplify
 228        return data
 229    return _simplify_albums(data["albums"]["items"], debug=debug)
 230
 231
 232def get_playlists_by_user(user_id , debug = True, simplify  = True):
 233    """
 234    Retrieves a list of Spotify playlists belonging to a particular user.
 235
 236    Args:
 237        user_id (`str`): A valid Spotify user id, represented as a string.
 238        debug (`bool`): Whether or not you want debug text to be printed.
 239        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
 240
 241    Returns:
 242        a `list` of playlists belonging to the user.
 243    """
 244    url = "https://api.spotify.com/v1/users/" + user_id + "/playlists"
 245    data = _issue_get_request(url, debug=debug)
 246    if not simplify
 247        return data
 248    return _simplify_playlists(data["items"], debug=debug)
 249
 250
 251def get_albums_by_artist(artist_id, options = [], debug = True, simplify = True):
 252    """
 253    Retrieves a list of Spotify albums by a given artist.
 254
 255    Args:
 256        artist_id (`str`): A valid Spotify artist ID
 257        options (`list`): A list of special strings to indicate what sort of albums to look for. Valid
 258                          items are: `"album"`, `"single"`, "`compilation`", and `"appears_on"`.
 259        debug (`bool`): Whether or not you want debug text to be printed.
 260        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
 261
 262    Returns:
 263        * a `list` of albums.
 264    """
 265    
 266    _verify_artist_ids([artist_id])
 267    
 268    valid_options = ["album", "single", "compilation", "appears_on"]
 269    for option in options
 270        if option not in valid_options
 271            raise TypeError(f"The options input only accepts the following options: {valid_options}")
 272    
 273    if options
 274        url = f"https://api.spotify.com/v1/artists/{artist_id}/albums?include_groups={",".join(options)}&market=US"
 275    else
 276        url = f"https://api.spotify.com/v1/artists/{artist_id}/albums?market=US"
 277    data = _issue_get_request(url, debug=debug)
 278    if not simplify
 279        return data
 280    return _simplify_albums(data["items"], debug=debug)
 281
 282def _get_several_artists(artist_ids , debug = True, simplify = True):
 283    """
 284    Retrieves a bunch of particular artists from Spotify API.
 285
 286    Args:
 287        artist_id (`str`): The id of the Spotify artist.
 288        debug (`bool`): Whether or not you want debug text to be printed.
 289
 290    Returns:
 291        a `dictionary` representing the artist
 292    """
 293    if artist_ids
 294        for i in artist_ids
 295            if len(i) != 22
 296                raise TypeError(f"This input requires Artist IDs but you gave it {i}.")
 297    else
 298        raise TypeError("There are no artist ids in this list.")
 299    
 300        
 301    url = "https://api.spotify.com/v1/artists?ids=" + ",".join(artist_ids)
 302    
 303    if debug
 304        print(f"DEBUG - {"_get_several_artists"}:\nHere"s the request we"re going to make.\n{url}\nYou can"t access it in a browser, but you can double check the inputs you gave the function are part of the URL.")
 305
 306    data = _issue_get_request(url, debug=debug)
 307    
 308    if not simplify
 309        return data
 310    
 311    return _simplify_artists(data["artists"], debug=debug)
 312
 313def _get_several_tracks(track_ids , debug = True, simplify  = True):
 314    """
 315    Retrieves a bunch of particular tracks from Spotify API.
 316
 317    Args:
 318        artist_id (`str`): The id of the Spotify artist.
 319        debug (`bool`): Whether or not you want debug text to be printed.
 320
 321    Returns:
 322        a `dictionary` representing the artist
 323    """
 324    if track_ids
 325        for i in track_ids
 326            if len(i) != 22
 327                raise TypeError(f"This input requires Track IDs but you gave it {i}.")
 328    else
 329        raise TypeError("There are no Track ids in this list.")
 330
 331    url = "https://api.spotify.com/v1/tracks?ids=" + ",".join(track_ids) + "&market=US"
 332
 333    print(f"DEBUG - {"_get_several_tracks"}: Here"s the request we"re going to make.\n{url}\nYou can"t access it in a browser, but you can double check the inputs you gave the function are part of the URL.")
 334
 335    data = _issue_get_request(url, debug=debug)
 336
 337    if not simplify
 338        return data
 339    
 340    return _simplify_tracks(data["tracks"], debug=debug)
 341
 342
 343def generate_mixtape(artist_ids  = [], track_ids  = [], genres  = [], length = 20, debug  = True, practice = True, simplify  = True):
 344    """
 345    Generate a mixtape based off the inputted artists, tracks, and genres. You must provide at least 1 input across artists, tracks, and genres.
 346    <mark>Keep in mind it does not accept artist names or track names.</mark> Specifying multiple genres might result in getting zero results.</mark>
 347
 348    Note: In practice mode, this function will print a warning if inputs are invalid but will still return data.
 349
 350    Args:
 351        artist_ids (`list`): A list of artist ids (list of strings). Example: `[ "06HL4z0CvFAxyc27GXpf02", "3Nrfpe0tUJi4K4DXYWgMUX" ]`
 352        track_ids (`list`): A list of track ids. Example: `[ "5ZBeML7Lf3FMEVviTyvi8l", "29U7stRjqHU6rMiS8BfaI9" ]`
 353        genres (`list`): A list of genres. Example: `[ "chill" ]`
 354        length (`int`): How many tracks to return as part of the mixtape
 355        debug (`bool`): Whether or not you want debug text to be printed.
 356        practice (`bool`): Whether or not you want real data <mark>ONLY DO THIS IF YOU HAVE SUCCESSFULLY GOTTEN PRACTICE DATA WORKING</mark>
 357        
 358    Returns:
 359        * a `list` of tracks (dictionaries)
 360    """
 361
 362    if not artist_ids and not track_ids and not genres
 363        if practice
 364            print(f"PRACTICE MODE: Note, no inputs were given.")
 365        else
 366            raise Exception("Either artist_ids or track_ids or genres required")
 367
 368    if practice
 369        return _simplify_tracks(json.loads(TRACKS_JSON)["tracks"])
 370
 371    _verify_artist_ids(artist_ids, practice=practice)
 372    _verify_track_ids(track_ids, practice=practice)
 373
 374    track_list = []
 375
 376    for artist in artist_ids
 377        track_list += _get_top_tracks_by_artist(artist_id=artist, debug=debug, simplify=simplify)
 378
 379    if track_ids
 380        track_list += _get_several_tracks(track_ids, debug=debug, simplify=simplify)
 381
 382    if genres
 383        track_list += _search_by_genres(genres, debug=debug, simplify=simplify)
 384
 385    track_list = _remove_duplicate_tracks(track_list)
 386    random.shuffle(track_list)
 387
 388    return track_list[:length]
 389
 390
 391def _remove_duplicate_tracks(track_list):
 392    unique_track_ids = []
 393    unique_tracks = []
 394    for track in track_list
 395        if track["id"] in unique_track_ids
 396            continue
 397        else
 398            unique_track_ids.append(track["id"])
 399            unique_tracks.append(track)
 400    
 401    return unique_tracks    
 402
 403def _verify_track_ids(track_ids=[], practice = True):
 404    for i in track_ids
 405        if len(i) != 22
 406            if practice
 407                print(f"PRACTICE MODE: Note, Track ID "{i}" is invalid.")
 408            else
 409                raise TypeError(f"This input requires Track IDs but you gave it {i}.")
 410
 411
 412def _verify_artist_ids(artist_ids=[], practice = True):
 413    for i in artist_ids
 414        if len(i) != 22
 415            if practice
 416                print(f"PRACTICE MODE: Note, Artist ID "{i}" is invalid.")
 417            else
 418                raise TypeError(f"This input requires Artist IDs but you gave it {i}.")
 419
 420
 421def get_similar_tracks(artist_ids  = [], track_ids  = [], genres  = [], debug  = True, practice = True, simplify  = True):
 422    """
 423    Spotify"s way of providing recommendations. One or more params is required:
 424    artist_ids, track_ids, or genres. Up to 5 seed values may be provided in
 425    any combination of seed_artists, seed_tracks and seed_genres. In other words:
 426    len(artist_ids) + len(track_ids) + len(genres) between 1 and 5. You MUST provide
 427    at least one seed artist or track.
 428
 429    Args:
 430        artist_ids (`list`): A list of artist ids (list of strings). Example: `[ "06HL4z0CvFAxyc27GXpf02", "3Nrfpe0tUJi4K4DXYWgMUX" ]`
 431        track_ids (`list`): A list of track ids. Example: `[ "5ZBeML7Lf3FMEVviTyvi8l", "29U7stRjqHU6rMiS8BfaI9" ]`
 432        genres (`list`): A list of genres. Example: `[ "chill" ]`
 433        debug (`bool`): Whether or not you want debug text to be printed.
 434        practice (`bool`): Whether or not you want real data <mark>ONLY DO THIS IF YOU HAVE SUCCESSFULLY GOTTEN PRACTICE DATA WORKING</mark>
 435
 436    Returns:
 437        a `list` of tracks that are similar
 438    """
 439    if not artist_ids and not track_ids and not genres
 440        raise Exception("Either artist_ids or track_ids or genres required")
 441
 442    # check if seeds <= 5:
 443    random_track = {}
 444    random_artist = {}
 445    artist_ids = (artist_ids) or []
 446    track_ids = (track_ids) or []
 447    genres = (genres) or []
 448    if len(artist_ids) + len(track_ids) + len(genres) > 5
 449        error = "You can only have 5 "seed values" in your recommendations query.\n" + \
 450            "In other words, (len(artist_ids) + len(track_ids) + len(genres)) must be less than or equal to 5."
 451        raise Exception(error)
 452
 453    if artist_ids
 454        artist_ids = sorted(artist_ids)
 455        for i in artist_ids
 456            if len(i) != 22
 457                raise TypeError(f"This input requires Artist IDs but you gave it {i}.")
 458
 459        if not practice
 460            artists = _get_several_artists(artist_ids, debug=debug)
 461            print(artists)
 462            simple_artists = _simplify_artists(artists)
 463
 464            random_artist = simple_artists[0]
 465
 466    if track_ids
 467        track_ids = sorted(track_ids)
 468        for i in track_ids
 469            if len(i) != 22
 470                raise TypeError(f"This input requires Track IDs but you gave it {i}.")
 471
 472        if not practice
 473            tracks = _get_several_tracks(track_ids, debug=debug)
 474            simple_tracks = _simplify_tracks(tracks)
 475
 476            random_track = simple_tracks[0]
 477
 478    if genres
 479        genres = sorted(genres)
 480        # params.append("seed_genres=" + ",".join(genres))
 481
 482    if practice
 483        return _simplify_tracks(TRACKS_JSON)
 484
 485    if random_artist and random_track
 486        related_artists = _lastfm_get_similar_artists(random_artist["name"], debug=debug)
 487        related_artists_tracks = _lastfm_get_top_tracks(related_artists[0]["name"], debug=debug)
 488
 489        pick_one = random.choice(related_artists_tracks)
 490        other_related_tracks = _lastfm_get_similar_tracks(pick_one["name"], debug=debug )
 491
 492        related_tracks = _lastfm_get_similar_tracks(random_track["name"], random_track["artists"][0]["name"], debug=debug)
 493
 494        return other_related_tracks + related_tracks
 495
 496    elif random_track
 497        related_tracks = _lastfm_get_similar_tracks(
 498            random_track["name"], random_track["artists"][0]["name"], debug=debug
 499        )
 500        return related_tracks
 501
 502    elif random_artist
 503        related_artists = _lastfm_get_similar_artists(random_artist["name"], limit=5, debug=debug)
 504        #print(related_artists)
 505        related_artists_tracks = _lastfm_get_top_tracks(related_artists[0]["name"], debug=debug)
 506        #print(related_artists_tracks)
 507        random_track = random.choice(related_artists_tracks)
 508        print(random_track)
 509        related_tracks = _lastfm_get_similar_tracks(
 510            random_track["name"],
 511            random_track["artist"]["name"],
 512            limit=10,
 513            debug=debug,
 514        )
 515
 516        return related_tracks
 517
 518    else
 519        raise Exception(f"It looks like you either only provided a genre or we didn"t get any data back from the API request. Here"s what you gave: artist_ids: {artist_ids}\ntrack_ids: {track_ids}\ngenres: {genres}")
 520
 521
 522def _lastfm_get_similar_tracks(track_name, artist_name, limit=5, debug = False):
 523
 524    if not track_name or not artist_name
 525        raise Exception("Tried to get a track or artist with no name.")    
 526
 527    url = f"http://ws.audioscrobbler.com/2.0/?method=track.getsimilar&artist={artist_name}&track={track_name}&api_key={LASTFM_KEY}&limit={limit}&format=json"
 528
 529    if debug
 530        print(
 531            f"DEBUG - {"_lastfm_get_similar_tracks"}\nHere"s the request we"re going to make.\n{url}\nYou can"t access it in a browser, but you can double check the inputs you gave the function are part of the URL."
 532        )
 533
 534    url = quote(url, safe="/:?&,=")
 535
 536    cache_lookup = _check_cache_for(url)
 537
 538    if not cache_lookup    
 539        response = requests.get(url, verify=True)
 540        json_response = response.json()
 541        _save_to_cache(url, json_response)
 542
 543    else
 544        json_response = cache_lookup
 545
 546    print(json_response)
 547
 548    list_of_tracks = []
 549    for old_track in json_response["similartracks"]["track"]:
 550        spotify_formatted_track = {
 551            "id" old_track["mbid"],
 552            "name" old_track["name"],
 553            "url" old_track["url"],
 554            "image_url" [x["#text"] for x in old_track["image"] if x["#text"] == "large"],
 555            "artist" {
 556                "name" old_track["artist"]["name"],
 557                "share_url" old_track["artist"]["url"],
 558                "id" old_track["artist"]["mbid"],
 559            }
 560        }
 561        list_of_tracks.append(spotify_formatted_track)
 562
 563    return list_of_tracks
 564
 565
 566def _lastfm_get_top_tracks(name , limit=5, debug = False):
 567    if not name
 568        raise Exception("Tried to get an artist with no name. Double check you"re entering a valid artist.")
 569    
 570    url = f"http://ws.audioscrobbler.com/2.0/?method=artist.gettoptracks&artist={name}&api_key={LASTFM_KEY}&limit={limit}&format=json"
 571    
 572    if debug
 573        print(f"DEBUG - {"lastfm_get_top_tracks"}\nHere"s the request we"re going to make.\n{url}\nYou can"t access it in a browser, but you can double check the inputs you gave the function are part of the URL.")
 574
 575    url = quote(url, safe="/:?&,=")
 576
 577    cache_lookup = _check_cache_for(url)
 578    
 579    if not cache_lookup    
 580        response = requests.get(url, verify=True)
 581        json_response = response.json()
 582        _save_to_cache(url, json_response)
 583
 584    else
 585        json_response = cache_lookup
 586    
 587    return json_response["toptracks"]["track"]
 588
 589
 590def _lastfm_get_similar_artists(name , limit=5, debug = False):
 591    if not name
 592        raise Exception("Tried to get an artist with no name. Double check you"re entering a valid artist.")
 593    
 594    url = f"http://ws.audioscrobbler.com/2.0/?method=artist.getsimilar&artist={name}&limit={limit}&api_key={LASTFM_KEY}&format=json"
 595    
 596    if debug
 597        print(f"DEBUG - {"_lastfm_get_similar_artists"}\nHere"s the request we"re going to make.\n{url}\nYou can"t access it in a browser, but you can double check the inputs you gave the function are part of the URL.")
 598
 599    url = quote(url, safe="/:?&,=")
 600
 601    cache_lookup = _check_cache_for(url)
 602    
 603    if not cache_lookup    
 604        response = requests.get(url, verify=True)
 605        json_response = response.json()
 606        _save_to_cache(url, json_response)
 607
 608    else
 609        json_response = cache_lookup
 610    
 611    artists = json_response.get("similarartists").get("artist")
 612    
 613    return artists
 614
 615
 616def _save_to_cache(url, response):
 617
 618    if os.path.isfile(SPOTIFY_CACHE):
 619        with open(SPOTIFY_CACHE, "rb") as file
 620            cache = pickle.load(file)
 621    else
 622        cache = {}  
 623    
 624    cache[url] = response
 625
 626    with open(SPOTIFY_CACHE, "wb") as file
 627        pickle.dump(cache, file)
 628
 629
 630def _check_cache_for(url, debug=False)   
 631    # Check cache
 632    if os.path.isfile(SPOTIFY_CACHE):
 633        with open(SPOTIFY_CACHE, "rb") as file
 634            cache = pickle.load(file)
 635    else
 636        cache = {}  
 637        
 638    if url in cache
 639        if debug
 640            print(f"DEBUG - {"_check_cache_for"}: Found previous request! Returning cached result.")
 641        return cache[url]
 642    else
 643        return None
 644
 645
 646#############################
 647# Some formatting utilities #
 648#############################
 649
 650def generate_tracks_table(tracks , to_html  = False):
 651    """
 652    Function that builds a string representation of a list tracks (dictionaries).
 653
 654    Args:
 655        tracks (`list`): List of tracks.
 656        to_html (`bool`): If `True` it will generate an HTML version (for an email or web page) and if `False` (default) will generate a string to print in Python.
 657
 658    Returns:
 659        * a `str` that has a table in it for tracks
 660    """
 661
 662    if to_html
 663        return _get_tracklist_table_html(tracks)
 664
 665    line_width = 95
 666    text = ""
 667    template = "{0:2} | {1:<22.22} | {2:<30.30} | {3:<30.30}\n"
 668
 669    # header section:
 670    text += "-" * line_width + "\n"
 671    text += template.format(
 672        "", "Name", "Artist", "Album"
 673    )
 674    text += "-" * line_width + "\n"
 675
 676    # data section:
 677    counter = 1
 678    for track in tracks
 679        text += template.format(
 680            counter,
 681            track.get("name"),
 682            track.get("artist").get("name"),
 683            track.get("album").get("name")
 684        )
 685        counter += 1
 686    text += "-" * line_width + "\n"
 687    return text
 688
 689
 690def generate_albums_table(albums , to_html  = False):
 691    """
 692    Function that builds a string representation of a list of albums (dicitonaries).
 693
 694    Args:
 695        albums (`list`): list of albums (dictionaries).
 696        to_html (`bool`): If `True` it will generate an HTML version (for an email or web page) and if `False` (default) will generate a string to print in Python.
 697
 698    Returns:
 699        * a `str` that has a table in it
 700    """
 701
 702    if to_html
 703        return _get_album_table_html(albums)
 704
 705    line_width = 95
 706    text = ""
 707    template = "{0:2} | {1:<30.30} | {2:<30.30} | {3:<22.22}\n"
 708
 709    # header section:
 710    text += "-" * line_width + "\n"
 711    text += template.format("", "Name", "Primary Artist", "Release Date")
 712    text += "-" * line_width + "\n"
 713
 714    # data section:
 715    counter = 1
 716    for album in albums
 717        text += template.format(
 718            counter,
 719            album.get("name"),
 720            album.get("artist").get("name"),
 721            album.get("release_date"),
 722        )
 723        counter += 1
 724    text += "-" * line_width + "\n"
 725    return text
 726
 727
 728def generate_artists_table(artists , to_html=False):
 729    """
 730    Makes a nice formatted table of artists. Good for writing to an
 731    HTML file or showing on the screen.
 732
 733    Args:
 734        artists (`list`): A list of artists.
 735        to_html (`bool`): Whether or not you want the HTML version.
 736
 737    Returns:
 738        a `str` with an HTML table in it.
 739    """
 740    if not artists
 741        raise TypeError(f"A list of artists is required but you gave us a {type(artists)}: {artists}")
 742
 743    if to_html
 744        return _get_artist_table_html(artists)
 745
 746    line_width = 118
 747    text = ""
 748    template = "{0:2} | {1:<22.22} | {2:<30.30} | {3:<60.60}\n"
 749
 750    # header section:
 751    text += "-" * line_width + "\n"
 752    text += template.format(
 753        "", "Name", "Genres", "URL"
 754    )
 755    text += "-" * line_width + "\n"
 756
 757    # data section:
 758    counter = 1
 759    for artist in artists
 760        text += template.format(
 761            counter,
 762            artist.get("name"),
 763            artist.get("genres"),
 764            artist.get("share_url")
 765        )
 766        counter += 1
 767    text += "-" * line_width + "\n"
 768    return text
 769
 770
 771def _get_album_table_html(albums ):
 772    template = """
 773        <tr>
 774            <td {css}>{name}</td>
 775            <td {css}><img src="{image_url}" /></td>
 776            <td {css}>{primary_artist}</td>
 777            <td {css}>{release_date}</td>
 778            <td {css}><a href="{share_url}">Listen on Spotify</a></td>
 779        </tr>
 780    """
 781    cell_css = (
 782        "style="padding:3px;border-bottom:solid 1px #CCC;border-right:solid 1px #CCC;""
 783    )
 784    table_css = "style="width:100%;border:solid 1px #CCC;border-collapse:collapse;margin-bottom:10px;""
 785
 786    rows = []
 787
 788    # data section:
 789    for album in albums
 790        rows.append(
 791            template.format(
 792                css=cell_css,
 793                name=album.get("name"),
 794                image_url=album.get("image_url_small"),
 795                primary_artist=album.get("artist").get("name"),
 796                release_date=album.get("release_date"),
 797                share_url=album.get("share_url"),
 798            )
 799        )
 800
 801    return """
 802        <table {table_css}>
 803            <tr>
 804                <th {css}>Name</th>
 805                <th {css}>Image</th>
 806                <th {css}>Primary Artist</th>
 807                <th {css}>Release Date</th>
 808                <th {css}>More</th>
 809            </tr>
 810            {rows}
 811        </table>
 812    """.format(
 813        css=cell_css, table_css=table_css, rows="".join(rows)
 814    )
 815
 816
 817def _get_artist_table_html(artists ):
 818    template = """
 819        <tr>
 820            <td {css}>{name}</td>
 821            <td {css}><img src="{image_url}" /></td>
 822            <td {css}>{genres}</td>
 823            <td {css}><a href="{share_url}">Listen on Spotify</a></td>
 824        </tr>
 825    """
 826    cell_css = "style="padding:3px;border-bottom:solid 1px #CCC;border-right:solid 1px #CCC;""
 827    table_css = "style="width:100%;border:solid 1px #CCC;border-collapse:collapse;margin-bottom:10px;""
 828
 829    rows = []
 830
 831    # data section:
 832    ["name", "image_url_small", "genres", "share_url"]
 833    for artist in artists
 834        rows.append(
 835            template.format(
 836                css=cell_css,
 837                name=artist.get("name"),
 838                image_url=artist.get("image_url_small"),
 839                genres=artist.get("genres"),
 840                share_url=artist.get("share_url")
 841            )
 842        )
 843
 844    return """
 845        <table {table_css}>
 846            <tr>
 847                <th {css}>Name</th>
 848                <th {css}>Image</th>
 849                <th {css}>Genres</th>
 850                <th {css}>More</th>
 851            </tr>
 852            {rows}
 853        </table>
 854    """.format(css=cell_css, table_css=table_css, rows="".join(rows))
 855
 856
 857def _get_tracklist_table_html(tracks ):
 858    """
 859    Makes a nice formatted HTML table of tracks. Good for writing to an
 860    HTML file or for sending in an email.
 861
 862    Args:
 863        tracks (`list`): A list of tracks.
 864
 865    Returns:
 866        a `str` with an HTML table in it.
 867    """
 868    if not tracks
 869        raise TypeError(f"A list of tracks is required but you gave us a {type(tracks)}: {tracks}")
 870
 871    template = """
 872        <tr>
 873            <td {css}>{name}</td>
 874            <td {css}><img src="{image_url}" /></td>
 875            <td {css}>{artist_name}</td>
 876            <td {css}>{album_name}</td>
 877            <td {css}><a href="{share_url}">Listen on Spotify</a></td>
 878        </tr>
 879    """
 880    cell_css = "style="padding:3px;border-bottom:solid 1px #CCC;border-right:solid 1px #CCC;""
 881    table_css = "style="width:100%;border:solid 1px #CCC;border-collapse:collapse;margin-bottom:10px;""
 882
 883    rows = []
 884
 885    # data section:
 886    ["name", "album_image_url_small", "artist_name", "album_name", "share_url"]
 887    for track in tracks
 888        rows.append(
 889            template.format(
 890                css=cell_css,
 891                name=track.get("name"),
 892                image_url=track.get("album").get("image_url_small"),
 893                artist_name=track.get("artist").get("name"),
 894                album_name=track.get("album").get("name"),
 895                share_url=track.get("share_url")
 896            )
 897        )
 898
 899    return """
 900        <table {table_css}>
 901            <tr>
 902                <th {css}>Name</th>
 903                <th {css}>Image</th>
 904                <th {css}>Artist</th>
 905                <th {css}>Album</th>
 906                <th {css}>More</th>
 907            </tr>
 908            {rows}
 909        </table>
 910    """.format(css=cell_css, table_css=table_css, rows="".join(rows))
 911
 912
 913############################################
 914# Some private, helper functions utilities #
 915############################################
 916
 917def _generate_authentication_header(backup=False, debug=True):
 918    not_cached = True
 919    shoud_i_remove = False
 920    if os.path.isfile(SPOTIFY_JSON):
 921        with open(SPOTIFY_JSON) as json_file
 922            data = json.load(json_file)
 923            if time.time() >= float(data["expires"]):
 924                if debug
 925                    print(f"DEBUG - {"_generate_authentication_header"}:\n Auth token expired, time to refresh!")
 926                should_i_remove = True
 927            else
 928                token = data["token"]
 929                not_cached = False
 930    
 931    if shoud_i_remove
 932        time.sleep(0.2)
 933        os.remove(SPOTIFY_JSON)
 934
 935    if not_cached
 936        if debug
 937            print(f"DEBUG - {"_generate_authentication_header"}:\n Generating new Spotify Authentication Token...") 
 938        from apis import secret_tokens
 939        
 940        client_id = secret_tokens.SPOTIFY_CLIENT_ID
 941        client_secret = secret_tokens.SPOTIFY_CLIENT_SECRET
 942
 943        # Step 1 - Authorization
 944        auth_url = "https://accounts.spotify.com/api/token"
 945        headers = {}
 946        data = {}
 947
 948        # Encode as Base64
 949        message = f"{client_id}:{client_secret}"
 950        messageBytes = message.encode("ascii")
 951        base64Bytes = base64.b64encode(messageBytes)
 952        base64Message = base64Bytes.decode("ascii")
 953
 954        headers["Authorization"] = f"Basic {base64Message}"
 955        data["grant_type"] = "client_credentials"
 956
 957        if not backup
 958            try
 959                r = requests.post(auth_url, headers=headers, data=data)
 960                token = r.json()["access_token"]
 961                with open(SPOTIFY_JSON, "w") as outfile
 962                    json_object = json.dumps({ "token" token, "expires" time.time() + 3540}, indent=4)
 963                    outfile.write(json_object)
 964                
 965            except Exception as e
 966                if debug
 967                    print(f"DEBUG - {"_generate_authentication_header"}:\nCouldn"t use either default API Key. Trying backup!")
 968                raise Exception(e)
 969
 970    headers = {
 971        "Authorization" "Bearer " + token
 972    }
 973
 974    return headers
 975
 976def _issue_get_request(url, debug = True, practice = True):
 977    """
 978    Private function. Retrieves data from any Spotify endpoint using the authentication key.
 979
 980    * url (str): The API Endpoint + query parameters.
 981    * debug (bool): Whether or not to print debug messages.
 982    * practice (bool): Whether or not to return real data or practice data
 983
 984    Returns whatever Spotify"s API endpoint gives back.
 985    """
 986    if debug
 987        print(f"DEBUG - {"_issue_get_request"}:\nHere"s the request we"re going to make.\n", url, "\nYou can"t access it in a browser, but you can double check the inputs you gave the function are part of the URL.")
 988
 989    headers = _generate_authentication_header()
 990
 991    url = quote(url, safe="/:?&,=-")
 992
 993    # Check cache
 994    if os.path.isfile(SPOTIFY_CACHE):
 995        with open(SPOTIFY_CACHE, "rb") as file
 996            cache = pickle.load(file)
 997    else
 998        cache = {}
 999
1000    if url in cache
1001        if debug
1002            print(f"DEBUG - {"_issue_get_request"}:\nFound previous request! Returning cached result.")
1003        return cache[url]
1004
1005    response = requests.get(url, headers=headers, verify=True)
1006    if response.status_code == 429
1007        retry_length = response.headers["Retry-After"]
1008        if debug
1009            print(f"ERROR: Spotify API is overloaded! It asked us to try again in {retry_length} seconds.")
1010
1011        if os.path.isfile(SPOTIFY_JSON):
1012            os.remove(SPOTIFY_JSON)
1013
1014        if debug
1015            print(f"DEBUG - {"_issue_get_request"}:\nWe"re going to try to use the backup...")
1016        headers = _generate_authentication_header(backup=True)
1017        response = requests.get(url, headers=headers, verify=True)
1018        if response.status_code != 200
1019            raise Exception("Uh oh. Couldn"t use the backup either. It"s likely you"ve given this function invalid inputs!")
1020
1021    json_response = response.json()
1022
1023    # Save it in the cache
1024    cache[url] = json_response
1025
1026    with open(SPOTIFY_CACHE, "wb") as file
1027        pickle.dump(cache, file)
1028        
1029    return json_response
1030
1031def _simplify_tracks(tracks , debug=True):
1032    """
1033    Private function. Simplifies the Spotify track data so that each dictionary only contains
1034    a few key features (the original dictionary is quite large).
1035
1036    * tracks (list): The original tracks data structure returned from Spotify.
1037
1038    Returns a list of simplified tracks.
1039    """
1040    try
1041        tracks[0]
1042    except Exception
1043        return tracks
1044
1045    simplified = []
1046    for item in tracks
1047        track = {
1048            "id" item["id"],
1049            "name" item["name"],
1050            "preview_url" item["preview_url"],
1051            "share_url" "https://open.spotify.com/track/" + item["id"]
1052        }
1053        try
1054            track["album"] = {
1055                "id" item["album"]["id"],
1056                "name" item["album"]["name"],
1057                "image_url" item["album"]["images"][0]["url"],
1058                "image_url_small" item["album"]["images"][-1]["url"],
1059                "share_url" "https://open.spotify.com/album/" + item["album"]["id"]
1060            }
1061        except Exception
1062            pass
1063        try
1064            artists = item.get("album").get("artists")
1065            artist = artists[0]
1066            track["artist"] = {
1067                "id" artist["id"],
1068                "name" artist["name"],
1069                "share_url" "https://open.spotify.com/artist/" + item["album"]["artists"][0]["id"]
1070            }
1071        except Exception
1072            pass
1073        simplified.append(track)
1074    return simplified
1075
1076
1077def _simplify_artists(artists , debug=True):
1078    """
1079    Private function. Simplifies the Spotify artist data so that each dictionary only contains
1080    a few key features (the original dictionary is quite large).
1081
1082    * artists (list): The original artists data structure returned from Spotify.
1083
1084    Returns a list of simplified artists.
1085    """
1086    try
1087        artists[0]
1088    except Exception
1089        return artists
1090
1091    simplified = []
1092    for item in artists
1093        artist = {
1094            "id" item["id"],
1095            "name" item["name"],
1096            "genres" ", ".join(item["genres"]),
1097            "share_url" "https://open.spotify.com/artist/" + item["id"]
1098        }
1099        try
1100            artist["image_url"] = item["images"][0]["url"]
1101            artist["image_url_small"] = item["images"][-1]["url"]
1102        except Exception
1103            pass
1104        simplified.append(artist)
1105    return simplified
1106
1107def _simplify_albums(albums , debug=True):
1108    """
1109    Private function. Simplifies the Spotify artist data so that each dictionary only contains
1110    a few key features (the original dictionary is quite large).
1111
1112    * artists (list): The original artists data structure returned from Spotify.
1113
1114    Returns a list of simplified artists.
1115    """
1116    try
1117        albums[0]
1118    except Exception
1119        return albums
1120
1121    simplified = []
1122    for item in albums
1123        album = {
1124            "id" item["id"],
1125            "name" item["name"],
1126            "release_date" item["release_date"],
1127            "artist" item["artists"][0],
1128            "share_url" "https://open.spotify.com/album/" + item["id"]
1129        }
1130        try
1131            album["image_url"] = item["images"][0]["url"]
1132            album["image_url_small"] = item["images"][-1]["url"]
1133        except Exception
1134            pass
1135        simplified.append(album)
1136    return simplified
1137
1138def _simplify_playlists(playlists , debug=True):
1139    """
1140    Private function. Simplifies the Spotify playlist data so that each dictionary only contains
1141    a few key features (the original dictionary is quite large).
1142
1143    * playlists (list): The original playlist data structure returned from Spotify.
1144
1145    Returns a list of simplified playlist entries.
1146    """
1147    try
1148        simplified = []
1149        for item in playlists
1150            # Winter 25 - some playlists come back as None
1151            if item is None
1152                continue
1153            simplified.append({
1154                "id" item["id"],
1155                "name" item["name"],
1156                "owner_display_name" item["owner"]["display_name"],
1157                "owner_id" item["owner"]["id"],
1158                "share_url" "https://open.spotify.com/playlist/" + item["id"],
1159                "num_tracks" item["tracks"]["total"]
1160            })
1161        return simplified
1162    except Exception as e
1163        raise Exception(
1164            f"The following playlist data structure could not be flattened:\n{playlists}"
1165        )
1166
1167
1168TRACKS_JSON = """
1169{
1170    "tracks": [
1171        {
1172            "album": {
1173                "album_type": "ALBUM",
1174                "artists": [
1175                    {
1176                        "external_urls": {
1177                            "spotify": "https://open.spotify.com/artist/6UE7nl9mha6s8z0wFQFIZ2"
1178                        },
1179                        "href": "https://api.spotify.com/v1/artists/6UE7nl9mha6s8z0wFQFIZ2",
1180                        "id": "6UE7nl9mha6s8z0wFQFIZ2",
1181                        "name": "Robyn",
1182                        "type": "artist",
1183                        "uri": "spotify:artist:6UE7nl9mha6s8z0wFQFIZ2"
1184                    }
1185                ],
1186                "external_urls": {
1187                    "spotify": "https://open.spotify.com/album/0le9TO3kU69m6iWHTjNs9Y"
1188                },
1189                "href": "https://api.spotify.com/v1/albums/0le9TO3kU69m6iWHTjNs9Y",
1190                "id": "0le9TO3kU69m6iWHTjNs9Y",
1191                "images": [
1192                    {
1193                        "height": 640,
1194                        "url": "https://i.scdn.co/image/ab67616d0000b2734689597708c1b0b3dcb9ecaf",
1195                        "width": 640
1196                    },
1197                    {
1198                        "height": 300,
1199                        "url": "https://i.scdn.co/image/ab67616d00001e024689597708c1b0b3dcb9ecaf",
1200                        "width": 300
1201                    },
1202                    {
1203                        "height": 64,
1204                        "url": "https://i.scdn.co/image/ab67616d000048514689597708c1b0b3dcb9ecaf",
1205                        "width": 64
1206                    }
1207                ],
1208                "is_playable": true,
1209                "name": "Body Talk",
1210                "release_date": "2010-01-01",
1211                "release_date_precision": "day",
1212                "total_tracks": 15,
1213                "type": "album",
1214                "uri": "spotify:album:0le9TO3kU69m6iWHTjNs9Y"
1215            },
1216            "artists": [
1217                {
1218                    "external_urls": {
1219                        "spotify": "https://open.spotify.com/artist/6UE7nl9mha6s8z0wFQFIZ2"
1220                    },
1221                    "href": "https://api.spotify.com/v1/artists/6UE7nl9mha6s8z0wFQFIZ2",
1222                    "id": "6UE7nl9mha6s8z0wFQFIZ2",
1223                    "name": "Robyn",
1224                    "type": "artist",
1225                    "uri": "spotify:artist:6UE7nl9mha6s8z0wFQFIZ2"
1226                }
1227            ],
1228            "disc_number": 1,
1229            "duration_ms": 278080,
1230            "explicit": false,
1231            "external_ids": {
1232                "isrc": "SEWKZ1000009"
1233            },
1234            "external_urls": {
1235                "spotify": "https://open.spotify.com/track/7g13jf3zqlP5S68Voo5v9m"
1236            },
1237            "href": "https://api.spotify.com/v1/tracks/7g13jf3zqlP5S68Voo5v9m",
1238            "id": "7g13jf3zqlP5S68Voo5v9m",
1239            "is_local": false,
1240            "is_playable": true,
1241            "linked_from": {
1242                "external_urls": {
1243                    "spotify": "https://open.spotify.com/track/6aqNCrRA7vs7v6QvRpI50t"
1244                },
1245                "href": "https://api.spotify.com/v1/tracks/6aqNCrRA7vs7v6QvRpI50t",
1246                "id": "6aqNCrRA7vs7v6QvRpI50t",
1247                "type": "track",
1248                "uri": "spotify:track:6aqNCrRA7vs7v6QvRpI50t"
1249            },
1250            "name": "Dancing On My Own - Radio Edit",
1251            "popularity": 63,
1252            "preview_url": null,
1253            "track_number": 1,
1254            "type": "track",
1255            "uri": "spotify:track:7g13jf3zqlP5S68Voo5v9m"
1256        },
1257        {
1258            "album": {
1259                "album_type": "COMPILATION",
1260                "artists": [
1261                    {
1262                        "external_urls": {
1263                            "spotify": "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of"
1264                        },
1265                        "href": "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of",
1266                        "id": "0LyfQWJT6nXafLPZqxe9Of",
1267                        "name": "Various Artists",
1268                        "type": "artist",
1269                        "uri": "spotify:artist:0LyfQWJT6nXafLPZqxe9Of"
1270                    },
1271                    {
1272                        "external_urls": {
1273                            "spotify": "https://open.spotify.com/artist/2dfDjeZroUd3LWmSFrAZCD"
1274                        },
1275                        "href": "https://api.spotify.com/v1/artists/2dfDjeZroUd3LWmSFrAZCD",
1276                        "id": "2dfDjeZroUd3LWmSFrAZCD",
1277                        "name": "David Parry",
1278                        "type": "artist",
1279                        "uri": "spotify:artist:2dfDjeZroUd3LWmSFrAZCD"
1280                    },
1281                    {
1282                        "external_urls": {
1283                            "spotify": "https://open.spotify.com/artist/3PfJE6ebCbCHeuqO4BfNeA"
1284                        },
1285                        "href": "https://api.spotify.com/v1/artists/3PfJE6ebCbCHeuqO4BfNeA",
1286                        "id": "3PfJE6ebCbCHeuqO4BfNeA",
1287                        "name": "London Philharmonic Orchestra",
1288                        "type": "artist",
1289                        "uri": "spotify:artist:3PfJE6ebCbCHeuqO4BfNeA"
1290                    }
1291                ],
1292                "external_urls": {
1293                    "spotify": "https://open.spotify.com/album/0bgjJ99UFbk0yBOzjJl7cq"
1294                },
1295                "href": "https://api.spotify.com/v1/albums/0bgjJ99UFbk0yBOzjJl7cq",
1296                "id": "0bgjJ99UFbk0yBOzjJl7cq",
1297                "images": [
1298                    {
1299                        "height": 640,
1300                        "url": "https://i.scdn.co/image/ab67616d0000b27376206bd8de3a477aafd7ba83",
1301                        "width": 640
1302                    },
1303                    {
1304                        "height": 300,
1305                        "url": "https://i.scdn.co/image/ab67616d00001e0276206bd8de3a477aafd7ba83",
1306                        "width": 300
1307                    },
1308                    {
1309                        "height": 64,
1310                        "url": "https://i.scdn.co/image/ab67616d0000485176206bd8de3a477aafd7ba83",
1311                        "width": 64
1312                    }
1313                ],
1314                "is_playable": true,
1315                "name": "The 50 Greatest Pieces of Classical Music",
1316                "release_date": "2009-11-23",
1317                "release_date_precision": "day",
1318                "total_tracks": 50,
1319                "type": "album",
1320                "uri": "spotify:album:0bgjJ99UFbk0yBOzjJl7cq"
1321            },
1322            "artists": [
1323                {
1324                    "external_urls": {
1325                        "spotify": "https://open.spotify.com/artist/430byzy0c5bPn5opiu0SRd"
1326                    },
1327                    "href": "https://api.spotify.com/v1/artists/430byzy0c5bPn5opiu0SRd",
1328                    "id": "430byzy0c5bPn5opiu0SRd",
1329                    "name": "Edward Elgar",
1330                    "type": "artist",
1331                    "uri": "spotify:artist:430byzy0c5bPn5opiu0SRd"
1332                },
1333                {
1334                    "external_urls": {
1335                        "spotify": "https://open.spotify.com/artist/2dfDjeZroUd3LWmSFrAZCD"
1336                    },
1337                    "href": "https://api.spotify.com/v1/artists/2dfDjeZroUd3LWmSFrAZCD",
1338                    "id": "2dfDjeZroUd3LWmSFrAZCD",
1339                    "name": "David Parry",
1340                    "type": "artist",
1341                    "uri": "spotify:artist:2dfDjeZroUd3LWmSFrAZCD"
1342                },
1343                {
1344                    "external_urls": {
1345                        "spotify": "https://open.spotify.com/artist/3PfJE6ebCbCHeuqO4BfNeA"
1346                    },
1347                    "href": "https://api.spotify.com/v1/artists/3PfJE6ebCbCHeuqO4BfNeA",
1348                    "id": "3PfJE6ebCbCHeuqO4BfNeA",
1349                    "name": "London Philharmonic Orchestra",
1350                    "type": "artist",
1351                    "uri": "spotify:artist:3PfJE6ebCbCHeuqO4BfNeA"
1352                }
1353            ],
1354            "disc_number": 1,
1355            "duration_ms": 345666,
1356            "explicit": false,
1357            "external_ids": {
1358                "isrc": "SEWDL9750023"
1359            },
1360            "external_urls": {
1361                "spotify": "https://open.spotify.com/track/5nsYZFNyMefd50yamWgMfy"
1362            },
1363            "href": "https://api.spotify.com/v1/tracks/5nsYZFNyMefd50yamWgMfy",
1364            "id": "5nsYZFNyMefd50yamWgMfy",
1365            "is_local": false,
1366            "is_playable": true,
1367            "name": "Pomp and Circumstance, Op. 39: No. 1, March in D Major",
1368            "popularity": 43,
1369            "preview_url": "https://p.scdn.co/mp3-preview/f617411fdc9c52d598ec9d5cde4baf24895598cb?cid=b800bf59070c4b52a8917d2230d25bdc",
1370            "track_number": 23,
1371            "type": "track",
1372            "uri": "spotify:track:5nsYZFNyMefd50yamWgMfy"
1373        },
1374        {
1375            "album": {
1376                "album_type": "ALBUM",
1377                "artists": [
1378                    {
1379                        "external_urls": {
1380                            "spotify": "https://open.spotify.com/artist/37mtx80nMDETlbsq2eFCzc"
1381                        },
1382                        "href": "https://api.spotify.com/v1/artists/37mtx80nMDETlbsq2eFCzc",
1383                        "id": "37mtx80nMDETlbsq2eFCzc",
1384                        "name": "Fleur East",
1385                        "type": "artist",
1386                        "uri": "spotify:artist:37mtx80nMDETlbsq2eFCzc"
1387                    }
1388                ],
1389                "external_urls": {
1390                    "spotify": "https://open.spotify.com/album/1nFgJpjh2doGfve56uADlm"
1391                },
1392                "href": "https://api.spotify.com/v1/albums/1nFgJpjh2doGfve56uADlm",
1393                "id": "1nFgJpjh2doGfve56uADlm",
1394                "images": [
1395                    {
1396                        "height": 640,
1397                        "url": "https://i.scdn.co/image/ab67616d0000b27340ab5a3c8e7e7c8f12cca2bb",
1398                        "width": 640
1399                    },
1400                    {
1401                        "height": 300,
1402                        "url": "https://i.scdn.co/image/ab67616d00001e0240ab5a3c8e7e7c8f12cca2bb",
1403                        "width": 300
1404                    },
1405                    {
1406                        "height": 64,
1407                        "url": "https://i.scdn.co/image/ab67616d0000485140ab5a3c8e7e7c8f12cca2bb",
1408                        "width": 64
1409                    }
1410                ],
1411                "is_playable": true,
1412                "name": "Love, Sax & Flashbacks (Track by Track)",
1413                "release_date": "2015-12-03",
1414                "release_date_precision": "day",
1415                "total_tracks": 32,
1416                "type": "album",
1417                "uri": "spotify:album:1nFgJpjh2doGfve56uADlm"
1418            },
1419            "artists": [
1420                {
1421                    "external_urls": {
1422                        "spotify": "https://open.spotify.com/artist/37mtx80nMDETlbsq2eFCzc"
1423                    },
1424                    "href": "https://api.spotify.com/v1/artists/37mtx80nMDETlbsq2eFCzc",
1425                    "id": "37mtx80nMDETlbsq2eFCzc",
1426                    "name": "Fleur East",
1427                    "type": "artist",
1428                    "uri": "spotify:artist:37mtx80nMDETlbsq2eFCzc"
1429                }
1430            ],
1431            "disc_number": 1,
1432            "duration_ms": 236440,
1433            "explicit": false,
1434            "external_ids": {
1435                "isrc": "GBHMU1500146"
1436            },
1437            "external_urls": {
1438                "spotify": "https://open.spotify.com/track/2lqgZDZnlXmVZgToWuoC0l"
1439            },
1440            "href": "https://api.spotify.com/v1/tracks/2lqgZDZnlXmVZgToWuoC0l",
1441            "id": "2lqgZDZnlXmVZgToWuoC0l",
1442            "is_local": false,
1443            "is_playable": true,
1444            "linked_from": {
1445                "external_urls": {
1446                    "spotify": "https://open.spotify.com/track/2IFl6p0LoIfIZOn5IaxZOO"
1447                },
1448                "href": "https://api.spotify.com/v1/tracks/2IFl6p0LoIfIZOn5IaxZOO",
1449                "id": "2IFl6p0LoIfIZOn5IaxZOO",
1450                "type": "track",
1451                "uri": "spotify:track:2IFl6p0LoIfIZOn5IaxZOO"
1452            },
1453            "name": "Sax",
1454            "popularity": 56,
1455            "preview_url": "https://p.scdn.co/mp3-preview/6d74e1c14810c12a9ccea0c523c740ab98a262fc?cid=b800bf59070c4b52a8917d2230d25bdc",
1456            "track_number": 1,
1457            "type": "track",
1458            "uri": "spotify:track:2lqgZDZnlXmVZgToWuoC0l"
1459        },
1460        {
1461            "album": {
1462                "album_type": "SINGLE",
1463                "artists": [
1464                    {
1465                        "external_urls": {
1466                            "spotify": "https://open.spotify.com/artist/1gALaWbNDnwS2ECV09sn2A"
1467                        },
1468                        "href": "https://api.spotify.com/v1/artists/1gALaWbNDnwS2ECV09sn2A",
1469                        "id": "1gALaWbNDnwS2ECV09sn2A",
1470                        "name": "Nightcrawlers",
1471                        "type": "artist",
1472                        "uri": "spotify:artist:1gALaWbNDnwS2ECV09sn2A"
1473                    }
1474                ],
1475                "external_urls": {
1476                    "spotify": "https://open.spotify.com/album/5JVyNX3e2hGoOttoe7B8QL"
1477                },
1478                "href": "https://api.spotify.com/v1/albums/5JVyNX3e2hGoOttoe7B8QL",
1479                "id": "5JVyNX3e2hGoOttoe7B8QL",
1480                "images": [
1481                    {
1482                        "height": 640,
1483                        "url": "https://i.scdn.co/image/ab67616d0000b2733b1e6a6f5aa7c01b433779fe",
1484                        "width": 640
1485                    },
1486                    {
1487                        "height": 300,
1488                        "url": "https://i.scdn.co/image/ab67616d00001e023b1e6a6f5aa7c01b433779fe",
1489                        "width": 300
1490                    },
1491                    {
1492                        "height": 64,
1493                        "url": "https://i.scdn.co/image/ab67616d000048513b1e6a6f5aa7c01b433779fe",
1494                        "width": 64
1495                    }
1496                ],
1497                "is_playable": true,
1498                "name": "Push The Feeling On",
1499                "release_date": "1995",
1500                "release_date_precision": "year",
1501                "total_tracks": 4,
1502                "type": "album",
1503                "uri": "spotify:album:5JVyNX3e2hGoOttoe7B8QL"
1504            },
1505            "artists": [
1506                {
1507                    "external_urls": {
1508                        "spotify": "https://open.spotify.com/artist/1gALaWbNDnwS2ECV09sn2A"
1509                    },
1510                    "href": "https://api.spotify.com/v1/artists/1gALaWbNDnwS2ECV09sn2A",
1511                    "id": "1gALaWbNDnwS2ECV09sn2A",
1512                    "name": "Nightcrawlers",
1513                    "type": "artist",
1514                    "uri": "spotify:artist:1gALaWbNDnwS2ECV09sn2A"
1515                },
1516                {
1517                    "external_urls": {
1518                        "spotify": "https://open.spotify.com/artist/1yqxFtPHKcGcv6SXZNdyT9"
1519                    },
1520                    "href": "https://api.spotify.com/v1/artists/1yqxFtPHKcGcv6SXZNdyT9",
1521                    "id": "1yqxFtPHKcGcv6SXZNdyT9",
1522                    "name": "MK",
1523                    "type": "artist",
1524                    "uri": "spotify:artist:1yqxFtPHKcGcv6SXZNdyT9"
1525                }
1526            ],
1527            "disc_number": 1,
1528            "duration_ms": 243160,
1529            "explicit": false,
1530            "external_ids": {
1531                "isrc": "GBANY9500081"
1532            },
1533            "external_urls": {
1534                "spotify": "https://open.spotify.com/track/1EWsVHU4FNAdtN4R8FETag"
1535            },
1536            "href": "https://api.spotify.com/v1/tracks/1EWsVHU4FNAdtN4R8FETag",
1537            "id": "1EWsVHU4FNAdtN4R8FETag",
1538            "is_local": false,
1539            "is_playable": true,
1540            "name": "Push The Feeling On - Mk Dub Revisited Edit",
1541            "popularity": 69,
1542            "preview_url": null,
1543            "track_number": 1,
1544            "type": "track",
1545            "uri": "spotify:track:1EWsVHU4FNAdtN4R8FETag"
1546        },
1547        {
1548            "album": {
1549                "album_type": "ALBUM",
1550                "artists": [
1551                    {
1552                        "external_urls": {
1553                            "spotify": "https://open.spotify.com/artist/7gAppWoH7pcYmphCVTXkzs"
1554                        },
1555                        "href": "https://api.spotify.com/v1/artists/7gAppWoH7pcYmphCVTXkzs",
1556                        "id": "7gAppWoH7pcYmphCVTXkzs",
1557                        "name": "The Vamps",
1558                        "type": "artist",
1559                        "uri": "spotify:artist:7gAppWoH7pcYmphCVTXkzs"
1560                    }
1561                ],
1562                "external_urls": {
1563                    "spotify": "https://open.spotify.com/album/69Pj3ce9XFZUi3XuQylLKf"
1564                },
1565                "href": "https://api.spotify.com/v1/albums/69Pj3ce9XFZUi3XuQylLKf",
1566                "id": "69Pj3ce9XFZUi3XuQylLKf",
1567                "images": [
1568                    {
1569                        "height": 640,
1570                        "url": "https://i.scdn.co/image/ab67616d0000b273f36a4e2e1687e678f29328cb",
1571                        "width": 640
1572                    },
1573                    {
1574                        "height": 300,
1575                        "url": "https://i.scdn.co/image/ab67616d00001e02f36a4e2e1687e678f29328cb",
1576                        "width": 300
1577                    },
1578                    {
1579                        "height": 64,
1580                        "url": "https://i.scdn.co/image/ab67616d00004851f36a4e2e1687e678f29328cb",
1581                        "width": 64
1582                    }
1583                ],
1584                "is_playable": true,
1585                "name": "Night & Day (Night Edition)",
1586                "release_date": "2017-07-14",
1587                "release_date_precision": "day",
1588                "total_tracks": 10,
1589                "type": "album",
1590                "uri": "spotify:album:69Pj3ce9XFZUi3XuQylLKf"
1591            },
1592            "artists": [
1593                {
1594                    "external_urls": {
1595                        "spotify": "https://open.spotify.com/artist/7gAppWoH7pcYmphCVTXkzs"
1596                    },
1597                    "href": "https://api.spotify.com/v1/artists/7gAppWoH7pcYmphCVTXkzs",
1598                    "id": "7gAppWoH7pcYmphCVTXkzs",
1599                    "name": "The Vamps",
1600                    "type": "artist",
1601                    "uri": "spotify:artist:7gAppWoH7pcYmphCVTXkzs"
1602                },
1603                {
1604                    "external_urls": {
1605                        "spotify": "https://open.spotify.com/artist/4YXycRbyyAE0wozTk7QMEq"
1606                    },
1607                    "href": "https://api.spotify.com/v1/artists/4YXycRbyyAE0wozTk7QMEq",
1608                    "id": "4YXycRbyyAE0wozTk7QMEq",
1609                    "name": "Matoma",
1610                    "type": "artist",
1611                    "uri": "spotify:artist:4YXycRbyyAE0wozTk7QMEq"
1612                }
1613            ],
1614            "disc_number": 1,
1615            "duration_ms": 197640,
1616            "explicit": false,
1617            "external_ids": {
1618                "isrc": "GBUM71605342"
1619            },
1620            "external_urls": {
1621                "spotify": "https://open.spotify.com/track/0dXNQ8dckG4eYfEtq9zcva"
1622            },
1623            "href": "https://api.spotify.com/v1/tracks/0dXNQ8dckG4eYfEtq9zcva",
1624            "id": "0dXNQ8dckG4eYfEtq9zcva",
1625            "is_local": false,
1626            "is_playable": true,
1627            "name": "All Night",
1628            "popularity": 72,
1629            "preview_url": null,
1630            "track_number": 2,
1631            "type": "track",
1632            "uri": "spotify:track:0dXNQ8dckG4eYfEtq9zcva"
1633        },
1634        {
1635            "album": {
1636                "album_type": "ALBUM",
1637                "artists": [
1638                    {
1639                        "external_urls": {
1640                            "spotify": "https://open.spotify.com/artist/6fxyWrfmjcbj5d12gXeiNV"
1641                        },
1642                        "href": "https://api.spotify.com/v1/artists/6fxyWrfmjcbj5d12gXeiNV",
1643                        "id": "6fxyWrfmjcbj5d12gXeiNV",
1644                        "name": "Denzel Curry",
1645                        "type": "artist",
1646                        "uri": "spotify:artist:6fxyWrfmjcbj5d12gXeiNV"
1647                    }
1648                ],
1649                "external_urls": {
1650                    "spotify": "https://open.spotify.com/album/42fyKPanos0Q3woi848ktg"
1651                },
1652                "href": "https://api.spotify.com/v1/albums/42fyKPanos0Q3woi848ktg",
1653                "id": "42fyKPanos0Q3woi848ktg",
1654                "images": [
1655                    {
1656                        "height": 640,
1657                        "url": "https://i.scdn.co/image/ab67616d0000b273166442984ba98f0a2dcaea5e",
1658                        "width": 640
1659                    },
1660                    {
1661                        "height": 300,
1662                        "url": "https://i.scdn.co/image/ab67616d00001e02166442984ba98f0a2dcaea5e",
1663                        "width": 300
1664                    },
1665                    {
1666                        "height": 64,
1667                        "url": "https://i.scdn.co/image/ab67616d00004851166442984ba98f0a2dcaea5e",
1668                        "width": 64
1669                    }
1670                ],
1671                "is_playable": true,
1672                "name": "Imperial",
1673                "release_date": "2016-10-14",
1674                "release_date_precision": "day",
1675                "total_tracks": 10,
1676                "type": "album",
1677                "uri": "spotify:album:42fyKPanos0Q3woi848ktg"
1678            },
1679            "artists": [
1680                {
1681                    "external_urls": {
1682                        "spotify": "https://open.spotify.com/artist/6fxyWrfmjcbj5d12gXeiNV"
1683                    },
1684                    "href": "https://api.spotify.com/v1/artists/6fxyWrfmjcbj5d12gXeiNV",
1685                    "id": "6fxyWrfmjcbj5d12gXeiNV",
1686                    "name": "Denzel Curry",
1687                    "type": "artist",
1688                    "uri": "spotify:artist:6fxyWrfmjcbj5d12gXeiNV"
1689                }
1690            ],
1691            "disc_number": 1,
1692            "duration_ms": 247054,
1693            "explicit": true,
1694            "external_ids": {
1695                "isrc": "USC4R1602006"
1696            },
1697            "external_urls": {
1698                "spotify": "https://open.spotify.com/track/5BSz8sJO2YmKfNVQG7fq2J"
1699            },
1700            "href": "https://api.spotify.com/v1/tracks/5BSz8sJO2YmKfNVQG7fq2J",
1701            "id": "5BSz8sJO2YmKfNVQG7fq2J",
1702            "is_local": false,
1703            "is_playable": true,
1704            "name": "ULT",
1705            "popularity": 52,
1706            "preview_url": null,
1707            "track_number": 1,
1708            "type": "track",
1709            "uri": "spotify:track:5BSz8sJO2YmKfNVQG7fq2J"
1710        },
1711        {
1712            "album": {
1713                "album_type": "ALBUM",
1714                "artists": [
1715                    {
1716                        "external_urls": {
1717                            "spotify": "https://open.spotify.com/artist/2ojlS7imGFiZ8A8tXXGEt7"
1718                        },
1719                        "href": "https://api.spotify.com/v1/artists/2ojlS7imGFiZ8A8tXXGEt7",
1720                        "id": "2ojlS7imGFiZ8A8tXXGEt7",
1721                        "name": "Library Tapes",
1722                        "type": "artist",
1723                        "uri": "spotify:artist:2ojlS7imGFiZ8A8tXXGEt7"
1724                    }
1725                ],
1726                "external_urls": {
1727                    "spotify": "https://open.spotify.com/album/43QOTxisI7tVOFZgUIWu4g"
1728                },
1729                "href": "https://api.spotify.com/v1/albums/43QOTxisI7tVOFZgUIWu4g",
1730                "id": "43QOTxisI7tVOFZgUIWu4g",
1731                "images": [
1732                    {
1733                        "height": 640,
1734                        "url": "https://i.scdn.co/image/ab67616d0000b2736813c2e10a4fb2a5cac8ebb0",
1735                        "width": 640
1736                    },
1737                    {
1738                        "height": 300,
1739                        "url": "https://i.scdn.co/image/ab67616d00001e026813c2e10a4fb2a5cac8ebb0",
1740                        "width": 300
1741                    },
1742                    {
1743                        "height": 64,
1744                        "url": "https://i.scdn.co/image/ab67616d000048516813c2e10a4fb2a5cac8ebb0",
1745                        "width": 64
1746                    }
1747                ],
1748                "is_playable": true,
1749                "name": "Fragment",
1750                "release_date": "2008-06-15",
1751                "release_date_precision": "day",
1752                "total_tracks": 8,
1753                "type": "album",
1754                "uri": "spotify:album:43QOTxisI7tVOFZgUIWu4g"
1755            },
1756            "artists": [
1757                {
1758                    "external_urls": {
1759                        "spotify": "https://open.spotify.com/artist/2ojlS7imGFiZ8A8tXXGEt7"
1760                    },
1761                    "href": "https://api.spotify.com/v1/artists/2ojlS7imGFiZ8A8tXXGEt7",
1762                    "id": "2ojlS7imGFiZ8A8tXXGEt7",
1763                    "name": "Library Tapes",
1764                    "type": "artist",
1765                    "uri": "spotify:artist:2ojlS7imGFiZ8A8tXXGEt7"
1766                }
1767            ],
1768            "disc_number": 1,
1769            "duration_ms": 240506,
1770            "explicit": false,
1771            "external_ids": {
1772                "isrc": "SEYTP0800202"
1773            },
1774            "external_urls": {
1775                "spotify": "https://open.spotify.com/track/7vv4tJIsMFm3XnDHikiwIc"
1776            },
1777            "href": "https://api.spotify.com/v1/tracks/7vv4tJIsMFm3XnDHikiwIc",
1778            "id": "7vv4tJIsMFm3XnDHikiwIc",
1779            "is_local": false,
1780            "is_playable": true,
1781            "linked_from": {
1782                "external_urls": {
1783                    "spotify": "https://open.spotify.com/track/7JQfc4yI4R8E4WOUYR7HD9"
1784                },
1785                "href": "https://api.spotify.com/v1/tracks/7JQfc4yI4R8E4WOUYR7HD9",
1786                "id": "7JQfc4yI4R8E4WOUYR7HD9",
1787                "type": "track",
1788                "uri": "spotify:track:7JQfc4yI4R8E4WOUYR7HD9"
1789            },
1790            "name": "Fragment II",
1791            "popularity": 44,
1792            "preview_url": null,
1793            "track_number": 2,
1794            "type": "track",
1795            "uri": "spotify:track:7vv4tJIsMFm3XnDHikiwIc"
1796        },
1797        {
1798            "album": {
1799                "album_type": "ALBUM",
1800                "artists": [
1801                    {
1802                        "external_urls": {
1803                            "spotify": "https://open.spotify.com/artist/163tK9Wjr9P9DmM0AVK7lm"
1804                        },
1805                        "href": "https://api.spotify.com/v1/artists/163tK9Wjr9P9DmM0AVK7lm",
1806                        "id": "163tK9Wjr9P9DmM0AVK7lm",
1807                        "name": "Lorde",
1808                        "type": "artist",
1809                        "uri": "spotify:artist:163tK9Wjr9P9DmM0AVK7lm"
1810                    }
1811                ],
1812                "external_urls": {
1813                    "spotify": "https://open.spotify.com/album/2nPokmAvYy5qYO4rFU7ZDm"
1814                },
1815                "href": "https://api.spotify.com/v1/albums/2nPokmAvYy5qYO4rFU7ZDm",
1816                "id": "2nPokmAvYy5qYO4rFU7ZDm",
1817                "images": [
1818                    {
1819                        "height": 640,
1820                        "url": "https://i.scdn.co/image/ab67616d0000b273e19c63f62581ab73a6589382",
1821                        "width": 640
1822                    },
1823                    {
1824                        "height": 300,
1825                        "url": "https://i.scdn.co/image/ab67616d00001e02e19c63f62581ab73a6589382",
1826                        "width": 300
1827                    },
1828                    {
1829                        "height": 64,
1830                        "url": "https://i.scdn.co/image/ab67616d00004851e19c63f62581ab73a6589382",
1831                        "width": 64
1832                    }
1833                ],
1834                "is_playable": true,
1835                "name": "Pure Heroine",
1836                "release_date": "2013-01-01",
1837                "release_date_precision": "day",
1838                "total_tracks": 13,
1839                "type": "album",
1840                "uri": "spotify:album:2nPokmAvYy5qYO4rFU7ZDm"
1841            },
1842            "artists": [
1843                {
1844                    "external_urls": {
1845                        "spotify": "https://open.spotify.com/artist/163tK9Wjr9P9DmM0AVK7lm"
1846                    },
1847                    "href": "https://api.spotify.com/v1/artists/163tK9Wjr9P9DmM0AVK7lm",
1848                    "id": "163tK9Wjr9P9DmM0AVK7lm",
1849                    "name": "Lorde",
1850                    "type": "artist",
1851                    "uri": "spotify:artist:163tK9Wjr9P9DmM0AVK7lm"
1852                }
1853            ],
1854            "disc_number": 1,
1855            "duration_ms": 258969,
1856            "explicit": false,
1857            "external_ids": {
1858                "isrc": "NZUM71300122"
1859            },
1860            "external_urls": {
1861                "spotify": "https://open.spotify.com/track/2MvvoeRt8NcOXWESkxWn3g"
1862            },
1863            "href": "https://api.spotify.com/v1/tracks/2MvvoeRt8NcOXWESkxWn3g",
1864            "id": "2MvvoeRt8NcOXWESkxWn3g",
1865            "is_local": false,
1866            "is_playable": true,
1867            "linked_from": {
1868                "external_urls": {
1869                    "spotify": "https://open.spotify.com/track/38WyDtxZhxm63jiythwemE"
1870                },
1871                "href": "https://api.spotify.com/v1/tracks/38WyDtxZhxm63jiythwemE",
1872                "id": "38WyDtxZhxm63jiythwemE",
1873                "type": "track",
1874                "uri": "spotify:track:38WyDtxZhxm63jiythwemE"
1875            },
1876            "name": "Ribs",
1877            "popularity": 80,
1878            "preview_url": null,
1879            "track_number": 4,
1880            "type": "track",
1881            "uri": "spotify:track:2MvvoeRt8NcOXWESkxWn3g"
1882        },
1883        {
1884            "album": {
1885                "album_type": "SINGLE",
1886                "artists": [
1887                    {
1888                        "external_urls": {
1889                            "spotify": "https://open.spotify.com/artist/0lZoBs4Pzo7R89JM9lxwoT"
1890                        },
1891                        "href": "https://api.spotify.com/v1/artists/0lZoBs4Pzo7R89JM9lxwoT",
1892                        "id": "0lZoBs4Pzo7R89JM9lxwoT",
1893                        "name": "Duran Duran",
1894                        "type": "artist",
1895                        "uri": "spotify:artist:0lZoBs4Pzo7R89JM9lxwoT"
1896                    }
1897                ],
1898                "external_urls": {
1899                    "spotify": "https://open.spotify.com/album/5NLAqcJTupUe8pUzf6Jaen"
1900                },
1901                "href": "https://api.spotify.com/v1/albums/5NLAqcJTupUe8pUzf6Jaen",
1902                "id": "5NLAqcJTupUe8pUzf6Jaen",
1903                "images": [
1904                    {
1905                        "height": 640,
1906                        "url": "https://i.scdn.co/image/ab67616d0000b273b35021533b9088e272ceeb90",
1907                        "width": 640
1908                    },
1909                    {
1910                        "height": 300,
1911                        "url": "https://i.scdn.co/image/ab67616d00001e02b35021533b9088e272ceeb90",
1912                        "width": 300
1913                    },
1914                    {
1915                        "height": 64,
1916                        "url": "https://i.scdn.co/image/ab67616d00004851b35021533b9088e272ceeb90",
1917                        "width": 64
1918                    }
1919                ],
1920                "is_playable": true,
1921                "name": "Last Night in the City (feat. Kiesza) [The Remixes]",
1922                "release_date": "2017-03-10",
1923                "release_date_precision": "day",
1924                "total_tracks": 4,
1925                "type": "album",
1926                "uri": "spotify:album:5NLAqcJTupUe8pUzf6Jaen"
1927            },
1928            "artists": [
1929                {
1930                    "external_urls": {
1931                        "spotify": "https://open.spotify.com/artist/0lZoBs4Pzo7R89JM9lxwoT"
1932                    },
1933                    "href": "https://api.spotify.com/v1/artists/0lZoBs4Pzo7R89JM9lxwoT",
1934                    "id": "0lZoBs4Pzo7R89JM9lxwoT",
1935                    "name": "Duran Duran",
1936                    "type": "artist",
1937                    "uri": "spotify:artist:0lZoBs4Pzo7R89JM9lxwoT"
1938                },
1939                {
1940                    "external_urls": {
1941                        "spotify": "https://open.spotify.com/artist/4zxvC7CRGvggq9EWXOpwAo"
1942                    },
1943                    "href": "https://api.spotify.com/v1/artists/4zxvC7CRGvggq9EWXOpwAo",
1944                    "id": "4zxvC7CRGvggq9EWXOpwAo",
1945                    "name": "Kiesza",
1946                    "type": "artist",
1947                    "uri": "spotify:artist:4zxvC7CRGvggq9EWXOpwAo"
1948                },
1949                {
1950                    "external_urls": {
1951                        "spotify": "https://open.spotify.com/artist/5c8rdJfIrtDTnRak9cuzwv"
1952                    },
1953                    "href": "https://api.spotify.com/v1/artists/5c8rdJfIrtDTnRak9cuzwv",
1954                    "id": "5c8rdJfIrtDTnRak9cuzwv",
1955                    "name": "Louis Vivet",
1956                    "type": "artist",
1957                    "uri": "spotify:artist:5c8rdJfIrtDTnRak9cuzwv"
1958                }
1959            ],
1960            "disc_number": 1,
1961            "duration_ms": 201999,
1962            "explicit": false,
1963            "external_ids": {
1964                "isrc": "USWB11700345"
1965            },
1966            "external_urls": {
1967                "spotify": "https://open.spotify.com/track/49Ux5DRv82fNGXDO7sIy4y"
1968            },
1969            "href": "https://api.spotify.com/v1/tracks/49Ux5DRv82fNGXDO7sIy4y",
1970            "id": "49Ux5DRv82fNGXDO7sIy4y",
1971            "is_local": false,
1972            "is_playable": true,
1973            "name": "Last Night in the City (feat. Kiesza) - Louis Vivet Remix",
1974            "popularity": 6,
1975            "preview_url": "https://p.scdn.co/mp3-preview/9aa4da8b4c1b17c48a1f8a6f24058ac4e47fdf7b?cid=b800bf59070c4b52a8917d2230d25bdc",
1976            "track_number": 3,
1977            "type": "track",
1978            "uri": "spotify:track:49Ux5DRv82fNGXDO7sIy4y"
1979        },
1980        {
1981            "album": {
1982                "album_type": "SINGLE",
1983                "artists": [
1984                    {
1985                        "external_urls": {
1986                            "spotify": "https://open.spotify.com/artist/65YhYi4Fz5Ibgq7ueev2Rm"
1987                        },
1988                        "href": "https://api.spotify.com/v1/artists/65YhYi4Fz5Ibgq7ueev2Rm",
1989                        "id": "65YhYi4Fz5Ibgq7ueev2Rm",
1990                        "name": "Frederick Delius",
1991                        "type": "artist",
1992                        "uri": "spotify:artist:65YhYi4Fz5Ibgq7ueev2Rm"
1993                    },
1994                    {
1995                        "external_urls": {
1996                            "spotify": "https://open.spotify.com/artist/5Dl3HXZjG6ZOWT5cV375lk"
1997                        },
1998                        "href": "https://api.spotify.com/v1/artists/5Dl3HXZjG6ZOWT5cV375lk",
1999                        "id": "5Dl3HXZjG6ZOWT5cV375lk",
2000                        "name": "Yo-Yo Ma",
2001                        "type": "artist",
2002                        "uri": "spotify:artist:5Dl3HXZjG6ZOWT5cV375lk"
2003                    },
2004                    {
2005                        "external_urls": {
2006                            "spotify": "https://open.spotify.com/artist/7JmDqds7Y1LRSWZVM8e0Og"
2007                        },
2008                        "href": "https://api.spotify.com/v1/artists/7JmDqds7Y1LRSWZVM8e0Og",
2009                        "id": "7JmDqds7Y1LRSWZVM8e0Og",
2010                        "name": "Kathryn Stott",
2011                        "type": "artist",
2012                        "uri": "spotify:artist:7JmDqds7Y1LRSWZVM8e0Og"
2013                    }
2014                ],
2015                "external_urls": {
2016                    "spotify": "https://open.spotify.com/album/5Srtg5Q52DBLYEAIEQBDyH"
2017                },
2018                "href": "https://api.spotify.com/v1/albums/5Srtg5Q52DBLYEAIEQBDyH",
2019                "id": "5Srtg5Q52DBLYEAIEQBDyH",
2020                "images": [
2021                    {
2022                        "height": 640,
2023                        "url": "https://i.scdn.co/image/ab67616d0000b27309516b49c785767fb6193732",
2024                        "width": 640
2025                    },
2026                    {
2027                        "height": 300,
2028                        "url": "https://i.scdn.co/image/ab67616d00001e0209516b49c785767fb6193732",
2029                        "width": 300
2030                    },
2031                    {
2032                        "height": 64,
2033                        "url": "https://i.scdn.co/image/ab67616d0000485109516b49c785767fb6193732",
2034                        "width": 64
2035                    }
2036                ],
2037                "is_playable": true,
2038                "name": "Romance for Cello and Piano",
2039                "release_date": "2015-07-24",
2040                "release_date_precision": "day",
2041                "total_tracks": 1,
2042                "type": "album",
2043                "uri": "spotify:album:5Srtg5Q52DBLYEAIEQBDyH"
2044            },
2045            "artists": [
2046                {
2047                    "external_urls": {
2048                        "spotify": "https://open.spotify.com/artist/65YhYi4Fz5Ibgq7ueev2Rm"
2049                    },
2050                    "href": "https://api.spotify.com/v1/artists/65YhYi4Fz5Ibgq7ueev2Rm",
2051                    "id": "65YhYi4Fz5Ibgq7ueev2Rm",
2052                    "name": "Frederick Delius",
2053                    "type": "artist",
2054                    "uri": "spotify:artist:65YhYi4Fz5Ibgq7ueev2Rm"
2055                },
2056                {
2057                    "external_urls": {
2058                        "spotify": "https://open.spotify.com/artist/7JmDqds7Y1LRSWZVM8e0Og"
2059                    },
2060                    "href": "https://api.spotify.com/v1/artists/7JmDqds7Y1LRSWZVM8e0Og",
2061                    "id": "7JmDqds7Y1LRSWZVM8e0Og",
2062                    "name": "Kathryn Stott",
2063                    "type": "artist",
2064                    "uri": "spotify:artist:7JmDqds7Y1LRSWZVM8e0Og"
2065                },
2066                {
2067                    "external_urls": {
2068                        "spotify": "https://open.spotify.com/artist/5Dl3HXZjG6ZOWT5cV375lk"
2069                    },
2070                    "href": "https://api.spotify.com/v1/artists/5Dl3HXZjG6ZOWT5cV375lk",
2071                    "id": "5Dl3HXZjG6ZOWT5cV375lk",
2072                    "name": "Yo-Yo Ma",
2073                    "type": "artist",
2074                    "uri": "spotify:artist:5Dl3HXZjG6ZOWT5cV375lk"
2075                }
2076            ],
2077            "disc_number": 1,
2078            "duration_ms": 385186,
2079            "explicit": false,
2080            "external_ids": {
2081                "isrc": "USQX91500821"
2082            },
2083            "external_urls": {
2084                "spotify": "https://open.spotify.com/track/6ufaxWhOW87EXsKh5TSxMp"
2085            },
2086            "href": "https://api.spotify.com/v1/tracks/6ufaxWhOW87EXsKh5TSxMp",
2087            "id": "6ufaxWhOW87EXsKh5TSxMp",
2088            "is_local": false,
2089            "is_playable": true,
2090            "linked_from": {
2091                "external_urls": {
2092                    "spotify": "https://open.spotify.com/track/70nMUxP46mAcjW5iRpRiyN"
2093                },
2094                "href": "https://api.spotify.com/v1/tracks/70nMUxP46mAcjW5iRpRiyN",
2095                "id": "70nMUxP46mAcjW5iRpRiyN",
2096                "type": "track",
2097                "uri": "spotify:track:70nMUxP46mAcjW5iRpRiyN"
2098            },
2099            "name": "Romance for Cello and Piano",
2100            "popularity": 33,
2101            "preview_url": "https://p.scdn.co/mp3-preview/59053165aa006169f88b0888a1c2d8e420d5508a?cid=b800bf59070c4b52a8917d2230d25bdc",
2102            "track_number": 11,
2103            "type": "track",
2104            "uri": "spotify:track:6ufaxWhOW87EXsKh5TSxMp"
2105        },
2106        {
2107            "album": {
2108                "album_type": "SINGLE",
2109                "artists": [
2110                    {
2111                        "external_urls": {
2112                            "spotify": "https://open.spotify.com/artist/137W8MRPWKqSmrBGDBFSop"
2113                        },
2114                        "href": "https://api.spotify.com/v1/artists/137W8MRPWKqSmrBGDBFSop",
2115                        "id": "137W8MRPWKqSmrBGDBFSop",
2116                        "name": "Wiz Khalifa",
2117                        "type": "artist",
2118                        "uri": "spotify:artist:137W8MRPWKqSmrBGDBFSop"
2119                    }
2120                ],
2121                "external_urls": {
2122                    "spotify": "https://open.spotify.com/album/3qv4Hjk70y70MNe9Kb9X8f"
2123                },
2124                "href": "https://api.spotify.com/v1/albums/3qv4Hjk70y70MNe9Kb9X8f",
2125                "id": "3qv4Hjk70y70MNe9Kb9X8f",
2126                "images": [
2127                    {
2128                        "height": 640,
2129                        "url": "https://i.scdn.co/image/ab67616d0000b273dfe0748e91928eaf21373018",
2130                        "width": 640
2131                    },
2132                    {
2133                        "height": 300,
2134                        "url": "https://i.scdn.co/image/ab67616d00001e02dfe0748e91928eaf21373018",
2135                        "width": 300
2136                    },
2137                    {
2138                        "height": 64,
2139                        "url": "https://i.scdn.co/image/ab67616d00004851dfe0748e91928eaf21373018",
2140                        "width": 64
2141                    }
2142                ],
2143                "is_playable": true,
2144                "name": "Pull Up (feat. Lil Uzi Vert)",
2145                "release_date": "2016-05-25",
2146                "release_date_precision": "day",
2147                "total_tracks": 1,
2148                "type": "album",
2149                "uri": "spotify:album:3qv4Hjk70y70MNe9Kb9X8f"
2150            },
2151            "artists": [
2152                {
2153                    "external_urls": {
2154                        "spotify": "https://open.spotify.com/artist/137W8MRPWKqSmrBGDBFSop"
2155                    },
2156                    "href": "https://api.spotify.com/v1/artists/137W8MRPWKqSmrBGDBFSop",
2157                    "id": "137W8MRPWKqSmrBGDBFSop",
2158                    "name": "Wiz Khalifa",
2159                    "type": "artist",
2160                    "uri": "spotify:artist:137W8MRPWKqSmrBGDBFSop"
2161                },
2162                {
2163                    "external_urls": {
2164                        "spotify": "https://open.spotify.com/artist/4O15NlyKLIASxsJ0PrXPfz"
2165                    },
2166                    "href": "https://api.spotify.com/v1/artists/4O15NlyKLIASxsJ0PrXPfz",
2167                    "id": "4O15NlyKLIASxsJ0PrXPfz",
2168                    "name": "Lil Uzi Vert",
2169                    "type": "artist",
2170                    "uri": "spotify:artist:4O15NlyKLIASxsJ0PrXPfz"
2171                }
2172            ],
2173            "disc_number": 1,
2174            "duration_ms": 207391,
2175            "explicit": true,
2176            "external_ids": {
2177                "isrc": "USAT21601765"
2178            },
2179            "external_urls": {
2180                "spotify": "https://open.spotify.com/track/6LTsvaebP6V9tJFvZxqi5M"
2181            },
2182            "href": "https://api.spotify.com/v1/tracks/6LTsvaebP6V9tJFvZxqi5M",
2183            "id": "6LTsvaebP6V9tJFvZxqi5M",
2184            "is_local": false,
2185            "is_playable": true,
2186            "name": "Pull Up (feat. Lil Uzi Vert)",
2187            "popularity": 50,
2188            "preview_url": "https://p.scdn.co/mp3-preview/644de9f6fa47954ea3b44748b345a8f5f8d3fdd7?cid=b800bf59070c4b52a8917d2230d25bdc",
2189            "track_number": 1,
2190            "type": "track",
2191            "uri": "spotify:track:6LTsvaebP6V9tJFvZxqi5M"
2192        },
2193        {
2194            "album": {
2195                "album_type": "ALBUM",
2196                "artists": [
2197                    {
2198                        "external_urls": {
2199                            "spotify": "https://open.spotify.com/artist/2KsP6tYLJlTBvSUxnwlVWa"
2200                        },
2201                        "href": "https://api.spotify.com/v1/artists/2KsP6tYLJlTBvSUxnwlVWa",
2202                        "id": "2KsP6tYLJlTBvSUxnwlVWa",
2203                        "name": "Mike Posner",
2204                        "type": "artist",
2205                        "uri": "spotify:artist:2KsP6tYLJlTBvSUxnwlVWa"
2206                    }
2207                ],
2208                "external_urls": {
2209                    "spotify": "https://open.spotify.com/album/6Phl1V5P0sPrWJytXHGFeO"
2210                },
2211                "href": "https://api.spotify.com/v1/albums/6Phl1V5P0sPrWJytXHGFeO",
2212                "id": "6Phl1V5P0sPrWJytXHGFeO",
2213                "images": [
2214                    {
2215                        "height": 640,
2216                        "url": "https://i.scdn.co/image/ab67616d0000b2731db27fa11dbafa67857da8f3",
2217                        "width": 640
2218                    },
2219                    {
2220                        "height": 300,
2221                        "url": "https://i.scdn.co/image/ab67616d00001e021db27fa11dbafa67857da8f3",
2222                        "width": 300
2223                    },
2224                    {
2225                        "height": 64,
2226                        "url": "https://i.scdn.co/image/ab67616d000048511db27fa11dbafa67857da8f3",
2227                        "width": 64
2228                    }
2229                ],
2230                "is_playable": true,
2231                "name": "At Night, Alone.",
2232                "release_date": "2016-05-06",
2233                "release_date_precision": "day",
2234                "total_tracks": 18,
2235                "type": "album",
2236                "uri": "spotify:album:6Phl1V5P0sPrWJytXHGFeO"
2237            },
2238            "artists": [
2239                {
2240                    "external_urls": {
2241                        "spotify": "https://open.spotify.com/artist/2KsP6tYLJlTBvSUxnwlVWa"
2242                    },
2243                    "href": "https://api.spotify.com/v1/artists/2KsP6tYLJlTBvSUxnwlVWa",
2244                    "id": "2KsP6tYLJlTBvSUxnwlVWa",
2245                    "name": "Mike Posner",
2246                    "type": "artist",
2247                    "uri": "spotify:artist:2KsP6tYLJlTBvSUxnwlVWa"
2248                },
2249                {
2250                    "external_urls": {
2251                        "spotify": "https://open.spotify.com/artist/5iNrZmtVMtYev5M9yoWpEq"
2252                    },
2253                    "href": "https://api.spotify.com/v1/artists/5iNrZmtVMtYev5M9yoWpEq",
2254                    "id": "5iNrZmtVMtYev5M9yoWpEq",
2255                    "name": "Seeb",
2256                    "type": "artist",
2257                    "uri": "spotify:artist:5iNrZmtVMtYev5M9yoWpEq"
2258                }
2259            ],
2260            "disc_number": 1,
2261            "duration_ms": 197933,
2262            "explicit": true,
2263            "external_ids": {
2264                "isrc": "USUM71509342"
2265            },
2266            "external_urls": {
2267                "spotify": "https://open.spotify.com/track/0vbtURX4qv1l7besfwmnD8"
2268            },
2269            "href": "https://api.spotify.com/v1/tracks/0vbtURX4qv1l7besfwmnD8",
2270            "id": "0vbtURX4qv1l7besfwmnD8",
2271            "is_local": false,
2272            "is_playable": true,
2273            "name": "I Took A Pill In Ibiza - Seeb Remix",
2274            "popularity": 83,
2275            "preview_url": null,
2276            "track_number": 13,
2277            "type": "track",
2278            "uri": "spotify:track:0vbtURX4qv1l7besfwmnD8"
2279        },
2280        {
2281            "album": {
2282                "album_type": "COMPILATION",
2283                "artists": [
2284                    {
2285                        "external_urls": {
2286                            "spotify": "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of"
2287                        },
2288                        "href": "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of",
2289                        "id": "0LyfQWJT6nXafLPZqxe9Of",
2290                        "name": "Various Artists",
2291                        "type": "artist",
2292                        "uri": "spotify:artist:0LyfQWJT6nXafLPZqxe9Of"
2293                    }
2294                ],
2295                "external_urls": {
2296                    "spotify": "https://open.spotify.com/album/6lJrqUXdCpEINx1fi5EqMa"
2297                },
2298                "href": "https://api.spotify.com/v1/albums/6lJrqUXdCpEINx1fi5EqMa",
2299                "id": "6lJrqUXdCpEINx1fi5EqMa",
2300                "images": [
2301                    {
2302                        "height": 640,
2303                        "url": "https://i.scdn.co/image/ab67616d0000b27333d6ad1275ae8ebe156686f5",
2304                        "width": 640
2305                    },
2306                    {
2307                        "height": 300,
2308                        "url": "https://i.scdn.co/image/ab67616d00001e0233d6ad1275ae8ebe156686f5",
2309                        "width": 300
2310                    },
2311                    {
2312                        "height": 64,
2313                        "url": "https://i.scdn.co/image/ab67616d0000485133d6ad1275ae8ebe156686f5",
2314                        "width": 64
2315                    }
2316                ],
2317                "is_playable": true,
2318                "name": "The Twilight Saga: Breaking Dawn - Part 2 (Original Motion Picture Soundtrack)",
2319                "release_date": "2012-11-09",
2320                "release_date_precision": "day",
2321                "total_tracks": 14,
2322                "type": "album",
2323                "uri": "spotify:album:6lJrqUXdCpEINx1fi5EqMa"
2324            },
2325            "artists": [
2326                {
2327                    "external_urls": {
2328                        "spotify": "https://open.spotify.com/artist/0SbSDzM4X41hnlURed0fcV"
2329                    },
2330                    "href": "https://api.spotify.com/v1/artists/0SbSDzM4X41hnlURed0fcV",
2331                    "id": "0SbSDzM4X41hnlURed0fcV",
2332                    "name": "Carter Burwell",
2333                    "type": "artist",
2334                    "uri": "spotify:artist:0SbSDzM4X41hnlURed0fcV"
2335                }
2336            ],
2337            "disc_number": 1,
2338            "duration_ms": 255773,
2339            "explicit": false,
2340            "external_ids": {
2341                "isrc": "USAT21206056"
2342            },
2343            "external_urls": {
2344                "spotify": "https://open.spotify.com/track/1brH9m4Q2LHTuwxaKoMTn5"
2345            },
2346            "href": "https://api.spotify.com/v1/tracks/1brH9m4Q2LHTuwxaKoMTn5",
2347            "id": "1brH9m4Q2LHTuwxaKoMTn5",
2348            "is_local": false,
2349            "is_playable": true,
2350            "name": "Plus Que Ma Prope Vie",
2351            "popularity": 48,
2352            "preview_url": "https://p.scdn.co/mp3-preview/585cd6ea1265df63d349dcda19035a27893f50d2?cid=b800bf59070c4b52a8917d2230d25bdc",
2353            "track_number": 14,
2354            "type": "track",
2355            "uri": "spotify:track:1brH9m4Q2LHTuwxaKoMTn5"
2356        },
2357        {
2358            "album": {
2359                "album_type": "ALBUM",
2360                "artists": [
2361                    {
2362                        "external_urls": {
2363                            "spotify": "https://open.spotify.com/artist/03r4iKL2g2442PT9n2UKsx"
2364                        },
2365                        "href": "https://api.spotify.com/v1/artists/03r4iKL2g2442PT9n2UKsx",
2366                        "id": "03r4iKL2g2442PT9n2UKsx",
2367                        "name": "Beastie Boys",
2368                        "type": "artist",
2369                        "uri": "spotify:artist:03r4iKL2g2442PT9n2UKsx"
2370                    }
2371                ],
2372                "external_urls": {
2373                    "spotify": "https://open.spotify.com/album/11oR0ZuqB3ucZwb5TGbZxb"
2374                },
2375                "href": "https://api.spotify.com/v1/albums/11oR0ZuqB3ucZwb5TGbZxb",
2376                "id": "11oR0ZuqB3ucZwb5TGbZxb",
2377                "images": [
2378                    {
2379                        "height": 640,
2380                        "url": "https://i.scdn.co/image/ab67616d0000b273a7ea08ab3914c5fb2084a8ac",
2381                        "width": 640
2382                    },
2383                    {
2384                        "height": 300,
2385                        "url": "https://i.scdn.co/image/ab67616d00001e02a7ea08ab3914c5fb2084a8ac",
2386                        "width": 300
2387                    },
2388                    {
2389                        "height": 64,
2390                        "url": "https://i.scdn.co/image/ab67616d00004851a7ea08ab3914c5fb2084a8ac",
2391                        "width": 64
2392                    }
2393                ],
2394                "is_playable": true,
2395                "name": "Licensed To Ill",
2396                "release_date": "1986-11-15",
2397                "release_date_precision": "day",
2398                "total_tracks": 13,
2399                "type": "album",
2400                "uri": "spotify:album:11oR0ZuqB3ucZwb5TGbZxb"
2401            },
2402            "artists": [
2403                {
2404                    "external_urls": {
2405                        "spotify": "https://open.spotify.com/artist/03r4iKL2g2442PT9n2UKsx"
2406                    },
2407                    "href": "https://api.spotify.com/v1/artists/03r4iKL2g2442PT9n2UKsx",
2408                    "id": "03r4iKL2g2442PT9n2UKsx",
2409                    "name": "Beastie Boys",
2410                    "type": "artist",
2411                    "uri": "spotify:artist:03r4iKL2g2442PT9n2UKsx"
2412                }
2413            ],
2414            "disc_number": 1,
2415            "duration_ms": 157440,
2416            "explicit": false,
2417            "external_ids": {
2418                "isrc": "USDJ28600011"
2419            },
2420            "external_urls": {
2421                "spotify": "https://open.spotify.com/track/2tY1gxCKslfXLFpFofYmJQ"
2422            },
2423            "href": "https://api.spotify.com/v1/tracks/2tY1gxCKslfXLFpFofYmJQ",
2424            "id": "2tY1gxCKslfXLFpFofYmJQ",
2425            "is_local": false,
2426            "is_playable": true,
2427            "name": "Brass Monkey",
2428            "popularity": 68,
2429            "preview_url": null,
2430            "track_number": 11,
2431            "type": "track",
2432            "uri": "spotify:track:2tY1gxCKslfXLFpFofYmJQ"
2433        },
2434        {
2435            "album": {
2436                "album_type": "ALBUM",
2437                "artists": [
2438                    {
2439                        "external_urls": {
2440                            "spotify": "https://open.spotify.com/artist/5Q81rlcTFh3k6DQJXPdsot"
2441                        },
2442                        "href": "https://api.spotify.com/v1/artists/5Q81rlcTFh3k6DQJXPdsot",
2443                        "id": "5Q81rlcTFh3k6DQJXPdsot",
2444                        "name": "Mura Masa",
2445                        "type": "artist",
2446                        "uri": "spotify:artist:5Q81rlcTFh3k6DQJXPdsot"
2447                    }
2448                ],
2449                "external_urls": {
2450                    "spotify": "https://open.spotify.com/album/0NBTBo1qrg554sAj79nEqD"
2451                },
2452                "href": "https://api.spotify.com/v1/albums/0NBTBo1qrg554sAj79nEqD",
2453                "id": "0NBTBo1qrg554sAj79nEqD",
2454                "images": [
2455                    {
2456                        "height": 640,
2457                        "url": "https://i.scdn.co/image/ab67616d0000b2736818aa231aa543cf87e1374a",
2458                        "width": 640
2459                    },
2460                    {
2461                        "height": 300,
2462                        "url": "https://i.scdn.co/image/ab67616d00001e026818aa231aa543cf87e1374a",
2463                        "width": 300
2464                    },
2465                    {
2466                        "height": 64,
2467                        "url": "https://i.scdn.co/image/ab67616d000048516818aa231aa543cf87e1374a",
2468                        "width": 64
2469                    }
2470                ],
2471                "is_playable": true,
2472                "name": "Mura Masa",
2473                "release_date": "2017-07-14",
2474                "release_date_precision": "day",
2475                "total_tracks": 13,
2476                "type": "album",
2477                "uri": "spotify:album:0NBTBo1qrg554sAj79nEqD"
2478            },
2479            "artists": [
2480                {
2481                    "external_urls": {
2482                        "spotify": "https://open.spotify.com/artist/5Q81rlcTFh3k6DQJXPdsot"
2483                    },
2484                    "href": "https://api.spotify.com/v1/artists/5Q81rlcTFh3k6DQJXPdsot",
2485                    "id": "5Q81rlcTFh3k6DQJXPdsot",
2486                    "name": "Mura Masa",
2487                    "type": "artist",
2488                    "uri": "spotify:artist:5Q81rlcTFh3k6DQJXPdsot"
2489                },
2490                {
2491                    "external_urls": {
2492                        "spotify": "https://open.spotify.com/artist/7pFeBzX627ff0VnN6bxPR4"
2493                    },
2494                    "href": "https://api.spotify.com/v1/artists/7pFeBzX627ff0VnN6bxPR4",
2495                    "id": "7pFeBzX627ff0VnN6bxPR4",
2496                    "name": "Desiigner",
2497                    "type": "artist",
2498                    "uri": "spotify:artist:7pFeBzX627ff0VnN6bxPR4"
2499                }
2500            ],
2501            "disc_number": 1,
2502            "duration_ms": 164013,
2503            "explicit": true,
2504            "external_ids": {
2505                "isrc": "GBUM71701364"
2506            },
2507            "external_urls": {
2508                "spotify": "https://open.spotify.com/track/4x8874idDYp8yxgKsyb4xG"
2509            },
2510            "href": "https://api.spotify.com/v1/tracks/4x8874idDYp8yxgKsyb4xG",
2511            "id": "4x8874idDYp8yxgKsyb4xG",
2512            "is_local": false,
2513            "is_playable": true,
2514            "name": "All Around The World (feat. Desiigner)",
2515            "popularity": 42,
2516            "preview_url": null,
2517            "track_number": 5,
2518            "type": "track",
2519            "uri": "spotify:track:4x8874idDYp8yxgKsyb4xG"
2520        },
2521        {
2522            "album": {
2523                "album_type": "SINGLE",
2524                "artists": [
2525                    {
2526                        "external_urls": {
2527                            "spotify": "https://open.spotify.com/artist/61lyPtntblHJvA7FMMhi7E"
2528                        },
2529                        "href": "https://api.spotify.com/v1/artists/61lyPtntblHJvA7FMMhi7E",
2530                        "id": "61lyPtntblHJvA7FMMhi7E",
2531                        "name": "Duke Dumont",
2532                        "type": "artist",
2533                        "uri": "spotify:artist:61lyPtntblHJvA7FMMhi7E"
2534                    }
2535                ],
2536                "external_urls": {
2537                    "spotify": "https://open.spotify.com/album/4SQqe6ACemVTNNOcq7Ql4A"
2538                },
2539                "href": "https://api.spotify.com/v1/albums/4SQqe6ACemVTNNOcq7Ql4A",
2540                "id": "4SQqe6ACemVTNNOcq7Ql4A",
2541                "images": [
2542                    {
2543                        "height": 640,
2544                        "url": "https://i.scdn.co/image/ab67616d0000b273be165dd0973a0db9607b3938",
2545                        "width": 640
2546                    },
2547                    {
2548                        "height": 300,
2549                        "url": "https://i.scdn.co/image/ab67616d00001e02be165dd0973a0db9607b3938",
2550                        "width": 300
2551                    },
2552                    {
2553                        "height": 64,
2554                        "url": "https://i.scdn.co/image/ab67616d00004851be165dd0973a0db9607b3938",
2555                        "width": 64
2556                    }
2557                ],
2558                "is_playable": true,
2559                "name": "The Giver (Reprise)",
2560                "release_date": "2015-03-17",
2561                "release_date_precision": "day",
2562                "total_tracks": 1,
2563                "type": "album",
2564                "uri": "spotify:album:4SQqe6ACemVTNNOcq7Ql4A"
2565            },
2566            "artists": [
2567                {
2568                    "external_urls": {
2569                        "spotify": "https://open.spotify.com/artist/61lyPtntblHJvA7FMMhi7E"
2570                    },
2571                    "href": "https://api.spotify.com/v1/artists/61lyPtntblHJvA7FMMhi7E",
2572                    "id": "61lyPtntblHJvA7FMMhi7E",
2573                    "name": "Duke Dumont",
2574                    "type": "artist",
2575                    "uri": "spotify:artist:61lyPtntblHJvA7FMMhi7E"
2576                }
2577            ],
2578            "disc_number": 1,
2579            "duration_ms": 195756,
2580            "explicit": false,
2581            "external_ids": {
2582                "isrc": "GBUM71501517"
2583            },
2584            "external_urls": {
2585                "spotify": "https://open.spotify.com/track/0ccSl4LZ7dksMNmJgkN7NO"
2586            },
2587            "href": "https://api.spotify.com/v1/tracks/0ccSl4LZ7dksMNmJgkN7NO",
2588            "id": "0ccSl4LZ7dksMNmJgkN7NO",
2589            "is_local": false,
2590            "is_playable": true,
2591            "name": "The Giver (Reprise)",
2592            "popularity": 43,
2593            "preview_url": null,
2594            "track_number": 1,
2595            "type": "track",
2596            "uri": "spotify:track:0ccSl4LZ7dksMNmJgkN7NO"
2597        },
2598        {
2599            "album": {
2600                "album_type": "ALBUM",
2601                "artists": [
2602                    {
2603                        "external_urls": {
2604                            "spotify": "https://open.spotify.com/artist/4NHQUGzhtTLFvgF5SZesLK"
2605                        },
2606                        "href": "https://api.spotify.com/v1/artists/4NHQUGzhtTLFvgF5SZesLK",
2607                        "id": "4NHQUGzhtTLFvgF5SZesLK",
2608                        "name": "Tove Lo",
2609                        "type": "artist",
2610                        "uri": "spotify:artist:4NHQUGzhtTLFvgF5SZesLK"
2611                    }
2612                ],
2613                "external_urls": {
2614                    "spotify": "https://open.spotify.com/album/1tuekzsMZQOuiMejKP6t2Y"
2615                },
2616                "href": "https://api.spotify.com/v1/albums/1tuekzsMZQOuiMejKP6t2Y",
2617                "id": "1tuekzsMZQOuiMejKP6t2Y",
2618                "images": [
2619                    {
2620                        "height": 640,
2621                        "url": "https://i.scdn.co/image/ab67616d0000b2739f0c014998bac13d3181474c",
2622                        "width": 640
2623                    },
2624                    {
2625                        "height": 300,
2626                        "url": "https://i.scdn.co/image/ab67616d00001e029f0c014998bac13d3181474c",
2627                        "width": 300
2628                    },
2629                    {
2630                        "height": 64,
2631                        "url": "https://i.scdn.co/image/ab67616d000048519f0c014998bac13d3181474c",
2632                        "width": 64
2633                    }
2634                ],
2635                "is_playable": true,
2636                "name": "Lady Wood",
2637                "release_date": "2016-10-28",
2638                "release_date_precision": "day",
2639                "total_tracks": 12,
2640                "type": "album",
2641                "uri": "spotify:album:1tuekzsMZQOuiMejKP6t2Y"
2642            },
2643            "artists": [
2644                {
2645                    "external_urls": {
2646                        "spotify": "https://open.spotify.com/artist/4NHQUGzhtTLFvgF5SZesLK"
2647                    },
2648                    "href": "https://api.spotify.com/v1/artists/4NHQUGzhtTLFvgF5SZesLK",
2649                    "id": "4NHQUGzhtTLFvgF5SZesLK",
2650                    "name": "Tove Lo",
2651                    "type": "artist",
2652                    "uri": "spotify:artist:4NHQUGzhtTLFvgF5SZesLK"
2653                }
2654            ],
2655            "disc_number": 1,
2656            "duration_ms": 234474,
2657            "explicit": true,
2658            "external_ids": {
2659                "isrc": "SEUM71601201"
2660            },
2661            "external_urls": {
2662                "spotify": "https://open.spotify.com/track/073A1FsNWqMxmdcRMeU57t"
2663            },
2664            "href": "https://api.spotify.com/v1/tracks/073A1FsNWqMxmdcRMeU57t",
2665            "id": "073A1FsNWqMxmdcRMeU57t",
2666            "is_local": false,
2667            "is_playable": true,
2668            "name": "Don’t Talk About It",
2669            "popularity": 39,
2670            "preview_url": null,
2671            "track_number": 8,
2672            "type": "track",
2673            "uri": "spotify:track:073A1FsNWqMxmdcRMeU57t"
2674        },
2675        {
2676            "album": {
2677                "album_type": "SINGLE",
2678                "artists": [
2679                    {
2680                        "external_urls": {
2681                            "spotify": "https://open.spotify.com/artist/6y02TEMv71ArWB2qhIaQ5m"
2682                        },
2683                        "href": "https://api.spotify.com/v1/artists/6y02TEMv71ArWB2qhIaQ5m",
2684                        "id": "6y02TEMv71ArWB2qhIaQ5m",
2685                        "name": "Kaiydo",
2686                        "type": "artist",
2687                        "uri": "spotify:artist:6y02TEMv71ArWB2qhIaQ5m"
2688                    }
2689                ],
2690                "external_urls": {
2691                    "spotify": "https://open.spotify.com/album/0oeJCHQwiz5dQhMuiFlhhM"
2692                },
2693                "href": "https://api.spotify.com/v1/albums/0oeJCHQwiz5dQhMuiFlhhM",
2694                "id": "0oeJCHQwiz5dQhMuiFlhhM",
2695                "images": [
2696                    {
2697                        "height": 640,
2698                        "url": "https://i.scdn.co/image/ab67616d0000b2731927f0378a81361fb80e20d6",
2699                        "width": 640
2700                    },
2701                    {
2702                        "height": 300,
2703                        "url": "https://i.scdn.co/image/ab67616d00001e021927f0378a81361fb80e20d6",
2704                        "width": 300
2705                    },
2706                    {
2707                        "height": 64,
2708                        "url": "https://i.scdn.co/image/ab67616d000048511927f0378a81361fb80e20d6",
2709                        "width": 64
2710                    }
2711                ],
2712                "is_playable": true,
2713                "name": "Fruit Punch",
2714                "release_date": "2016-08-12",
2715                "release_date_precision": "day",
2716                "total_tracks": 1,
2717                "type": "album",
2718                "uri": "spotify:album:0oeJCHQwiz5dQhMuiFlhhM"
2719            },
2720            "artists": [
2721                {
2722                    "external_urls": {
2723                        "spotify": "https://open.spotify.com/artist/6y02TEMv71ArWB2qhIaQ5m"
2724                    },
2725                    "href": "https://api.spotify.com/v1/artists/6y02TEMv71ArWB2qhIaQ5m",
2726                    "id": "6y02TEMv71ArWB2qhIaQ5m",
2727                    "name": "Kaiydo",
2728                    "type": "artist",
2729                    "uri": "spotify:artist:6y02TEMv71ArWB2qhIaQ5m"
2730                }
2731            ],
2732            "disc_number": 1,
2733            "duration_ms": 221622,
2734            "explicit": true,
2735            "external_ids": {
2736                "isrc": "TCACR1606159"
2737            },
2738            "external_urls": {
2739                "spotify": "https://open.spotify.com/track/0lpRp9KzzMbC0w1uiL7H7f"
2740            },
2741            "href": "https://api.spotify.com/v1/tracks/0lpRp9KzzMbC0w1uiL7H7f",
2742            "id": "0lpRp9KzzMbC0w1uiL7H7f",
2743            "is_local": false,
2744            "is_playable": true,
2745            "name": "Fruit Punch",
2746            "popularity": 48,
2747            "preview_url": "https://p.scdn.co/mp3-preview/62b43baeb1993236dfc7e78557996514f64a3d9f?cid=b800bf59070c4b52a8917d2230d25bdc",
2748            "track_number": 1,
2749            "type": "track",
2750            "uri": "spotify:track:0lpRp9KzzMbC0w1uiL7H7f"
2751        },
2752        {
2753            "album": {
2754                "album_type": "SINGLE",
2755                "artists": [
2756                    {
2757                        "external_urls": {
2758                            "spotify": "https://open.spotify.com/artist/21dooacK2WGBB5amYvKyfM"
2759                        },
2760                        "href": "https://api.spotify.com/v1/artists/21dooacK2WGBB5amYvKyfM",
2761                        "id": "21dooacK2WGBB5amYvKyfM",
2762                        "name": "Smokepurpp",
2763                        "type": "artist",
2764                        "uri": "spotify:artist:21dooacK2WGBB5amYvKyfM"
2765                    }
2766                ],
2767                "external_urls": {
2768                    "spotify": "https://open.spotify.com/album/2TeGNWZYaj9yeM0mjiO8zL"
2769                },
2770                "href": "https://api.spotify.com/v1/albums/2TeGNWZYaj9yeM0mjiO8zL",
2771                "id": "2TeGNWZYaj9yeM0mjiO8zL",
2772                "images": [
2773                    {
2774                        "height": 640,
2775                        "url": "https://i.scdn.co/image/ab67616d0000b273069c2ee3bae4205c1fed2981",
2776                        "width": 640
2777                    },
2778                    {
2779                        "height": 300,
2780                        "url": "https://i.scdn.co/image/ab67616d00001e02069c2ee3bae4205c1fed2981",
2781                        "width": 300
2782                    },
2783                    {
2784                        "height": 64,
2785                        "url": "https://i.scdn.co/image/ab67616d00004851069c2ee3bae4205c1fed2981",
2786                        "width": 64
2787                    }
2788                ],
2789                "is_playable": true,
2790                "name": "Nephew (feat. Lil Pump)",
2791                "release_date": "2018-07-27",
2792                "release_date_precision": "day",
2793                "total_tracks": 1,
2794                "type": "album",
2795                "uri": "spotify:album:2TeGNWZYaj9yeM0mjiO8zL"
2796            },
2797            "artists": [
2798                {
2799                    "external_urls": {
2800                        "spotify": "https://open.spotify.com/artist/21dooacK2WGBB5amYvKyfM"
2801                    },
2802                    "href": "https://api.spotify.com/v1/artists/21dooacK2WGBB5amYvKyfM",
2803                    "id": "21dooacK2WGBB5amYvKyfM",
2804                    "name": "Smokepurpp",
2805                    "type": "artist",
2806                    "uri": "spotify:artist:21dooacK2WGBB5amYvKyfM"
2807                },
2808                {
2809                    "external_urls": {
2810                        "spotify": "https://open.spotify.com/artist/3wyVrVrFCkukjdVIdirGVY"
2811                    },
2812                    "href": "https://api.spotify.com/v1/artists/3wyVrVrFCkukjdVIdirGVY",
2813                    "id": "3wyVrVrFCkukjdVIdirGVY",
2814                    "name": "Lil Pump",
2815                    "type": "artist",
2816                    "uri": "spotify:artist:3wyVrVrFCkukjdVIdirGVY"
2817                }
2818            ],
2819            "disc_number": 1,
2820            "duration_ms": 202962,
2821            "explicit": true,
2822            "external_ids": {
2823                "isrc": "USUM71810095"
2824            },
2825            "external_urls": {
2826                "spotify": "https://open.spotify.com/track/67KvputYgCRghvDQYj5FMq"
2827            },
2828            "href": "https://api.spotify.com/v1/tracks/67KvputYgCRghvDQYj5FMq",
2829            "id": "67KvputYgCRghvDQYj5FMq",
2830            "is_local": false,
2831            "is_playable": true,
2832            "linked_from": {
2833                "external_urls": {
2834                    "spotify": "https://open.spotify.com/track/0ibOcbkp2XG46Do8jcy0bL"
2835                },
2836                "href": "https://api.spotify.com/v1/tracks/0ibOcbkp2XG46Do8jcy0bL",
2837                "id": "0ibOcbkp2XG46Do8jcy0bL",
2838                "type": "track",
2839                "uri": "spotify:track:0ibOcbkp2XG46Do8jcy0bL"
2840            },
2841            "name": "Nephew (feat. Lil Pump)",
2842            "popularity": 50,
2843            "preview_url": "https://p.scdn.co/mp3-preview/bc901043dd4bcb1c43f6e7b1642e2d9d93b9539a?cid=b800bf59070c4b52a8917d2230d25bdc",
2844            "track_number": 1,
2845            "type": "track",
2846            "uri": "spotify:track:67KvputYgCRghvDQYj5FMq"
2847        },
2848        {
2849            "album": {
2850                "album_type": "ALBUM",
2851                "artists": [
2852                    {
2853                        "external_urls": {
2854                            "spotify": "https://open.spotify.com/artist/5xtqw2B8z8JGfDYi2eAZHI"
2855                        },
2856                        "href": "https://api.spotify.com/v1/artists/5xtqw2B8z8JGfDYi2eAZHI",
2857                        "id": "5xtqw2B8z8JGfDYi2eAZHI",
2858                        "name": "Sonique",
2859                        "type": "artist",
2860                        "uri": "spotify:artist:5xtqw2B8z8JGfDYi2eAZHI"
2861                    }
2862                ],
2863                "external_urls": {
2864                    "spotify": "https://open.spotify.com/album/4LX27S3cszKEJW84BGa1Ff"
2865                },
2866                "href": "https://api.spotify.com/v1/albums/4LX27S3cszKEJW84BGa1Ff",
2867                "id": "4LX27S3cszKEJW84BGa1Ff",
2868                "images": [
2869                    {
2870                        "height": 640,
2871                        "url": "https://i.scdn.co/image/ab67616d0000b2732b30281b18d808c60135837c",
2872                        "width": 640
2873                    },
2874                    {
2875                        "height": 300,
2876                        "url": "https://i.scdn.co/image/ab67616d00001e022b30281b18d808c60135837c",
2877                        "width": 300
2878                    },
2879                    {
2880                        "height": 64,
2881                        "url": "https://i.scdn.co/image/ab67616d000048512b30281b18d808c60135837c",
2882                        "width": 64
2883                    }
2884                ],
2885                "is_playable": true,
2886                "name": "Hear My Cry",
2887                "release_date": "2000-08-24",
2888                "release_date_precision": "day",
2889                "total_tracks": 13,
2890                "type": "album",
2891                "uri": "spotify:album:4LX27S3cszKEJW84BGa1Ff"
2892            },
2893            "artists": [
2894                {
2895                    "external_urls": {
2896                        "spotify": "https://open.spotify.com/artist/5xtqw2B8z8JGfDYi2eAZHI"
2897                    },
2898                    "href": "https://api.spotify.com/v1/artists/5xtqw2B8z8JGfDYi2eAZHI",
2899                    "id": "5xtqw2B8z8JGfDYi2eAZHI",
2900                    "name": "Sonique",
2901                    "type": "artist",
2902                    "uri": "spotify:artist:5xtqw2B8z8JGfDYi2eAZHI"
2903                }
2904            ],
2905            "disc_number": 1,
2906            "duration_ms": 240866,
2907            "explicit": false,
2908            "external_ids": {
2909                "isrc": "USUR10300602"
2910            },
2911            "external_urls": {
2912                "spotify": "https://open.spotify.com/track/4Y8q64VnhD0vFYy9g2WFpi"
2913            },
2914            "href": "https://api.spotify.com/v1/tracks/4Y8q64VnhD0vFYy9g2WFpi",
2915            "id": "4Y8q64VnhD0vFYy9g2WFpi",
2916            "is_local": false,
2917            "is_playable": true,
2918            "name": "It Feels So Good",
2919            "popularity": 67,
2920            "preview_url": "https://p.scdn.co/mp3-preview/028068f83d3d988b1661c03e93ab0651f6dd5957?cid=b800bf59070c4b52a8917d2230d25bdc",
2921            "track_number": 1,
2922            "type": "track",
2923            "uri": "spotify:track:4Y8q64VnhD0vFYy9g2WFpi"
2924        }
2925    ],
2926    "seeds": [
2927        {
2928            "initialPoolSize": 378,
2929            "afterFilteringSize": 378,
2930            "afterRelinkingSize": 378,
2931            "id": "4NHQUGzhtTLFvgF5SZesLK",
2932            "type": "ARTIST",
2933            "href": "https://api.spotify.com/v1/artists/4NHQUGzhtTLFvgF5SZesLK"
2934        },
2935        {
2936            "initialPoolSize": 400,
2937            "afterFilteringSize": 400,
2938            "afterRelinkingSize": 400,
2939            "id": "0c6xIDDpzE81m2q797ordA",
2940            "type": "TRACK",
2941            "href": "https://api.spotify.com/v1/tracks/0c6xIDDpzE81m2q797ordA"
2942        },
2943        {
2944            "initialPoolSize": 404,
2945            "afterFilteringSize": 404,
2946            "afterRelinkingSize": 404,
2947            "id": "classical",
2948            "type": "GENRE",
2949            "href": null
2950        },
2951        {
2952            "initialPoolSize": 369,
2953            "afterFilteringSize": 369,
2954            "afterRelinkingSize": 369,
2955            "id": "hip-hop",
2956            "type": "GENRE",
2957            "href": null
2958        }
2959    ]
2960}
2961"""
def get_genres(debug = True):
46def get_genres(debug = True):
47    """
48    Asks Spotify for a list of available genres. There are actually 6000+ valid
49    genres on Spotify [all of which can be found here](https://everynoise.com/everynoise1d.html)
50    but for our purposes it might be wise to limit yourself to just these.
51
52    Args:
53        debug (`bool`): whether or not you want the debug messages to be printed.
54
55    Returns:
56        a `list` of `str` representing valid genres.
57    """
58    return [
59        "alternative", "ambient", "blues",
60        "chill", "country", "dance", "electronic", "folk",
61        "funk", "happy", "hip-hop", "indie-pop", "jazz", "k-pop", "metal",
62        "new-release", "pop", "punk", "reggae", "rock",
63        "soul", "study", "trance", "work-out", "world-music"
64    ]

Asks Spotify for a list of available genres. There are actually 6000+ valid genres on Spotify all of which can be found here but for our purposes it might be wise to limit yourself to just these.

Arguments:
  • debug (bool): whether or not you want the debug messages to be printed.
Returns:

a list of str representing valid genres.

def search_for_artists(search_term, debug = True, simplify = True):
157def search_for_artists(search_term , debug = True, simplify  = True):
158    """
159    Retrieves a list of Spotify artists, given the search term passed in.
160
161    Args:
162        search_term (`str`): A search term (for an artist), represented as a string.
163        debug (`bool`): Whether or not you want debug text to be printed.
164        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
165
166    Returns:
167        a `list` of artists.
168    """
169    url = "https://api.spotify.com/v1/search?q=" + search_term + "&type=artist&market=US"
170    data = _issue_get_request(url, debug=debug)
171    if not simplify
172        return data
173    return _simplify_artists(data["artists"]["items"], debug=debug)

Retrieves a list of Spotify artists, given the search term passed in.

Arguments:
  • search_term (str): A search term (for an artist), represented as a string.
  • debug (bool): Whether or not you want debug text to be printed.
  • simplify (bool): Indicates whether you want to simplify the data that is returned.
Returns:

a list of artists.

def search_for_tracks(search_term, debug = True, simplify = True):
67def search_for_tracks(search_term , debug = True, simplify  = True):
68    """
69    Retrieves a list of Spotify tracks, given the search term passed in.
70
71    Args:
72        search_term (`str`): A search term (for a song), represented as a string.
73        debug (`bool`): Whether or not you want debug text to be printed.
74        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
75
76    Returns:
77        a `list` of tracks.
78    """
79    url = "https://api.spotify.com/v1/search?q=" + search_term + "&type=track"
80    data = _issue_get_request(url, debug=debug)
81    if not simplify
82        return data
83    return _simplify_tracks(data["tracks"]["items"], debug=debug)

Retrieves a list of Spotify tracks, given the search term passed in.

Arguments:
  • search_term (str): A search term (for a song), represented as a string.
  • debug (bool): Whether or not you want debug text to be printed.
  • simplify (bool): Indicates whether you want to simplify the data that is returned.
Returns:

a list of tracks.

def search_for_playlists(search_term, debug = True, simplify = True):
195def search_for_playlists(search_term , debug = True, simplify  = True):
196    """
197    Retrieves a list of Spotify playlists, given the search term passed in.
198
199    Args:
200        search_term (`str`): A search term (for a song), represented as a string.
201        debug (`bool`): Whether or not you want debug text to be printed.
202        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
203
204    Returns:
205        a `list` of playlists.
206    """
207    url = "https://api.spotify.com/v1/search?q=" + search_term + "&type=playlist"
208    data = _issue_get_request(url, debug=debug)
209    if not simplify
210        return data
211    return _simplify_playlists(data["playlists"]["items"], debug=debug)

Retrieves a list of Spotify playlists, given the search term passed in.

Arguments:
  • search_term (str): A search term (for a song), represented as a string.
  • debug (bool): Whether or not you want debug text to be printed.
  • simplify (bool): Indicates whether you want to simplify the data that is returned.
Returns:

a list of playlists.

def search_for_albums(search_term, debug = True, simplify = True):
176def search_for_albums(search_term , debug = True, simplify  = True):
177    """
178    Retrieves a list of Spotify albums, given the search term passed in.
179
180    Args:
181        search_term (`str`): A search term (for an album), represented as a string.
182        debug (`bool`): Whether or not you want debug text to be printed.
183        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
184
185    Returns:
186        * a `list` of albums.
187    """
188    url = "https://api.spotify.com/v1/search?q=" + search_term + "&type=album&market=US"
189    data = _issue_get_request(url, debug=debug)
190    if not simplify
191        return data
192    return _simplify_albums(data["albums"]["items"], debug=debug)

Retrieves a list of Spotify albums, given the search term passed in.

Arguments:
  • search_term (str): A search term (for an album), represented as a string.
  • debug (bool): Whether or not you want debug text to be printed.
  • simplify (bool): Indicates whether you want to simplify the data that is returned.
Returns:
  • a list of albums.
def get_top_tracks_by_artist(artist_id, debug = True, simplify = True):
104def get_top_tracks_by_artist(artist_id , debug = True, simplify  = True):
105    """
106    Retrieves a list of Spotify "top tracks" by an artist
107
108    Args:a
109        artist_id (`str`): The Spotify id of the artist.
110        debug (`bool`): Whether or not you want debug text to be printed.
111        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
112
113    Returns:
114        a `list` of tracks.
115    """
116    if len(artist_id) != 22
117        raise TypeError(f"This function expects an Artist ID but you gave it {artist_id}.")
118    
119    url = "https://api.spotify.com/v1/artists/" + \
120        artist_id + "/top-tracks?market=US"
121    data = _issue_get_request(url, debug=debug)
122    if not simplify
123        return data
124    return _simplify_tracks(data["tracks"], debug=debug)

Retrieves a list of Spotify "top tracks" by an artist

Args:a artist_id (str): The Spotify id of the artist. debug (bool): Whether or not you want debug text to be printed. simplify (bool): Indicates whether you want to simplify the data that is returned.

Returns:

a list of tracks.

def get_playlist_tracks(playlist_id, debug = True, simplify = True):
134def get_playlist_tracks(playlist_id , debug = True, simplify  = True):
135    """
136    Retrieves a list of the tracks associated with a playlist_id.
137
138    Args:
139        playlist_id (`str`): The id of the Spotify playlist.
140        debug (`bool`): Whether or not you want debug text to be printed.
141        simplify (`bool`):  Whether you want to simplify the data that is returned.
142
143    Returns:
144        a `list` of tracks.
145    """
146    url = "https://api.spotify.com/v1/playlists/" + playlist_id + "/tracks"
147    data = _issue_get_request(url, debug=debug)
148    if not simplify
149        return data
150
151    def get_track(item):
152        return item["track"]
153    tracks = (map(get_track, data["items"]))
154    return _simplify_tracks(tracks, debug=debug)

Retrieves a list of the tracks associated with a playlist_id.

Arguments:
  • playlist_id (str): The id of the Spotify playlist.
  • debug (bool): Whether or not you want debug text to be printed.
  • simplify (bool): Whether you want to simplify the data that is returned.
Returns:

a list of tracks.

def get_playlists_by_user(user_id, debug = True, simplify = True):
233def get_playlists_by_user(user_id , debug = True, simplify  = True):
234    """
235    Retrieves a list of Spotify playlists belonging to a particular user.
236
237    Args:
238        user_id (`str`): A valid Spotify user id, represented as a string.
239        debug (`bool`): Whether or not you want debug text to be printed.
240        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
241
242    Returns:
243        a `list` of playlists belonging to the user.
244    """
245    url = "https://api.spotify.com/v1/users/" + user_id + "/playlists"
246    data = _issue_get_request(url, debug=debug)
247    if not simplify
248        return data
249    return _simplify_playlists(data["items"], debug=debug)

Retrieves a list of Spotify playlists belonging to a particular user.

Arguments:
  • user_id (str): A valid Spotify user id, represented as a string.
  • debug (bool): Whether or not you want debug text to be printed.
  • simplify (bool): Indicates whether you want to simplify the data that is returned.
Returns:

a list of playlists belonging to the user.

def get_albums_by_artist( artist_id , options = [], debug = True, simplify = True):
252def get_albums_by_artist(artist_id, options = [], debug = True, simplify = True):
253    """
254    Retrieves a list of Spotify albums by a given artist.
255
256    Args:
257        artist_id (`str`): A valid Spotify artist ID
258        options (`list`): A list of special strings to indicate what sort of albums to look for. Valid
259                          items are: `"album"`, `"single"`, "`compilation`", and `"appears_on"`.
260        debug (`bool`): Whether or not you want debug text to be printed.
261        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
262
263    Returns:
264        * a `list` of albums.
265    """
266    
267    _verify_artist_ids([artist_id])
268    
269    valid_options = ["album", "single", "compilation", "appears_on"]
270    for option in options
271        if option not in valid_options
272            raise TypeError(f"The options input only accepts the following options: {valid_options}")
273    
274    if options
275        url = f"https://api.spotify.com/v1/artists/{artist_id}/albums?include_groups={",".join(options)}&market=US"
276    else
277        url = f"https://api.spotify.com/v1/artists/{artist_id}/albums?market=US"
278    data = _issue_get_request(url, debug=debug)
279    if not simplify
280        return data
281    return _simplify_albums(data["items"], debug=debug)

Retrieves a list of Spotify albums by a given artist.

Arguments:
  • artist_id (str): A valid Spotify artist ID
  • options (list): A list of special strings to indicate what sort of albums to look for. Valid items are: "album", "single", "compilation", and "appears_on".
  • debug (bool): Whether or not you want debug text to be printed.
  • simplify (bool): Indicates whether you want to simplify the data that is returned.
Returns:
  • a list of albums.
def get_new_releases(debug = True, simplify = True):
214def get_new_releases(debug = True, simplify = True):
215    """
216    Retrieves a list of Spotify albums that are newly released.
217
218    Args:
219        debug (`bool`): Whether or not you want debug text to be printed.
220        simplify (`bool`): Indicates whether you want to simplify the data that is returned.
221
222    Returns:
223        * a `list` of albums.
224    """
225    
226    url = f"https://api.spotify.com/v1/search?q=tag:new&type=album&market=US&offset=0"
227    data = _issue_get_request(url, debug=debug)
228    if not simplify
229        return data
230    return _simplify_albums(data["albums"]["items"], debug=debug)

Retrieves a list of Spotify albums that are newly released.

Arguments:
  • debug (bool): Whether or not you want debug text to be printed.
  • simplify (bool): Indicates whether you want to simplify the data that is returned.
Returns:
  • a list of albums.
def generate_tracks_table(tracks, to_html = False):
651def generate_tracks_table(tracks , to_html  = False):
652    """
653    Function that builds a string representation of a list tracks (dictionaries).
654
655    Args:
656        tracks (`list`): List of tracks.
657        to_html (`bool`): If `True` it will generate an HTML version (for an email or web page) and if `False` (default) will generate a string to print in Python.
658
659    Returns:
660        * a `str` that has a table in it for tracks
661    """
662
663    if to_html
664        return _get_tracklist_table_html(tracks)
665
666    line_width = 95
667    text = ""
668    template = "{0:2} | {1:<22.22} | {2:<30.30} | {3:<30.30}\n"
669
670    # header section:
671    text += "-" * line_width + "\n"
672    text += template.format(
673        "", "Name", "Artist", "Album"
674    )
675    text += "-" * line_width + "\n"
676
677    # data section:
678    counter = 1
679    for track in tracks
680        text += template.format(
681            counter,
682            track.get("name"),
683            track.get("artist").get("name"),
684            track.get("album").get("name")
685        )
686        counter += 1
687    text += "-" * line_width + "\n"
688    return text

Function that builds a string representation of a list tracks (dictionaries).

Arguments:
  • tracks (list): List of tracks.
  • to_html (bool): If True it will generate an HTML version (for an email or web page) and if False (default) will generate a string to print in Python.
Returns:
  • a str that has a table in it for tracks
def generate_artists_table(artists, to_html = False):
729def generate_artists_table(artists , to_html=False):
730    """
731    Makes a nice formatted table of artists. Good for writing to an
732    HTML file or showing on the screen.
733
734    Args:
735        artists (`list`): A list of artists.
736        to_html (`bool`): Whether or not you want the HTML version.
737
738    Returns:
739        a `str` with an HTML table in it.
740    """
741    if not artists
742        raise TypeError(f"A list of artists is required but you gave us a {type(artists)}: {artists}")
743
744    if to_html
745        return _get_artist_table_html(artists)
746
747    line_width = 118
748    text = ""
749    template = "{0:2} | {1:<22.22} | {2:<30.30} | {3:<60.60}\n"
750
751    # header section:
752    text += "-" * line_width + "\n"
753    text += template.format(
754        "", "Name", "Genres", "URL"
755    )
756    text += "-" * line_width + "\n"
757
758    # data section:
759    counter = 1
760    for artist in artists
761        text += template.format(
762            counter,
763            artist.get("name"),
764            artist.get("genres"),
765            artist.get("share_url")
766        )
767        counter += 1
768    text += "-" * line_width + "\n"
769    return text

Makes a nice formatted table of artists. Good for writing to an HTML file or showing on the screen.

Arguments:
  • artists (list): A list of artists.
  • to_html (bool): Whether or not you want the HTML version.
Returns:

a str with an HTML table in it.

def generate_albums_table(albums, to_html = False):
691def generate_albums_table(albums , to_html  = False):
692    """
693    Function that builds a string representation of a list of albums (dicitonaries).
694
695    Args:
696        albums (`list`): list of albums (dictionaries).
697        to_html (`bool`): If `True` it will generate an HTML version (for an email or web page) and if `False` (default) will generate a string to print in Python.
698
699    Returns:
700        * a `str` that has a table in it
701    """
702
703    if to_html
704        return _get_album_table_html(albums)
705
706    line_width = 95
707    text = ""
708    template = "{0:2} | {1:<30.30} | {2:<30.30} | {3:<22.22}\n"
709
710    # header section:
711    text += "-" * line_width + "\n"
712    text += template.format("", "Name", "Primary Artist", "Release Date")
713    text += "-" * line_width + "\n"
714
715    # data section:
716    counter = 1
717    for album in albums
718        text += template.format(
719            counter,
720            album.get("name"),
721            album.get("artist").get("name"),
722            album.get("release_date"),
723        )
724        counter += 1
725    text += "-" * line_width + "\n"
726    return text

Function that builds a string representation of a list of albums (dicitonaries).

Arguments:
  • albums (list): list of albums (dictionaries).
  • to_html (bool): If True it will generate an HTML version (for an email or web page) and if False (default) will generate a string to print in Python.
Returns:
  • a str that has a table in it
def generate_mixtape( artist_ids = [], track_ids = [], genres = [], length = 20, debug = True, practice = True, simplify = True):
344def generate_mixtape(artist_ids  = [], track_ids  = [], genres  = [], length = 20, debug  = True, practice = True, simplify  = True):
345    """
346    Generate a mixtape based off the inputted artists, tracks, and genres. You must provide at least 1 input across artists, tracks, and genres.
347    <mark>Keep in mind it does not accept artist names or track names.</mark> Specifying multiple genres might result in getting zero results.</mark>
348
349    Note: In practice mode, this function will print a warning if inputs are invalid but will still return data.
350
351    Args:
352        artist_ids (`list`): A list of artist ids (list of strings). Example: `[ "06HL4z0CvFAxyc27GXpf02", "3Nrfpe0tUJi4K4DXYWgMUX" ]`
353        track_ids (`list`): A list of track ids. Example: `[ "5ZBeML7Lf3FMEVviTyvi8l", "29U7stRjqHU6rMiS8BfaI9" ]`
354        genres (`list`): A list of genres. Example: `[ "chill" ]`
355        length (`int`): How many tracks to return as part of the mixtape
356        debug (`bool`): Whether or not you want debug text to be printed.
357        practice (`bool`): Whether or not you want real data <mark>ONLY DO THIS IF YOU HAVE SUCCESSFULLY GOTTEN PRACTICE DATA WORKING</mark>
358        
359    Returns:
360        * a `list` of tracks (dictionaries)
361    """
362
363    if not artist_ids and not track_ids and not genres
364        if practice
365            print(f"PRACTICE MODE: Note, no inputs were given.")
366        else
367            raise Exception("Either artist_ids or track_ids or genres required")
368
369    if practice
370        return _simplify_tracks(json.loads(TRACKS_JSON)["tracks"])
371
372    _verify_artist_ids(artist_ids, practice=practice)
373    _verify_track_ids(track_ids, practice=practice)
374
375    track_list = []
376
377    for artist in artist_ids
378        track_list += _get_top_tracks_by_artist(artist_id=artist, debug=debug, simplify=simplify)
379
380    if track_ids
381        track_list += _get_several_tracks(track_ids, debug=debug, simplify=simplify)
382
383    if genres
384        track_list += _search_by_genres(genres, debug=debug, simplify=simplify)
385
386    track_list = _remove_duplicate_tracks(track_list)
387    random.shuffle(track_list)
388
389    return track_list[:length]

Generate a mixtape based off the inputted artists, tracks, and genres. You must provide at least 1 input across artists, tracks, and genres. Keep in mind it does not accept artist names or track names. Specifying multiple genres might result in getting zero results.

Note: In practice mode, this function will print a warning if inputs are invalid but will still return data.

Arguments:
  • artist_ids (list): A list of artist ids (list of strings). Example: [ '06HL4z0CvFAxyc27GXpf02', '3Nrfpe0tUJi4K4DXYWgMUX' ]
  • track_ids (list): A list of track ids. Example: [ '5ZBeML7Lf3FMEVviTyvi8l', '29U7stRjqHU6rMiS8BfaI9' ]
  • genres (list): A list of genres. Example: [ 'chill' ]
  • length (int): How many tracks to return as part of the mixtape
  • debug (bool): Whether or not you want debug text to be printed.
  • practice (bool): Whether or not you want real data ONLY DO THIS IF YOU HAVE SUCCESSFULLY GOTTEN PRACTICE DATA WORKING
Returns:
  • a list of tracks (dictionaries)