apis.audio

   1_VERSION = 1.4 # Fixes favorite track selection
   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    alt_in_use = False
 920    shoud_i_remove = False
 921    if os.path.isfile(SPOTIFY_JSON):
 922        with open(SPOTIFY_JSON) as json_file
 923            data = json.load(json_file)
 924            if time.time() >= float(data["expires"]):
 925                if debug
 926                    print(f"DEBUG - {"_generate_authentication_header"}:\n Auth token expired, time to refresh!")
 927                should_i_remove = True
 928            else
 929                token = data["token"]
 930                not_cached = False
 931    
 932    if shoud_i_remove
 933        time.sleep(0.2)
 934        os.remove(SPOTIFY_JSON)
 935
 936    if not_cached
 937        if debug
 938            print(f"DEBUG - {"_generate_authentication_header"}:\n Generating new Spotify Authentication Token...") 
 939        from apis import secret_tokens
 940        
 941        current_timestamp = (time.time())
 942        if current_timestamp % 10 < 7
 943            alt_in_use = True
 944            client_id = secret_tokens.ALT_SPOTIFY_CLIENT_ID
 945            client_secret = secret_tokens.ALT_SPOTIFY_CLIENT_SECRET
 946        else
 947            client_id = secret_tokens.SPOTIFY_CLIENT_ID
 948            client_secret = secret_tokens.SPOTIFY_CLIENT_SECRET
 949
 950        # Step 1 - Authorization
 951        auth_url = "https://accounts.spotify.com/api/token"
 952        headers = {}
 953        data = {}
 954
 955        # Encode as Base64
 956        message = f"{client_id}:{client_secret}"
 957        messageBytes = message.encode("ascii")
 958        base64Bytes = base64.b64encode(messageBytes)
 959        base64Message = base64Bytes.decode("ascii")
 960
 961        headers["Authorization"] = f"Basic {base64Message}"
 962        data["grant_type"] = "client_credentials"
 963
 964        if not backup
 965            try
 966                r = requests.post(auth_url, headers=headers, data=data)
 967                token = r.json()["access_token"]
 968                with open(SPOTIFY_JSON, "w") as outfile
 969                    json_object = json.dumps({ "token" token, "expires" time.time() + 3540, "alt?"alt_in_use }, indent=4)
 970                    outfile.write(json_object)
 971                
 972            except
 973                if debug
 974                    print(f"DEBUG - {"_generate_authentication_header"}:\nCouldn"t use either default API Key. Trying backup!")
 975                backup = True
 976
 977    if backup
 978        if debug
 979            print(f"DEBUG - {"_generate_authentication_header"}:\nUsing backup...")
 980        time.sleep(1)
 981        if os.path.isfile(SPOTIFY_JSON):
 982            os.remove(SPOTIFY_JSON)
 983        
 984        from apis import authentication
 985        try
 986            token = authentication.get_token(
 987                "https://www.apitutor.org/spotify/key")
 988        except Exception as e
 989            print("ERROR: COULD NOT COMMUNICATE WITH SPOTIFY. I even tried the backup. Did you run the setup tests?")
 990            raise Exception(e)
 991    
 992    headers = {
 993        "Authorization" "Bearer " + token
 994    }
 995
 996    return headers
 997
 998def _issue_get_request(url, debug = True, practice = True):
 999    """
1000    Private function. Retrieves data from any Spotify endpoint using the authentication key.
1001
1002    * url (str): The API Endpoint + query parameters.
1003    * debug (bool): Whether or not to print debug messages.
1004    * practice (bool): Whether or not to return real data or practice data
1005
1006    Returns whatever Spotify"s API endpoint gives back.
1007    """
1008    if debug
1009        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.")
1010
1011    headers = _generate_authentication_header()
1012
1013    url = quote(url, safe="/:?&,=-")
1014
1015    # Check cache
1016    if os.path.isfile(SPOTIFY_CACHE):
1017        with open(SPOTIFY_CACHE, "rb") as file
1018            cache = pickle.load(file)
1019    else
1020        cache = {}
1021
1022    if url in cache
1023        if debug
1024            print(f"DEBUG - {"_issue_get_request"}:\nFound previous request! Returning cached result.")
1025        return cache[url]
1026
1027    response = requests.get(url, headers=headers, verify=True)
1028    if response.status_code == 429
1029        retry_length = response.headers["Retry-After"]
1030        if debug
1031            print(f"ERROR: Spotify API is overloaded! It asked us to try again in {retry_length} seconds.")
1032
1033        if os.path.isfile(SPOTIFY_JSON):
1034            os.remove(SPOTIFY_JSON)
1035
1036        if debug
1037            print(f"DEBUG - {"_issue_get_request"}:\nWe"re going to try to use the backup...")
1038        headers = _generate_authentication_header(backup=True)
1039        response = requests.get(url, headers=headers, verify=True)
1040        if response.status_code != 200
1041            raise Exception("Uh oh. Couldn"t use the backup either. It"s likely you"ve given this function invalid inputs!")
1042
1043    json_response = response.json()
1044
1045    # Save it in the cache
1046    cache[url] = json_response
1047
1048    with open(SPOTIFY_CACHE, "wb") as file
1049        pickle.dump(cache, file)
1050        
1051    return json_response
1052
1053def _simplify_tracks(tracks , debug=True):
1054    """
1055    Private function. Simplifies the Spotify track data so that each dictionary only contains
1056    a few key features (the original dictionary is quite large).
1057
1058    * tracks (list): The original tracks data structure returned from Spotify.
1059
1060    Returns a list of simplified tracks.
1061    """
1062    try
1063        tracks[0]
1064    except Exception
1065        return tracks
1066
1067    simplified = []
1068    for item in tracks
1069        track = {
1070            "id" item["id"],
1071            "name" item["name"],
1072            "preview_url" item["preview_url"],
1073            "share_url" "https://open.spotify.com/track/" + item["id"]
1074        }
1075        try
1076            track["album"] = {
1077                "id" item["album"]["id"],
1078                "name" item["album"]["name"],
1079                "image_url" item["album"]["images"][0]["url"],
1080                "image_url_small" item["album"]["images"][-1]["url"],
1081                "share_url" "https://open.spotify.com/album/" + item["album"]["id"]
1082            }
1083        except Exception
1084            pass
1085        try
1086            artists = item.get("album").get("artists")
1087            artist = artists[0]
1088            track["artist"] = {
1089                "id" artist["id"],
1090                "name" artist["name"],
1091                "share_url" "https://open.spotify.com/artist/" + item["album"]["artists"][0]["id"]
1092            }
1093        except Exception
1094            pass
1095        simplified.append(track)
1096    return simplified
1097
1098
1099def _simplify_artists(artists , debug=True):
1100    """
1101    Private function. Simplifies the Spotify artist data so that each dictionary only contains
1102    a few key features (the original dictionary is quite large).
1103
1104    * artists (list): The original artists data structure returned from Spotify.
1105
1106    Returns a list of simplified artists.
1107    """
1108    try
1109        artists[0]
1110    except Exception
1111        return artists
1112
1113    simplified = []
1114    for item in artists
1115        artist = {
1116            "id" item["id"],
1117            "name" item["name"],
1118            "genres" ", ".join(item["genres"]),
1119            "share_url" "https://open.spotify.com/artist/" + item["id"]
1120        }
1121        try
1122            artist["image_url"] = item["images"][0]["url"]
1123            artist["image_url_small"] = item["images"][-1]["url"]
1124        except Exception
1125            pass
1126        simplified.append(artist)
1127    return simplified
1128
1129def _simplify_albums(albums , debug=True):
1130    """
1131    Private function. Simplifies the Spotify artist data so that each dictionary only contains
1132    a few key features (the original dictionary is quite large).
1133
1134    * artists (list): The original artists data structure returned from Spotify.
1135
1136    Returns a list of simplified artists.
1137    """
1138    try
1139        albums[0]
1140    except Exception
1141        return albums
1142
1143    simplified = []
1144    for item in albums
1145        album = {
1146            "id" item["id"],
1147            "name" item["name"],
1148            "release_date" item["release_date"],
1149            "artist" item["artists"][0],
1150            "share_url" "https://open.spotify.com/album/" + item["id"]
1151        }
1152        try
1153            album["image_url"] = item["images"][0]["url"]
1154            album["image_url_small"] = item["images"][-1]["url"]
1155        except Exception
1156            pass
1157        simplified.append(album)
1158    return simplified
1159
1160def _simplify_playlists(playlists , debug=True):
1161    """
1162    Private function. Simplifies the Spotify playlist data so that each dictionary only contains
1163    a few key features (the original dictionary is quite large).
1164
1165    * playlists (list): The original playlist data structure returned from Spotify.
1166
1167    Returns a list of simplified playlist entries.
1168    """
1169    try
1170        simplified = []
1171        for item in playlists
1172            # Winter 25 - some playlists come back as None
1173            if item is None
1174                continue
1175            simplified.append({
1176                "id" item["id"],
1177                "name" item["name"],
1178                "owner_display_name" item["owner"]["display_name"],
1179                "owner_id" item["owner"]["id"],
1180                "share_url" "https://open.spotify.com/playlist/" + item["id"],
1181                "num_tracks" item["tracks"]["total"]
1182            })
1183        return simplified
1184    except Exception as e
1185        raise Exception(
1186            f"The following playlist data structure could not be flattened:\n{playlists}"
1187        )
1188
1189
1190TRACKS_JSON = """
1191{
1192    "tracks": [
1193        {
1194            "album": {
1195                "album_type": "ALBUM",
1196                "artists": [
1197                    {
1198                        "external_urls": {
1199                            "spotify": "https://open.spotify.com/artist/6UE7nl9mha6s8z0wFQFIZ2"
1200                        },
1201                        "href": "https://api.spotify.com/v1/artists/6UE7nl9mha6s8z0wFQFIZ2",
1202                        "id": "6UE7nl9mha6s8z0wFQFIZ2",
1203                        "name": "Robyn",
1204                        "type": "artist",
1205                        "uri": "spotify:artist:6UE7nl9mha6s8z0wFQFIZ2"
1206                    }
1207                ],
1208                "external_urls": {
1209                    "spotify": "https://open.spotify.com/album/0le9TO3kU69m6iWHTjNs9Y"
1210                },
1211                "href": "https://api.spotify.com/v1/albums/0le9TO3kU69m6iWHTjNs9Y",
1212                "id": "0le9TO3kU69m6iWHTjNs9Y",
1213                "images": [
1214                    {
1215                        "height": 640,
1216                        "url": "https://i.scdn.co/image/ab67616d0000b2734689597708c1b0b3dcb9ecaf",
1217                        "width": 640
1218                    },
1219                    {
1220                        "height": 300,
1221                        "url": "https://i.scdn.co/image/ab67616d00001e024689597708c1b0b3dcb9ecaf",
1222                        "width": 300
1223                    },
1224                    {
1225                        "height": 64,
1226                        "url": "https://i.scdn.co/image/ab67616d000048514689597708c1b0b3dcb9ecaf",
1227                        "width": 64
1228                    }
1229                ],
1230                "is_playable": true,
1231                "name": "Body Talk",
1232                "release_date": "2010-01-01",
1233                "release_date_precision": "day",
1234                "total_tracks": 15,
1235                "type": "album",
1236                "uri": "spotify:album:0le9TO3kU69m6iWHTjNs9Y"
1237            },
1238            "artists": [
1239                {
1240                    "external_urls": {
1241                        "spotify": "https://open.spotify.com/artist/6UE7nl9mha6s8z0wFQFIZ2"
1242                    },
1243                    "href": "https://api.spotify.com/v1/artists/6UE7nl9mha6s8z0wFQFIZ2",
1244                    "id": "6UE7nl9mha6s8z0wFQFIZ2",
1245                    "name": "Robyn",
1246                    "type": "artist",
1247                    "uri": "spotify:artist:6UE7nl9mha6s8z0wFQFIZ2"
1248                }
1249            ],
1250            "disc_number": 1,
1251            "duration_ms": 278080,
1252            "explicit": false,
1253            "external_ids": {
1254                "isrc": "SEWKZ1000009"
1255            },
1256            "external_urls": {
1257                "spotify": "https://open.spotify.com/track/7g13jf3zqlP5S68Voo5v9m"
1258            },
1259            "href": "https://api.spotify.com/v1/tracks/7g13jf3zqlP5S68Voo5v9m",
1260            "id": "7g13jf3zqlP5S68Voo5v9m",
1261            "is_local": false,
1262            "is_playable": true,
1263            "linked_from": {
1264                "external_urls": {
1265                    "spotify": "https://open.spotify.com/track/6aqNCrRA7vs7v6QvRpI50t"
1266                },
1267                "href": "https://api.spotify.com/v1/tracks/6aqNCrRA7vs7v6QvRpI50t",
1268                "id": "6aqNCrRA7vs7v6QvRpI50t",
1269                "type": "track",
1270                "uri": "spotify:track:6aqNCrRA7vs7v6QvRpI50t"
1271            },
1272            "name": "Dancing On My Own - Radio Edit",
1273            "popularity": 63,
1274            "preview_url": null,
1275            "track_number": 1,
1276            "type": "track",
1277            "uri": "spotify:track:7g13jf3zqlP5S68Voo5v9m"
1278        },
1279        {
1280            "album": {
1281                "album_type": "COMPILATION",
1282                "artists": [
1283                    {
1284                        "external_urls": {
1285                            "spotify": "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of"
1286                        },
1287                        "href": "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of",
1288                        "id": "0LyfQWJT6nXafLPZqxe9Of",
1289                        "name": "Various Artists",
1290                        "type": "artist",
1291                        "uri": "spotify:artist:0LyfQWJT6nXafLPZqxe9Of"
1292                    },
1293                    {
1294                        "external_urls": {
1295                            "spotify": "https://open.spotify.com/artist/2dfDjeZroUd3LWmSFrAZCD"
1296                        },
1297                        "href": "https://api.spotify.com/v1/artists/2dfDjeZroUd3LWmSFrAZCD",
1298                        "id": "2dfDjeZroUd3LWmSFrAZCD",
1299                        "name": "David Parry",
1300                        "type": "artist",
1301                        "uri": "spotify:artist:2dfDjeZroUd3LWmSFrAZCD"
1302                    },
1303                    {
1304                        "external_urls": {
1305                            "spotify": "https://open.spotify.com/artist/3PfJE6ebCbCHeuqO4BfNeA"
1306                        },
1307                        "href": "https://api.spotify.com/v1/artists/3PfJE6ebCbCHeuqO4BfNeA",
1308                        "id": "3PfJE6ebCbCHeuqO4BfNeA",
1309                        "name": "London Philharmonic Orchestra",
1310                        "type": "artist",
1311                        "uri": "spotify:artist:3PfJE6ebCbCHeuqO4BfNeA"
1312                    }
1313                ],
1314                "external_urls": {
1315                    "spotify": "https://open.spotify.com/album/0bgjJ99UFbk0yBOzjJl7cq"
1316                },
1317                "href": "https://api.spotify.com/v1/albums/0bgjJ99UFbk0yBOzjJl7cq",
1318                "id": "0bgjJ99UFbk0yBOzjJl7cq",
1319                "images": [
1320                    {
1321                        "height": 640,
1322                        "url": "https://i.scdn.co/image/ab67616d0000b27376206bd8de3a477aafd7ba83",
1323                        "width": 640
1324                    },
1325                    {
1326                        "height": 300,
1327                        "url": "https://i.scdn.co/image/ab67616d00001e0276206bd8de3a477aafd7ba83",
1328                        "width": 300
1329                    },
1330                    {
1331                        "height": 64,
1332                        "url": "https://i.scdn.co/image/ab67616d0000485176206bd8de3a477aafd7ba83",
1333                        "width": 64
1334                    }
1335                ],
1336                "is_playable": true,
1337                "name": "The 50 Greatest Pieces of Classical Music",
1338                "release_date": "2009-11-23",
1339                "release_date_precision": "day",
1340                "total_tracks": 50,
1341                "type": "album",
1342                "uri": "spotify:album:0bgjJ99UFbk0yBOzjJl7cq"
1343            },
1344            "artists": [
1345                {
1346                    "external_urls": {
1347                        "spotify": "https://open.spotify.com/artist/430byzy0c5bPn5opiu0SRd"
1348                    },
1349                    "href": "https://api.spotify.com/v1/artists/430byzy0c5bPn5opiu0SRd",
1350                    "id": "430byzy0c5bPn5opiu0SRd",
1351                    "name": "Edward Elgar",
1352                    "type": "artist",
1353                    "uri": "spotify:artist:430byzy0c5bPn5opiu0SRd"
1354                },
1355                {
1356                    "external_urls": {
1357                        "spotify": "https://open.spotify.com/artist/2dfDjeZroUd3LWmSFrAZCD"
1358                    },
1359                    "href": "https://api.spotify.com/v1/artists/2dfDjeZroUd3LWmSFrAZCD",
1360                    "id": "2dfDjeZroUd3LWmSFrAZCD",
1361                    "name": "David Parry",
1362                    "type": "artist",
1363                    "uri": "spotify:artist:2dfDjeZroUd3LWmSFrAZCD"
1364                },
1365                {
1366                    "external_urls": {
1367                        "spotify": "https://open.spotify.com/artist/3PfJE6ebCbCHeuqO4BfNeA"
1368                    },
1369                    "href": "https://api.spotify.com/v1/artists/3PfJE6ebCbCHeuqO4BfNeA",
1370                    "id": "3PfJE6ebCbCHeuqO4BfNeA",
1371                    "name": "London Philharmonic Orchestra",
1372                    "type": "artist",
1373                    "uri": "spotify:artist:3PfJE6ebCbCHeuqO4BfNeA"
1374                }
1375            ],
1376            "disc_number": 1,
1377            "duration_ms": 345666,
1378            "explicit": false,
1379            "external_ids": {
1380                "isrc": "SEWDL9750023"
1381            },
1382            "external_urls": {
1383                "spotify": "https://open.spotify.com/track/5nsYZFNyMefd50yamWgMfy"
1384            },
1385            "href": "https://api.spotify.com/v1/tracks/5nsYZFNyMefd50yamWgMfy",
1386            "id": "5nsYZFNyMefd50yamWgMfy",
1387            "is_local": false,
1388            "is_playable": true,
1389            "name": "Pomp and Circumstance, Op. 39: No. 1, March in D Major",
1390            "popularity": 43,
1391            "preview_url": "https://p.scdn.co/mp3-preview/f617411fdc9c52d598ec9d5cde4baf24895598cb?cid=b800bf59070c4b52a8917d2230d25bdc",
1392            "track_number": 23,
1393            "type": "track",
1394            "uri": "spotify:track:5nsYZFNyMefd50yamWgMfy"
1395        },
1396        {
1397            "album": {
1398                "album_type": "ALBUM",
1399                "artists": [
1400                    {
1401                        "external_urls": {
1402                            "spotify": "https://open.spotify.com/artist/37mtx80nMDETlbsq2eFCzc"
1403                        },
1404                        "href": "https://api.spotify.com/v1/artists/37mtx80nMDETlbsq2eFCzc",
1405                        "id": "37mtx80nMDETlbsq2eFCzc",
1406                        "name": "Fleur East",
1407                        "type": "artist",
1408                        "uri": "spotify:artist:37mtx80nMDETlbsq2eFCzc"
1409                    }
1410                ],
1411                "external_urls": {
1412                    "spotify": "https://open.spotify.com/album/1nFgJpjh2doGfve56uADlm"
1413                },
1414                "href": "https://api.spotify.com/v1/albums/1nFgJpjh2doGfve56uADlm",
1415                "id": "1nFgJpjh2doGfve56uADlm",
1416                "images": [
1417                    {
1418                        "height": 640,
1419                        "url": "https://i.scdn.co/image/ab67616d0000b27340ab5a3c8e7e7c8f12cca2bb",
1420                        "width": 640
1421                    },
1422                    {
1423                        "height": 300,
1424                        "url": "https://i.scdn.co/image/ab67616d00001e0240ab5a3c8e7e7c8f12cca2bb",
1425                        "width": 300
1426                    },
1427                    {
1428                        "height": 64,
1429                        "url": "https://i.scdn.co/image/ab67616d0000485140ab5a3c8e7e7c8f12cca2bb",
1430                        "width": 64
1431                    }
1432                ],
1433                "is_playable": true,
1434                "name": "Love, Sax & Flashbacks (Track by Track)",
1435                "release_date": "2015-12-03",
1436                "release_date_precision": "day",
1437                "total_tracks": 32,
1438                "type": "album",
1439                "uri": "spotify:album:1nFgJpjh2doGfve56uADlm"
1440            },
1441            "artists": [
1442                {
1443                    "external_urls": {
1444                        "spotify": "https://open.spotify.com/artist/37mtx80nMDETlbsq2eFCzc"
1445                    },
1446                    "href": "https://api.spotify.com/v1/artists/37mtx80nMDETlbsq2eFCzc",
1447                    "id": "37mtx80nMDETlbsq2eFCzc",
1448                    "name": "Fleur East",
1449                    "type": "artist",
1450                    "uri": "spotify:artist:37mtx80nMDETlbsq2eFCzc"
1451                }
1452            ],
1453            "disc_number": 1,
1454            "duration_ms": 236440,
1455            "explicit": false,
1456            "external_ids": {
1457                "isrc": "GBHMU1500146"
1458            },
1459            "external_urls": {
1460                "spotify": "https://open.spotify.com/track/2lqgZDZnlXmVZgToWuoC0l"
1461            },
1462            "href": "https://api.spotify.com/v1/tracks/2lqgZDZnlXmVZgToWuoC0l",
1463            "id": "2lqgZDZnlXmVZgToWuoC0l",
1464            "is_local": false,
1465            "is_playable": true,
1466            "linked_from": {
1467                "external_urls": {
1468                    "spotify": "https://open.spotify.com/track/2IFl6p0LoIfIZOn5IaxZOO"
1469                },
1470                "href": "https://api.spotify.com/v1/tracks/2IFl6p0LoIfIZOn5IaxZOO",
1471                "id": "2IFl6p0LoIfIZOn5IaxZOO",
1472                "type": "track",
1473                "uri": "spotify:track:2IFl6p0LoIfIZOn5IaxZOO"
1474            },
1475            "name": "Sax",
1476            "popularity": 56,
1477            "preview_url": "https://p.scdn.co/mp3-preview/6d74e1c14810c12a9ccea0c523c740ab98a262fc?cid=b800bf59070c4b52a8917d2230d25bdc",
1478            "track_number": 1,
1479            "type": "track",
1480            "uri": "spotify:track:2lqgZDZnlXmVZgToWuoC0l"
1481        },
1482        {
1483            "album": {
1484                "album_type": "SINGLE",
1485                "artists": [
1486                    {
1487                        "external_urls": {
1488                            "spotify": "https://open.spotify.com/artist/1gALaWbNDnwS2ECV09sn2A"
1489                        },
1490                        "href": "https://api.spotify.com/v1/artists/1gALaWbNDnwS2ECV09sn2A",
1491                        "id": "1gALaWbNDnwS2ECV09sn2A",
1492                        "name": "Nightcrawlers",
1493                        "type": "artist",
1494                        "uri": "spotify:artist:1gALaWbNDnwS2ECV09sn2A"
1495                    }
1496                ],
1497                "external_urls": {
1498                    "spotify": "https://open.spotify.com/album/5JVyNX3e2hGoOttoe7B8QL"
1499                },
1500                "href": "https://api.spotify.com/v1/albums/5JVyNX3e2hGoOttoe7B8QL",
1501                "id": "5JVyNX3e2hGoOttoe7B8QL",
1502                "images": [
1503                    {
1504                        "height": 640,
1505                        "url": "https://i.scdn.co/image/ab67616d0000b2733b1e6a6f5aa7c01b433779fe",
1506                        "width": 640
1507                    },
1508                    {
1509                        "height": 300,
1510                        "url": "https://i.scdn.co/image/ab67616d00001e023b1e6a6f5aa7c01b433779fe",
1511                        "width": 300
1512                    },
1513                    {
1514                        "height": 64,
1515                        "url": "https://i.scdn.co/image/ab67616d000048513b1e6a6f5aa7c01b433779fe",
1516                        "width": 64
1517                    }
1518                ],
1519                "is_playable": true,
1520                "name": "Push The Feeling On",
1521                "release_date": "1995",
1522                "release_date_precision": "year",
1523                "total_tracks": 4,
1524                "type": "album",
1525                "uri": "spotify:album:5JVyNX3e2hGoOttoe7B8QL"
1526            },
1527            "artists": [
1528                {
1529                    "external_urls": {
1530                        "spotify": "https://open.spotify.com/artist/1gALaWbNDnwS2ECV09sn2A"
1531                    },
1532                    "href": "https://api.spotify.com/v1/artists/1gALaWbNDnwS2ECV09sn2A",
1533                    "id": "1gALaWbNDnwS2ECV09sn2A",
1534                    "name": "Nightcrawlers",
1535                    "type": "artist",
1536                    "uri": "spotify:artist:1gALaWbNDnwS2ECV09sn2A"
1537                },
1538                {
1539                    "external_urls": {
1540                        "spotify": "https://open.spotify.com/artist/1yqxFtPHKcGcv6SXZNdyT9"
1541                    },
1542                    "href": "https://api.spotify.com/v1/artists/1yqxFtPHKcGcv6SXZNdyT9",
1543                    "id": "1yqxFtPHKcGcv6SXZNdyT9",
1544                    "name": "MK",
1545                    "type": "artist",
1546                    "uri": "spotify:artist:1yqxFtPHKcGcv6SXZNdyT9"
1547                }
1548            ],
1549            "disc_number": 1,
1550            "duration_ms": 243160,
1551            "explicit": false,
1552            "external_ids": {
1553                "isrc": "GBANY9500081"
1554            },
1555            "external_urls": {
1556                "spotify": "https://open.spotify.com/track/1EWsVHU4FNAdtN4R8FETag"
1557            },
1558            "href": "https://api.spotify.com/v1/tracks/1EWsVHU4FNAdtN4R8FETag",
1559            "id": "1EWsVHU4FNAdtN4R8FETag",
1560            "is_local": false,
1561            "is_playable": true,
1562            "name": "Push The Feeling On - Mk Dub Revisited Edit",
1563            "popularity": 69,
1564            "preview_url": null,
1565            "track_number": 1,
1566            "type": "track",
1567            "uri": "spotify:track:1EWsVHU4FNAdtN4R8FETag"
1568        },
1569        {
1570            "album": {
1571                "album_type": "ALBUM",
1572                "artists": [
1573                    {
1574                        "external_urls": {
1575                            "spotify": "https://open.spotify.com/artist/7gAppWoH7pcYmphCVTXkzs"
1576                        },
1577                        "href": "https://api.spotify.com/v1/artists/7gAppWoH7pcYmphCVTXkzs",
1578                        "id": "7gAppWoH7pcYmphCVTXkzs",
1579                        "name": "The Vamps",
1580                        "type": "artist",
1581                        "uri": "spotify:artist:7gAppWoH7pcYmphCVTXkzs"
1582                    }
1583                ],
1584                "external_urls": {
1585                    "spotify": "https://open.spotify.com/album/69Pj3ce9XFZUi3XuQylLKf"
1586                },
1587                "href": "https://api.spotify.com/v1/albums/69Pj3ce9XFZUi3XuQylLKf",
1588                "id": "69Pj3ce9XFZUi3XuQylLKf",
1589                "images": [
1590                    {
1591                        "height": 640,
1592                        "url": "https://i.scdn.co/image/ab67616d0000b273f36a4e2e1687e678f29328cb",
1593                        "width": 640
1594                    },
1595                    {
1596                        "height": 300,
1597                        "url": "https://i.scdn.co/image/ab67616d00001e02f36a4e2e1687e678f29328cb",
1598                        "width": 300
1599                    },
1600                    {
1601                        "height": 64,
1602                        "url": "https://i.scdn.co/image/ab67616d00004851f36a4e2e1687e678f29328cb",
1603                        "width": 64
1604                    }
1605                ],
1606                "is_playable": true,
1607                "name": "Night & Day (Night Edition)",
1608                "release_date": "2017-07-14",
1609                "release_date_precision": "day",
1610                "total_tracks": 10,
1611                "type": "album",
1612                "uri": "spotify:album:69Pj3ce9XFZUi3XuQylLKf"
1613            },
1614            "artists": [
1615                {
1616                    "external_urls": {
1617                        "spotify": "https://open.spotify.com/artist/7gAppWoH7pcYmphCVTXkzs"
1618                    },
1619                    "href": "https://api.spotify.com/v1/artists/7gAppWoH7pcYmphCVTXkzs",
1620                    "id": "7gAppWoH7pcYmphCVTXkzs",
1621                    "name": "The Vamps",
1622                    "type": "artist",
1623                    "uri": "spotify:artist:7gAppWoH7pcYmphCVTXkzs"
1624                },
1625                {
1626                    "external_urls": {
1627                        "spotify": "https://open.spotify.com/artist/4YXycRbyyAE0wozTk7QMEq"
1628                    },
1629                    "href": "https://api.spotify.com/v1/artists/4YXycRbyyAE0wozTk7QMEq",
1630                    "id": "4YXycRbyyAE0wozTk7QMEq",
1631                    "name": "Matoma",
1632                    "type": "artist",
1633                    "uri": "spotify:artist:4YXycRbyyAE0wozTk7QMEq"
1634                }
1635            ],
1636            "disc_number": 1,
1637            "duration_ms": 197640,
1638            "explicit": false,
1639            "external_ids": {
1640                "isrc": "GBUM71605342"
1641            },
1642            "external_urls": {
1643                "spotify": "https://open.spotify.com/track/0dXNQ8dckG4eYfEtq9zcva"
1644            },
1645            "href": "https://api.spotify.com/v1/tracks/0dXNQ8dckG4eYfEtq9zcva",
1646            "id": "0dXNQ8dckG4eYfEtq9zcva",
1647            "is_local": false,
1648            "is_playable": true,
1649            "name": "All Night",
1650            "popularity": 72,
1651            "preview_url": null,
1652            "track_number": 2,
1653            "type": "track",
1654            "uri": "spotify:track:0dXNQ8dckG4eYfEtq9zcva"
1655        },
1656        {
1657            "album": {
1658                "album_type": "ALBUM",
1659                "artists": [
1660                    {
1661                        "external_urls": {
1662                            "spotify": "https://open.spotify.com/artist/6fxyWrfmjcbj5d12gXeiNV"
1663                        },
1664                        "href": "https://api.spotify.com/v1/artists/6fxyWrfmjcbj5d12gXeiNV",
1665                        "id": "6fxyWrfmjcbj5d12gXeiNV",
1666                        "name": "Denzel Curry",
1667                        "type": "artist",
1668                        "uri": "spotify:artist:6fxyWrfmjcbj5d12gXeiNV"
1669                    }
1670                ],
1671                "external_urls": {
1672                    "spotify": "https://open.spotify.com/album/42fyKPanos0Q3woi848ktg"
1673                },
1674                "href": "https://api.spotify.com/v1/albums/42fyKPanos0Q3woi848ktg",
1675                "id": "42fyKPanos0Q3woi848ktg",
1676                "images": [
1677                    {
1678                        "height": 640,
1679                        "url": "https://i.scdn.co/image/ab67616d0000b273166442984ba98f0a2dcaea5e",
1680                        "width": 640
1681                    },
1682                    {
1683                        "height": 300,
1684                        "url": "https://i.scdn.co/image/ab67616d00001e02166442984ba98f0a2dcaea5e",
1685                        "width": 300
1686                    },
1687                    {
1688                        "height": 64,
1689                        "url": "https://i.scdn.co/image/ab67616d00004851166442984ba98f0a2dcaea5e",
1690                        "width": 64
1691                    }
1692                ],
1693                "is_playable": true,
1694                "name": "Imperial",
1695                "release_date": "2016-10-14",
1696                "release_date_precision": "day",
1697                "total_tracks": 10,
1698                "type": "album",
1699                "uri": "spotify:album:42fyKPanos0Q3woi848ktg"
1700            },
1701            "artists": [
1702                {
1703                    "external_urls": {
1704                        "spotify": "https://open.spotify.com/artist/6fxyWrfmjcbj5d12gXeiNV"
1705                    },
1706                    "href": "https://api.spotify.com/v1/artists/6fxyWrfmjcbj5d12gXeiNV",
1707                    "id": "6fxyWrfmjcbj5d12gXeiNV",
1708                    "name": "Denzel Curry",
1709                    "type": "artist",
1710                    "uri": "spotify:artist:6fxyWrfmjcbj5d12gXeiNV"
1711                }
1712            ],
1713            "disc_number": 1,
1714            "duration_ms": 247054,
1715            "explicit": true,
1716            "external_ids": {
1717                "isrc": "USC4R1602006"
1718            },
1719            "external_urls": {
1720                "spotify": "https://open.spotify.com/track/5BSz8sJO2YmKfNVQG7fq2J"
1721            },
1722            "href": "https://api.spotify.com/v1/tracks/5BSz8sJO2YmKfNVQG7fq2J",
1723            "id": "5BSz8sJO2YmKfNVQG7fq2J",
1724            "is_local": false,
1725            "is_playable": true,
1726            "name": "ULT",
1727            "popularity": 52,
1728            "preview_url": null,
1729            "track_number": 1,
1730            "type": "track",
1731            "uri": "spotify:track:5BSz8sJO2YmKfNVQG7fq2J"
1732        },
1733        {
1734            "album": {
1735                "album_type": "ALBUM",
1736                "artists": [
1737                    {
1738                        "external_urls": {
1739                            "spotify": "https://open.spotify.com/artist/2ojlS7imGFiZ8A8tXXGEt7"
1740                        },
1741                        "href": "https://api.spotify.com/v1/artists/2ojlS7imGFiZ8A8tXXGEt7",
1742                        "id": "2ojlS7imGFiZ8A8tXXGEt7",
1743                        "name": "Library Tapes",
1744                        "type": "artist",
1745                        "uri": "spotify:artist:2ojlS7imGFiZ8A8tXXGEt7"
1746                    }
1747                ],
1748                "external_urls": {
1749                    "spotify": "https://open.spotify.com/album/43QOTxisI7tVOFZgUIWu4g"
1750                },
1751                "href": "https://api.spotify.com/v1/albums/43QOTxisI7tVOFZgUIWu4g",
1752                "id": "43QOTxisI7tVOFZgUIWu4g",
1753                "images": [
1754                    {
1755                        "height": 640,
1756                        "url": "https://i.scdn.co/image/ab67616d0000b2736813c2e10a4fb2a5cac8ebb0",
1757                        "width": 640
1758                    },
1759                    {
1760                        "height": 300,
1761                        "url": "https://i.scdn.co/image/ab67616d00001e026813c2e10a4fb2a5cac8ebb0",
1762                        "width": 300
1763                    },
1764                    {
1765                        "height": 64,
1766                        "url": "https://i.scdn.co/image/ab67616d000048516813c2e10a4fb2a5cac8ebb0",
1767                        "width": 64
1768                    }
1769                ],
1770                "is_playable": true,
1771                "name": "Fragment",
1772                "release_date": "2008-06-15",
1773                "release_date_precision": "day",
1774                "total_tracks": 8,
1775                "type": "album",
1776                "uri": "spotify:album:43QOTxisI7tVOFZgUIWu4g"
1777            },
1778            "artists": [
1779                {
1780                    "external_urls": {
1781                        "spotify": "https://open.spotify.com/artist/2ojlS7imGFiZ8A8tXXGEt7"
1782                    },
1783                    "href": "https://api.spotify.com/v1/artists/2ojlS7imGFiZ8A8tXXGEt7",
1784                    "id": "2ojlS7imGFiZ8A8tXXGEt7",
1785                    "name": "Library Tapes",
1786                    "type": "artist",
1787                    "uri": "spotify:artist:2ojlS7imGFiZ8A8tXXGEt7"
1788                }
1789            ],
1790            "disc_number": 1,
1791            "duration_ms": 240506,
1792            "explicit": false,
1793            "external_ids": {
1794                "isrc": "SEYTP0800202"
1795            },
1796            "external_urls": {
1797                "spotify": "https://open.spotify.com/track/7vv4tJIsMFm3XnDHikiwIc"
1798            },
1799            "href": "https://api.spotify.com/v1/tracks/7vv4tJIsMFm3XnDHikiwIc",
1800            "id": "7vv4tJIsMFm3XnDHikiwIc",
1801            "is_local": false,
1802            "is_playable": true,
1803            "linked_from": {
1804                "external_urls": {
1805                    "spotify": "https://open.spotify.com/track/7JQfc4yI4R8E4WOUYR7HD9"
1806                },
1807                "href": "https://api.spotify.com/v1/tracks/7JQfc4yI4R8E4WOUYR7HD9",
1808                "id": "7JQfc4yI4R8E4WOUYR7HD9",
1809                "type": "track",
1810                "uri": "spotify:track:7JQfc4yI4R8E4WOUYR7HD9"
1811            },
1812            "name": "Fragment II",
1813            "popularity": 44,
1814            "preview_url": null,
1815            "track_number": 2,
1816            "type": "track",
1817            "uri": "spotify:track:7vv4tJIsMFm3XnDHikiwIc"
1818        },
1819        {
1820            "album": {
1821                "album_type": "ALBUM",
1822                "artists": [
1823                    {
1824                        "external_urls": {
1825                            "spotify": "https://open.spotify.com/artist/163tK9Wjr9P9DmM0AVK7lm"
1826                        },
1827                        "href": "https://api.spotify.com/v1/artists/163tK9Wjr9P9DmM0AVK7lm",
1828                        "id": "163tK9Wjr9P9DmM0AVK7lm",
1829                        "name": "Lorde",
1830                        "type": "artist",
1831                        "uri": "spotify:artist:163tK9Wjr9P9DmM0AVK7lm"
1832                    }
1833                ],
1834                "external_urls": {
1835                    "spotify": "https://open.spotify.com/album/2nPokmAvYy5qYO4rFU7ZDm"
1836                },
1837                "href": "https://api.spotify.com/v1/albums/2nPokmAvYy5qYO4rFU7ZDm",
1838                "id": "2nPokmAvYy5qYO4rFU7ZDm",
1839                "images": [
1840                    {
1841                        "height": 640,
1842                        "url": "https://i.scdn.co/image/ab67616d0000b273e19c63f62581ab73a6589382",
1843                        "width": 640
1844                    },
1845                    {
1846                        "height": 300,
1847                        "url": "https://i.scdn.co/image/ab67616d00001e02e19c63f62581ab73a6589382",
1848                        "width": 300
1849                    },
1850                    {
1851                        "height": 64,
1852                        "url": "https://i.scdn.co/image/ab67616d00004851e19c63f62581ab73a6589382",
1853                        "width": 64
1854                    }
1855                ],
1856                "is_playable": true,
1857                "name": "Pure Heroine",
1858                "release_date": "2013-01-01",
1859                "release_date_precision": "day",
1860                "total_tracks": 13,
1861                "type": "album",
1862                "uri": "spotify:album:2nPokmAvYy5qYO4rFU7ZDm"
1863            },
1864            "artists": [
1865                {
1866                    "external_urls": {
1867                        "spotify": "https://open.spotify.com/artist/163tK9Wjr9P9DmM0AVK7lm"
1868                    },
1869                    "href": "https://api.spotify.com/v1/artists/163tK9Wjr9P9DmM0AVK7lm",
1870                    "id": "163tK9Wjr9P9DmM0AVK7lm",
1871                    "name": "Lorde",
1872                    "type": "artist",
1873                    "uri": "spotify:artist:163tK9Wjr9P9DmM0AVK7lm"
1874                }
1875            ],
1876            "disc_number": 1,
1877            "duration_ms": 258969,
1878            "explicit": false,
1879            "external_ids": {
1880                "isrc": "NZUM71300122"
1881            },
1882            "external_urls": {
1883                "spotify": "https://open.spotify.com/track/2MvvoeRt8NcOXWESkxWn3g"
1884            },
1885            "href": "https://api.spotify.com/v1/tracks/2MvvoeRt8NcOXWESkxWn3g",
1886            "id": "2MvvoeRt8NcOXWESkxWn3g",
1887            "is_local": false,
1888            "is_playable": true,
1889            "linked_from": {
1890                "external_urls": {
1891                    "spotify": "https://open.spotify.com/track/38WyDtxZhxm63jiythwemE"
1892                },
1893                "href": "https://api.spotify.com/v1/tracks/38WyDtxZhxm63jiythwemE",
1894                "id": "38WyDtxZhxm63jiythwemE",
1895                "type": "track",
1896                "uri": "spotify:track:38WyDtxZhxm63jiythwemE"
1897            },
1898            "name": "Ribs",
1899            "popularity": 80,
1900            "preview_url": null,
1901            "track_number": 4,
1902            "type": "track",
1903            "uri": "spotify:track:2MvvoeRt8NcOXWESkxWn3g"
1904        },
1905        {
1906            "album": {
1907                "album_type": "SINGLE",
1908                "artists": [
1909                    {
1910                        "external_urls": {
1911                            "spotify": "https://open.spotify.com/artist/0lZoBs4Pzo7R89JM9lxwoT"
1912                        },
1913                        "href": "https://api.spotify.com/v1/artists/0lZoBs4Pzo7R89JM9lxwoT",
1914                        "id": "0lZoBs4Pzo7R89JM9lxwoT",
1915                        "name": "Duran Duran",
1916                        "type": "artist",
1917                        "uri": "spotify:artist:0lZoBs4Pzo7R89JM9lxwoT"
1918                    }
1919                ],
1920                "external_urls": {
1921                    "spotify": "https://open.spotify.com/album/5NLAqcJTupUe8pUzf6Jaen"
1922                },
1923                "href": "https://api.spotify.com/v1/albums/5NLAqcJTupUe8pUzf6Jaen",
1924                "id": "5NLAqcJTupUe8pUzf6Jaen",
1925                "images": [
1926                    {
1927                        "height": 640,
1928                        "url": "https://i.scdn.co/image/ab67616d0000b273b35021533b9088e272ceeb90",
1929                        "width": 640
1930                    },
1931                    {
1932                        "height": 300,
1933                        "url": "https://i.scdn.co/image/ab67616d00001e02b35021533b9088e272ceeb90",
1934                        "width": 300
1935                    },
1936                    {
1937                        "height": 64,
1938                        "url": "https://i.scdn.co/image/ab67616d00004851b35021533b9088e272ceeb90",
1939                        "width": 64
1940                    }
1941                ],
1942                "is_playable": true,
1943                "name": "Last Night in the City (feat. Kiesza) [The Remixes]",
1944                "release_date": "2017-03-10",
1945                "release_date_precision": "day",
1946                "total_tracks": 4,
1947                "type": "album",
1948                "uri": "spotify:album:5NLAqcJTupUe8pUzf6Jaen"
1949            },
1950            "artists": [
1951                {
1952                    "external_urls": {
1953                        "spotify": "https://open.spotify.com/artist/0lZoBs4Pzo7R89JM9lxwoT"
1954                    },
1955                    "href": "https://api.spotify.com/v1/artists/0lZoBs4Pzo7R89JM9lxwoT",
1956                    "id": "0lZoBs4Pzo7R89JM9lxwoT",
1957                    "name": "Duran Duran",
1958                    "type": "artist",
1959                    "uri": "spotify:artist:0lZoBs4Pzo7R89JM9lxwoT"
1960                },
1961                {
1962                    "external_urls": {
1963                        "spotify": "https://open.spotify.com/artist/4zxvC7CRGvggq9EWXOpwAo"
1964                    },
1965                    "href": "https://api.spotify.com/v1/artists/4zxvC7CRGvggq9EWXOpwAo",
1966                    "id": "4zxvC7CRGvggq9EWXOpwAo",
1967                    "name": "Kiesza",
1968                    "type": "artist",
1969                    "uri": "spotify:artist:4zxvC7CRGvggq9EWXOpwAo"
1970                },
1971                {
1972                    "external_urls": {
1973                        "spotify": "https://open.spotify.com/artist/5c8rdJfIrtDTnRak9cuzwv"
1974                    },
1975                    "href": "https://api.spotify.com/v1/artists/5c8rdJfIrtDTnRak9cuzwv",
1976                    "id": "5c8rdJfIrtDTnRak9cuzwv",
1977                    "name": "Louis Vivet",
1978                    "type": "artist",
1979                    "uri": "spotify:artist:5c8rdJfIrtDTnRak9cuzwv"
1980                }
1981            ],
1982            "disc_number": 1,
1983            "duration_ms": 201999,
1984            "explicit": false,
1985            "external_ids": {
1986                "isrc": "USWB11700345"
1987            },
1988            "external_urls": {
1989                "spotify": "https://open.spotify.com/track/49Ux5DRv82fNGXDO7sIy4y"
1990            },
1991            "href": "https://api.spotify.com/v1/tracks/49Ux5DRv82fNGXDO7sIy4y",
1992            "id": "49Ux5DRv82fNGXDO7sIy4y",
1993            "is_local": false,
1994            "is_playable": true,
1995            "name": "Last Night in the City (feat. Kiesza) - Louis Vivet Remix",
1996            "popularity": 6,
1997            "preview_url": "https://p.scdn.co/mp3-preview/9aa4da8b4c1b17c48a1f8a6f24058ac4e47fdf7b?cid=b800bf59070c4b52a8917d2230d25bdc",
1998            "track_number": 3,
1999            "type": "track",
2000            "uri": "spotify:track:49Ux5DRv82fNGXDO7sIy4y"
2001        },
2002        {
2003            "album": {
2004                "album_type": "SINGLE",
2005                "artists": [
2006                    {
2007                        "external_urls": {
2008                            "spotify": "https://open.spotify.com/artist/65YhYi4Fz5Ibgq7ueev2Rm"
2009                        },
2010                        "href": "https://api.spotify.com/v1/artists/65YhYi4Fz5Ibgq7ueev2Rm",
2011                        "id": "65YhYi4Fz5Ibgq7ueev2Rm",
2012                        "name": "Frederick Delius",
2013                        "type": "artist",
2014                        "uri": "spotify:artist:65YhYi4Fz5Ibgq7ueev2Rm"
2015                    },
2016                    {
2017                        "external_urls": {
2018                            "spotify": "https://open.spotify.com/artist/5Dl3HXZjG6ZOWT5cV375lk"
2019                        },
2020                        "href": "https://api.spotify.com/v1/artists/5Dl3HXZjG6ZOWT5cV375lk",
2021                        "id": "5Dl3HXZjG6ZOWT5cV375lk",
2022                        "name": "Yo-Yo Ma",
2023                        "type": "artist",
2024                        "uri": "spotify:artist:5Dl3HXZjG6ZOWT5cV375lk"
2025                    },
2026                    {
2027                        "external_urls": {
2028                            "spotify": "https://open.spotify.com/artist/7JmDqds7Y1LRSWZVM8e0Og"
2029                        },
2030                        "href": "https://api.spotify.com/v1/artists/7JmDqds7Y1LRSWZVM8e0Og",
2031                        "id": "7JmDqds7Y1LRSWZVM8e0Og",
2032                        "name": "Kathryn Stott",
2033                        "type": "artist",
2034                        "uri": "spotify:artist:7JmDqds7Y1LRSWZVM8e0Og"
2035                    }
2036                ],
2037                "external_urls": {
2038                    "spotify": "https://open.spotify.com/album/5Srtg5Q52DBLYEAIEQBDyH"
2039                },
2040                "href": "https://api.spotify.com/v1/albums/5Srtg5Q52DBLYEAIEQBDyH",
2041                "id": "5Srtg5Q52DBLYEAIEQBDyH",
2042                "images": [
2043                    {
2044                        "height": 640,
2045                        "url": "https://i.scdn.co/image/ab67616d0000b27309516b49c785767fb6193732",
2046                        "width": 640
2047                    },
2048                    {
2049                        "height": 300,
2050                        "url": "https://i.scdn.co/image/ab67616d00001e0209516b49c785767fb6193732",
2051                        "width": 300
2052                    },
2053                    {
2054                        "height": 64,
2055                        "url": "https://i.scdn.co/image/ab67616d0000485109516b49c785767fb6193732",
2056                        "width": 64
2057                    }
2058                ],
2059                "is_playable": true,
2060                "name": "Romance for Cello and Piano",
2061                "release_date": "2015-07-24",
2062                "release_date_precision": "day",
2063                "total_tracks": 1,
2064                "type": "album",
2065                "uri": "spotify:album:5Srtg5Q52DBLYEAIEQBDyH"
2066            },
2067            "artists": [
2068                {
2069                    "external_urls": {
2070                        "spotify": "https://open.spotify.com/artist/65YhYi4Fz5Ibgq7ueev2Rm"
2071                    },
2072                    "href": "https://api.spotify.com/v1/artists/65YhYi4Fz5Ibgq7ueev2Rm",
2073                    "id": "65YhYi4Fz5Ibgq7ueev2Rm",
2074                    "name": "Frederick Delius",
2075                    "type": "artist",
2076                    "uri": "spotify:artist:65YhYi4Fz5Ibgq7ueev2Rm"
2077                },
2078                {
2079                    "external_urls": {
2080                        "spotify": "https://open.spotify.com/artist/7JmDqds7Y1LRSWZVM8e0Og"
2081                    },
2082                    "href": "https://api.spotify.com/v1/artists/7JmDqds7Y1LRSWZVM8e0Og",
2083                    "id": "7JmDqds7Y1LRSWZVM8e0Og",
2084                    "name": "Kathryn Stott",
2085                    "type": "artist",
2086                    "uri": "spotify:artist:7JmDqds7Y1LRSWZVM8e0Og"
2087                },
2088                {
2089                    "external_urls": {
2090                        "spotify": "https://open.spotify.com/artist/5Dl3HXZjG6ZOWT5cV375lk"
2091                    },
2092                    "href": "https://api.spotify.com/v1/artists/5Dl3HXZjG6ZOWT5cV375lk",
2093                    "id": "5Dl3HXZjG6ZOWT5cV375lk",
2094                    "name": "Yo-Yo Ma",
2095                    "type": "artist",
2096                    "uri": "spotify:artist:5Dl3HXZjG6ZOWT5cV375lk"
2097                }
2098            ],
2099            "disc_number": 1,
2100            "duration_ms": 385186,
2101            "explicit": false,
2102            "external_ids": {
2103                "isrc": "USQX91500821"
2104            },
2105            "external_urls": {
2106                "spotify": "https://open.spotify.com/track/6ufaxWhOW87EXsKh5TSxMp"
2107            },
2108            "href": "https://api.spotify.com/v1/tracks/6ufaxWhOW87EXsKh5TSxMp",
2109            "id": "6ufaxWhOW87EXsKh5TSxMp",
2110            "is_local": false,
2111            "is_playable": true,
2112            "linked_from": {
2113                "external_urls": {
2114                    "spotify": "https://open.spotify.com/track/70nMUxP46mAcjW5iRpRiyN"
2115                },
2116                "href": "https://api.spotify.com/v1/tracks/70nMUxP46mAcjW5iRpRiyN",
2117                "id": "70nMUxP46mAcjW5iRpRiyN",
2118                "type": "track",
2119                "uri": "spotify:track:70nMUxP46mAcjW5iRpRiyN"
2120            },
2121            "name": "Romance for Cello and Piano",
2122            "popularity": 33,
2123            "preview_url": "https://p.scdn.co/mp3-preview/59053165aa006169f88b0888a1c2d8e420d5508a?cid=b800bf59070c4b52a8917d2230d25bdc",
2124            "track_number": 11,
2125            "type": "track",
2126            "uri": "spotify:track:6ufaxWhOW87EXsKh5TSxMp"
2127        },
2128        {
2129            "album": {
2130                "album_type": "SINGLE",
2131                "artists": [
2132                    {
2133                        "external_urls": {
2134                            "spotify": "https://open.spotify.com/artist/137W8MRPWKqSmrBGDBFSop"
2135                        },
2136                        "href": "https://api.spotify.com/v1/artists/137W8MRPWKqSmrBGDBFSop",
2137                        "id": "137W8MRPWKqSmrBGDBFSop",
2138                        "name": "Wiz Khalifa",
2139                        "type": "artist",
2140                        "uri": "spotify:artist:137W8MRPWKqSmrBGDBFSop"
2141                    }
2142                ],
2143                "external_urls": {
2144                    "spotify": "https://open.spotify.com/album/3qv4Hjk70y70MNe9Kb9X8f"
2145                },
2146                "href": "https://api.spotify.com/v1/albums/3qv4Hjk70y70MNe9Kb9X8f",
2147                "id": "3qv4Hjk70y70MNe9Kb9X8f",
2148                "images": [
2149                    {
2150                        "height": 640,
2151                        "url": "https://i.scdn.co/image/ab67616d0000b273dfe0748e91928eaf21373018",
2152                        "width": 640
2153                    },
2154                    {
2155                        "height": 300,
2156                        "url": "https://i.scdn.co/image/ab67616d00001e02dfe0748e91928eaf21373018",
2157                        "width": 300
2158                    },
2159                    {
2160                        "height": 64,
2161                        "url": "https://i.scdn.co/image/ab67616d00004851dfe0748e91928eaf21373018",
2162                        "width": 64
2163                    }
2164                ],
2165                "is_playable": true,
2166                "name": "Pull Up (feat. Lil Uzi Vert)",
2167                "release_date": "2016-05-25",
2168                "release_date_precision": "day",
2169                "total_tracks": 1,
2170                "type": "album",
2171                "uri": "spotify:album:3qv4Hjk70y70MNe9Kb9X8f"
2172            },
2173            "artists": [
2174                {
2175                    "external_urls": {
2176                        "spotify": "https://open.spotify.com/artist/137W8MRPWKqSmrBGDBFSop"
2177                    },
2178                    "href": "https://api.spotify.com/v1/artists/137W8MRPWKqSmrBGDBFSop",
2179                    "id": "137W8MRPWKqSmrBGDBFSop",
2180                    "name": "Wiz Khalifa",
2181                    "type": "artist",
2182                    "uri": "spotify:artist:137W8MRPWKqSmrBGDBFSop"
2183                },
2184                {
2185                    "external_urls": {
2186                        "spotify": "https://open.spotify.com/artist/4O15NlyKLIASxsJ0PrXPfz"
2187                    },
2188                    "href": "https://api.spotify.com/v1/artists/4O15NlyKLIASxsJ0PrXPfz",
2189                    "id": "4O15NlyKLIASxsJ0PrXPfz",
2190                    "name": "Lil Uzi Vert",
2191                    "type": "artist",
2192                    "uri": "spotify:artist:4O15NlyKLIASxsJ0PrXPfz"
2193                }
2194            ],
2195            "disc_number": 1,
2196            "duration_ms": 207391,
2197            "explicit": true,
2198            "external_ids": {
2199                "isrc": "USAT21601765"
2200            },
2201            "external_urls": {
2202                "spotify": "https://open.spotify.com/track/6LTsvaebP6V9tJFvZxqi5M"
2203            },
2204            "href": "https://api.spotify.com/v1/tracks/6LTsvaebP6V9tJFvZxqi5M",
2205            "id": "6LTsvaebP6V9tJFvZxqi5M",
2206            "is_local": false,
2207            "is_playable": true,
2208            "name": "Pull Up (feat. Lil Uzi Vert)",
2209            "popularity": 50,
2210            "preview_url": "https://p.scdn.co/mp3-preview/644de9f6fa47954ea3b44748b345a8f5f8d3fdd7?cid=b800bf59070c4b52a8917d2230d25bdc",
2211            "track_number": 1,
2212            "type": "track",
2213            "uri": "spotify:track:6LTsvaebP6V9tJFvZxqi5M"
2214        },
2215        {
2216            "album": {
2217                "album_type": "ALBUM",
2218                "artists": [
2219                    {
2220                        "external_urls": {
2221                            "spotify": "https://open.spotify.com/artist/2KsP6tYLJlTBvSUxnwlVWa"
2222                        },
2223                        "href": "https://api.spotify.com/v1/artists/2KsP6tYLJlTBvSUxnwlVWa",
2224                        "id": "2KsP6tYLJlTBvSUxnwlVWa",
2225                        "name": "Mike Posner",
2226                        "type": "artist",
2227                        "uri": "spotify:artist:2KsP6tYLJlTBvSUxnwlVWa"
2228                    }
2229                ],
2230                "external_urls": {
2231                    "spotify": "https://open.spotify.com/album/6Phl1V5P0sPrWJytXHGFeO"
2232                },
2233                "href": "https://api.spotify.com/v1/albums/6Phl1V5P0sPrWJytXHGFeO",
2234                "id": "6Phl1V5P0sPrWJytXHGFeO",
2235                "images": [
2236                    {
2237                        "height": 640,
2238                        "url": "https://i.scdn.co/image/ab67616d0000b2731db27fa11dbafa67857da8f3",
2239                        "width": 640
2240                    },
2241                    {
2242                        "height": 300,
2243                        "url": "https://i.scdn.co/image/ab67616d00001e021db27fa11dbafa67857da8f3",
2244                        "width": 300
2245                    },
2246                    {
2247                        "height": 64,
2248                        "url": "https://i.scdn.co/image/ab67616d000048511db27fa11dbafa67857da8f3",
2249                        "width": 64
2250                    }
2251                ],
2252                "is_playable": true,
2253                "name": "At Night, Alone.",
2254                "release_date": "2016-05-06",
2255                "release_date_precision": "day",
2256                "total_tracks": 18,
2257                "type": "album",
2258                "uri": "spotify:album:6Phl1V5P0sPrWJytXHGFeO"
2259            },
2260            "artists": [
2261                {
2262                    "external_urls": {
2263                        "spotify": "https://open.spotify.com/artist/2KsP6tYLJlTBvSUxnwlVWa"
2264                    },
2265                    "href": "https://api.spotify.com/v1/artists/2KsP6tYLJlTBvSUxnwlVWa",
2266                    "id": "2KsP6tYLJlTBvSUxnwlVWa",
2267                    "name": "Mike Posner",
2268                    "type": "artist",
2269                    "uri": "spotify:artist:2KsP6tYLJlTBvSUxnwlVWa"
2270                },
2271                {
2272                    "external_urls": {
2273                        "spotify": "https://open.spotify.com/artist/5iNrZmtVMtYev5M9yoWpEq"
2274                    },
2275                    "href": "https://api.spotify.com/v1/artists/5iNrZmtVMtYev5M9yoWpEq",
2276                    "id": "5iNrZmtVMtYev5M9yoWpEq",
2277                    "name": "Seeb",
2278                    "type": "artist",
2279                    "uri": "spotify:artist:5iNrZmtVMtYev5M9yoWpEq"
2280                }
2281            ],
2282            "disc_number": 1,
2283            "duration_ms": 197933,
2284            "explicit": true,
2285            "external_ids": {
2286                "isrc": "USUM71509342"
2287            },
2288            "external_urls": {
2289                "spotify": "https://open.spotify.com/track/0vbtURX4qv1l7besfwmnD8"
2290            },
2291            "href": "https://api.spotify.com/v1/tracks/0vbtURX4qv1l7besfwmnD8",
2292            "id": "0vbtURX4qv1l7besfwmnD8",
2293            "is_local": false,
2294            "is_playable": true,
2295            "name": "I Took A Pill In Ibiza - Seeb Remix",
2296            "popularity": 83,
2297            "preview_url": null,
2298            "track_number": 13,
2299            "type": "track",
2300            "uri": "spotify:track:0vbtURX4qv1l7besfwmnD8"
2301        },
2302        {
2303            "album": {
2304                "album_type": "COMPILATION",
2305                "artists": [
2306                    {
2307                        "external_urls": {
2308                            "spotify": "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of"
2309                        },
2310                        "href": "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of",
2311                        "id": "0LyfQWJT6nXafLPZqxe9Of",
2312                        "name": "Various Artists",
2313                        "type": "artist",
2314                        "uri": "spotify:artist:0LyfQWJT6nXafLPZqxe9Of"
2315                    }
2316                ],
2317                "external_urls": {
2318                    "spotify": "https://open.spotify.com/album/6lJrqUXdCpEINx1fi5EqMa"
2319                },
2320                "href": "https://api.spotify.com/v1/albums/6lJrqUXdCpEINx1fi5EqMa",
2321                "id": "6lJrqUXdCpEINx1fi5EqMa",
2322                "images": [
2323                    {
2324                        "height": 640,
2325                        "url": "https://i.scdn.co/image/ab67616d0000b27333d6ad1275ae8ebe156686f5",
2326                        "width": 640
2327                    },
2328                    {
2329                        "height": 300,
2330                        "url": "https://i.scdn.co/image/ab67616d00001e0233d6ad1275ae8ebe156686f5",
2331                        "width": 300
2332                    },
2333                    {
2334                        "height": 64,
2335                        "url": "https://i.scdn.co/image/ab67616d0000485133d6ad1275ae8ebe156686f5",
2336                        "width": 64
2337                    }
2338                ],
2339                "is_playable": true,
2340                "name": "The Twilight Saga: Breaking Dawn - Part 2 (Original Motion Picture Soundtrack)",
2341                "release_date": "2012-11-09",
2342                "release_date_precision": "day",
2343                "total_tracks": 14,
2344                "type": "album",
2345                "uri": "spotify:album:6lJrqUXdCpEINx1fi5EqMa"
2346            },
2347            "artists": [
2348                {
2349                    "external_urls": {
2350                        "spotify": "https://open.spotify.com/artist/0SbSDzM4X41hnlURed0fcV"
2351                    },
2352                    "href": "https://api.spotify.com/v1/artists/0SbSDzM4X41hnlURed0fcV",
2353                    "id": "0SbSDzM4X41hnlURed0fcV",
2354                    "name": "Carter Burwell",
2355                    "type": "artist",
2356                    "uri": "spotify:artist:0SbSDzM4X41hnlURed0fcV"
2357                }
2358            ],
2359            "disc_number": 1,
2360            "duration_ms": 255773,
2361            "explicit": false,
2362            "external_ids": {
2363                "isrc": "USAT21206056"
2364            },
2365            "external_urls": {
2366                "spotify": "https://open.spotify.com/track/1brH9m4Q2LHTuwxaKoMTn5"
2367            },
2368            "href": "https://api.spotify.com/v1/tracks/1brH9m4Q2LHTuwxaKoMTn5",
2369            "id": "1brH9m4Q2LHTuwxaKoMTn5",
2370            "is_local": false,
2371            "is_playable": true,
2372            "name": "Plus Que Ma Prope Vie",
2373            "popularity": 48,
2374            "preview_url": "https://p.scdn.co/mp3-preview/585cd6ea1265df63d349dcda19035a27893f50d2?cid=b800bf59070c4b52a8917d2230d25bdc",
2375            "track_number": 14,
2376            "type": "track",
2377            "uri": "spotify:track:1brH9m4Q2LHTuwxaKoMTn5"
2378        },
2379        {
2380            "album": {
2381                "album_type": "ALBUM",
2382                "artists": [
2383                    {
2384                        "external_urls": {
2385                            "spotify": "https://open.spotify.com/artist/03r4iKL2g2442PT9n2UKsx"
2386                        },
2387                        "href": "https://api.spotify.com/v1/artists/03r4iKL2g2442PT9n2UKsx",
2388                        "id": "03r4iKL2g2442PT9n2UKsx",
2389                        "name": "Beastie Boys",
2390                        "type": "artist",
2391                        "uri": "spotify:artist:03r4iKL2g2442PT9n2UKsx"
2392                    }
2393                ],
2394                "external_urls": {
2395                    "spotify": "https://open.spotify.com/album/11oR0ZuqB3ucZwb5TGbZxb"
2396                },
2397                "href": "https://api.spotify.com/v1/albums/11oR0ZuqB3ucZwb5TGbZxb",
2398                "id": "11oR0ZuqB3ucZwb5TGbZxb",
2399                "images": [
2400                    {
2401                        "height": 640,
2402                        "url": "https://i.scdn.co/image/ab67616d0000b273a7ea08ab3914c5fb2084a8ac",
2403                        "width": 640
2404                    },
2405                    {
2406                        "height": 300,
2407                        "url": "https://i.scdn.co/image/ab67616d00001e02a7ea08ab3914c5fb2084a8ac",
2408                        "width": 300
2409                    },
2410                    {
2411                        "height": 64,
2412                        "url": "https://i.scdn.co/image/ab67616d00004851a7ea08ab3914c5fb2084a8ac",
2413                        "width": 64
2414                    }
2415                ],
2416                "is_playable": true,
2417                "name": "Licensed To Ill",
2418                "release_date": "1986-11-15",
2419                "release_date_precision": "day",
2420                "total_tracks": 13,
2421                "type": "album",
2422                "uri": "spotify:album:11oR0ZuqB3ucZwb5TGbZxb"
2423            },
2424            "artists": [
2425                {
2426                    "external_urls": {
2427                        "spotify": "https://open.spotify.com/artist/03r4iKL2g2442PT9n2UKsx"
2428                    },
2429                    "href": "https://api.spotify.com/v1/artists/03r4iKL2g2442PT9n2UKsx",
2430                    "id": "03r4iKL2g2442PT9n2UKsx",
2431                    "name": "Beastie Boys",
2432                    "type": "artist",
2433                    "uri": "spotify:artist:03r4iKL2g2442PT9n2UKsx"
2434                }
2435            ],
2436            "disc_number": 1,
2437            "duration_ms": 157440,
2438            "explicit": false,
2439            "external_ids": {
2440                "isrc": "USDJ28600011"
2441            },
2442            "external_urls": {
2443                "spotify": "https://open.spotify.com/track/2tY1gxCKslfXLFpFofYmJQ"
2444            },
2445            "href": "https://api.spotify.com/v1/tracks/2tY1gxCKslfXLFpFofYmJQ",
2446            "id": "2tY1gxCKslfXLFpFofYmJQ",
2447            "is_local": false,
2448            "is_playable": true,
2449            "name": "Brass Monkey",
2450            "popularity": 68,
2451            "preview_url": null,
2452            "track_number": 11,
2453            "type": "track",
2454            "uri": "spotify:track:2tY1gxCKslfXLFpFofYmJQ"
2455        },
2456        {
2457            "album": {
2458                "album_type": "ALBUM",
2459                "artists": [
2460                    {
2461                        "external_urls": {
2462                            "spotify": "https://open.spotify.com/artist/5Q81rlcTFh3k6DQJXPdsot"
2463                        },
2464                        "href": "https://api.spotify.com/v1/artists/5Q81rlcTFh3k6DQJXPdsot",
2465                        "id": "5Q81rlcTFh3k6DQJXPdsot",
2466                        "name": "Mura Masa",
2467                        "type": "artist",
2468                        "uri": "spotify:artist:5Q81rlcTFh3k6DQJXPdsot"
2469                    }
2470                ],
2471                "external_urls": {
2472                    "spotify": "https://open.spotify.com/album/0NBTBo1qrg554sAj79nEqD"
2473                },
2474                "href": "https://api.spotify.com/v1/albums/0NBTBo1qrg554sAj79nEqD",
2475                "id": "0NBTBo1qrg554sAj79nEqD",
2476                "images": [
2477                    {
2478                        "height": 640,
2479                        "url": "https://i.scdn.co/image/ab67616d0000b2736818aa231aa543cf87e1374a",
2480                        "width": 640
2481                    },
2482                    {
2483                        "height": 300,
2484                        "url": "https://i.scdn.co/image/ab67616d00001e026818aa231aa543cf87e1374a",
2485                        "width": 300
2486                    },
2487                    {
2488                        "height": 64,
2489                        "url": "https://i.scdn.co/image/ab67616d000048516818aa231aa543cf87e1374a",
2490                        "width": 64
2491                    }
2492                ],
2493                "is_playable": true,
2494                "name": "Mura Masa",
2495                "release_date": "2017-07-14",
2496                "release_date_precision": "day",
2497                "total_tracks": 13,
2498                "type": "album",
2499                "uri": "spotify:album:0NBTBo1qrg554sAj79nEqD"
2500            },
2501            "artists": [
2502                {
2503                    "external_urls": {
2504                        "spotify": "https://open.spotify.com/artist/5Q81rlcTFh3k6DQJXPdsot"
2505                    },
2506                    "href": "https://api.spotify.com/v1/artists/5Q81rlcTFh3k6DQJXPdsot",
2507                    "id": "5Q81rlcTFh3k6DQJXPdsot",
2508                    "name": "Mura Masa",
2509                    "type": "artist",
2510                    "uri": "spotify:artist:5Q81rlcTFh3k6DQJXPdsot"
2511                },
2512                {
2513                    "external_urls": {
2514                        "spotify": "https://open.spotify.com/artist/7pFeBzX627ff0VnN6bxPR4"
2515                    },
2516                    "href": "https://api.spotify.com/v1/artists/7pFeBzX627ff0VnN6bxPR4",
2517                    "id": "7pFeBzX627ff0VnN6bxPR4",
2518                    "name": "Desiigner",
2519                    "type": "artist",
2520                    "uri": "spotify:artist:7pFeBzX627ff0VnN6bxPR4"
2521                }
2522            ],
2523            "disc_number": 1,
2524            "duration_ms": 164013,
2525            "explicit": true,
2526            "external_ids": {
2527                "isrc": "GBUM71701364"
2528            },
2529            "external_urls": {
2530                "spotify": "https://open.spotify.com/track/4x8874idDYp8yxgKsyb4xG"
2531            },
2532            "href": "https://api.spotify.com/v1/tracks/4x8874idDYp8yxgKsyb4xG",
2533            "id": "4x8874idDYp8yxgKsyb4xG",
2534            "is_local": false,
2535            "is_playable": true,
2536            "name": "All Around The World (feat. Desiigner)",
2537            "popularity": 42,
2538            "preview_url": null,
2539            "track_number": 5,
2540            "type": "track",
2541            "uri": "spotify:track:4x8874idDYp8yxgKsyb4xG"
2542        },
2543        {
2544            "album": {
2545                "album_type": "SINGLE",
2546                "artists": [
2547                    {
2548                        "external_urls": {
2549                            "spotify": "https://open.spotify.com/artist/61lyPtntblHJvA7FMMhi7E"
2550                        },
2551                        "href": "https://api.spotify.com/v1/artists/61lyPtntblHJvA7FMMhi7E",
2552                        "id": "61lyPtntblHJvA7FMMhi7E",
2553                        "name": "Duke Dumont",
2554                        "type": "artist",
2555                        "uri": "spotify:artist:61lyPtntblHJvA7FMMhi7E"
2556                    }
2557                ],
2558                "external_urls": {
2559                    "spotify": "https://open.spotify.com/album/4SQqe6ACemVTNNOcq7Ql4A"
2560                },
2561                "href": "https://api.spotify.com/v1/albums/4SQqe6ACemVTNNOcq7Ql4A",
2562                "id": "4SQqe6ACemVTNNOcq7Ql4A",
2563                "images": [
2564                    {
2565                        "height": 640,
2566                        "url": "https://i.scdn.co/image/ab67616d0000b273be165dd0973a0db9607b3938",
2567                        "width": 640
2568                    },
2569                    {
2570                        "height": 300,
2571                        "url": "https://i.scdn.co/image/ab67616d00001e02be165dd0973a0db9607b3938",
2572                        "width": 300
2573                    },
2574                    {
2575                        "height": 64,
2576                        "url": "https://i.scdn.co/image/ab67616d00004851be165dd0973a0db9607b3938",
2577                        "width": 64
2578                    }
2579                ],
2580                "is_playable": true,
2581                "name": "The Giver (Reprise)",
2582                "release_date": "2015-03-17",
2583                "release_date_precision": "day",
2584                "total_tracks": 1,
2585                "type": "album",
2586                "uri": "spotify:album:4SQqe6ACemVTNNOcq7Ql4A"
2587            },
2588            "artists": [
2589                {
2590                    "external_urls": {
2591                        "spotify": "https://open.spotify.com/artist/61lyPtntblHJvA7FMMhi7E"
2592                    },
2593                    "href": "https://api.spotify.com/v1/artists/61lyPtntblHJvA7FMMhi7E",
2594                    "id": "61lyPtntblHJvA7FMMhi7E",
2595                    "name": "Duke Dumont",
2596                    "type": "artist",
2597                    "uri": "spotify:artist:61lyPtntblHJvA7FMMhi7E"
2598                }
2599            ],
2600            "disc_number": 1,
2601            "duration_ms": 195756,
2602            "explicit": false,
2603            "external_ids": {
2604                "isrc": "GBUM71501517"
2605            },
2606            "external_urls": {
2607                "spotify": "https://open.spotify.com/track/0ccSl4LZ7dksMNmJgkN7NO"
2608            },
2609            "href": "https://api.spotify.com/v1/tracks/0ccSl4LZ7dksMNmJgkN7NO",
2610            "id": "0ccSl4LZ7dksMNmJgkN7NO",
2611            "is_local": false,
2612            "is_playable": true,
2613            "name": "The Giver (Reprise)",
2614            "popularity": 43,
2615            "preview_url": null,
2616            "track_number": 1,
2617            "type": "track",
2618            "uri": "spotify:track:0ccSl4LZ7dksMNmJgkN7NO"
2619        },
2620        {
2621            "album": {
2622                "album_type": "ALBUM",
2623                "artists": [
2624                    {
2625                        "external_urls": {
2626                            "spotify": "https://open.spotify.com/artist/4NHQUGzhtTLFvgF5SZesLK"
2627                        },
2628                        "href": "https://api.spotify.com/v1/artists/4NHQUGzhtTLFvgF5SZesLK",
2629                        "id": "4NHQUGzhtTLFvgF5SZesLK",
2630                        "name": "Tove Lo",
2631                        "type": "artist",
2632                        "uri": "spotify:artist:4NHQUGzhtTLFvgF5SZesLK"
2633                    }
2634                ],
2635                "external_urls": {
2636                    "spotify": "https://open.spotify.com/album/1tuekzsMZQOuiMejKP6t2Y"
2637                },
2638                "href": "https://api.spotify.com/v1/albums/1tuekzsMZQOuiMejKP6t2Y",
2639                "id": "1tuekzsMZQOuiMejKP6t2Y",
2640                "images": [
2641                    {
2642                        "height": 640,
2643                        "url": "https://i.scdn.co/image/ab67616d0000b2739f0c014998bac13d3181474c",
2644                        "width": 640
2645                    },
2646                    {
2647                        "height": 300,
2648                        "url": "https://i.scdn.co/image/ab67616d00001e029f0c014998bac13d3181474c",
2649                        "width": 300
2650                    },
2651                    {
2652                        "height": 64,
2653                        "url": "https://i.scdn.co/image/ab67616d000048519f0c014998bac13d3181474c",
2654                        "width": 64
2655                    }
2656                ],
2657                "is_playable": true,
2658                "name": "Lady Wood",
2659                "release_date": "2016-10-28",
2660                "release_date_precision": "day",
2661                "total_tracks": 12,
2662                "type": "album",
2663                "uri": "spotify:album:1tuekzsMZQOuiMejKP6t2Y"
2664            },
2665            "artists": [
2666                {
2667                    "external_urls": {
2668                        "spotify": "https://open.spotify.com/artist/4NHQUGzhtTLFvgF5SZesLK"
2669                    },
2670                    "href": "https://api.spotify.com/v1/artists/4NHQUGzhtTLFvgF5SZesLK",
2671                    "id": "4NHQUGzhtTLFvgF5SZesLK",
2672                    "name": "Tove Lo",
2673                    "type": "artist",
2674                    "uri": "spotify:artist:4NHQUGzhtTLFvgF5SZesLK"
2675                }
2676            ],
2677            "disc_number": 1,
2678            "duration_ms": 234474,
2679            "explicit": true,
2680            "external_ids": {
2681                "isrc": "SEUM71601201"
2682            },
2683            "external_urls": {
2684                "spotify": "https://open.spotify.com/track/073A1FsNWqMxmdcRMeU57t"
2685            },
2686            "href": "https://api.spotify.com/v1/tracks/073A1FsNWqMxmdcRMeU57t",
2687            "id": "073A1FsNWqMxmdcRMeU57t",
2688            "is_local": false,
2689            "is_playable": true,
2690            "name": "Don’t Talk About It",
2691            "popularity": 39,
2692            "preview_url": null,
2693            "track_number": 8,
2694            "type": "track",
2695            "uri": "spotify:track:073A1FsNWqMxmdcRMeU57t"
2696        },
2697        {
2698            "album": {
2699                "album_type": "SINGLE",
2700                "artists": [
2701                    {
2702                        "external_urls": {
2703                            "spotify": "https://open.spotify.com/artist/6y02TEMv71ArWB2qhIaQ5m"
2704                        },
2705                        "href": "https://api.spotify.com/v1/artists/6y02TEMv71ArWB2qhIaQ5m",
2706                        "id": "6y02TEMv71ArWB2qhIaQ5m",
2707                        "name": "Kaiydo",
2708                        "type": "artist",
2709                        "uri": "spotify:artist:6y02TEMv71ArWB2qhIaQ5m"
2710                    }
2711                ],
2712                "external_urls": {
2713                    "spotify": "https://open.spotify.com/album/0oeJCHQwiz5dQhMuiFlhhM"
2714                },
2715                "href": "https://api.spotify.com/v1/albums/0oeJCHQwiz5dQhMuiFlhhM",
2716                "id": "0oeJCHQwiz5dQhMuiFlhhM",
2717                "images": [
2718                    {
2719                        "height": 640,
2720                        "url": "https://i.scdn.co/image/ab67616d0000b2731927f0378a81361fb80e20d6",
2721                        "width": 640
2722                    },
2723                    {
2724                        "height": 300,
2725                        "url": "https://i.scdn.co/image/ab67616d00001e021927f0378a81361fb80e20d6",
2726                        "width": 300
2727                    },
2728                    {
2729                        "height": 64,
2730                        "url": "https://i.scdn.co/image/ab67616d000048511927f0378a81361fb80e20d6",
2731                        "width": 64
2732                    }
2733                ],
2734                "is_playable": true,
2735                "name": "Fruit Punch",
2736                "release_date": "2016-08-12",
2737                "release_date_precision": "day",
2738                "total_tracks": 1,
2739                "type": "album",
2740                "uri": "spotify:album:0oeJCHQwiz5dQhMuiFlhhM"
2741            },
2742            "artists": [
2743                {
2744                    "external_urls": {
2745                        "spotify": "https://open.spotify.com/artist/6y02TEMv71ArWB2qhIaQ5m"
2746                    },
2747                    "href": "https://api.spotify.com/v1/artists/6y02TEMv71ArWB2qhIaQ5m",
2748                    "id": "6y02TEMv71ArWB2qhIaQ5m",
2749                    "name": "Kaiydo",
2750                    "type": "artist",
2751                    "uri": "spotify:artist:6y02TEMv71ArWB2qhIaQ5m"
2752                }
2753            ],
2754            "disc_number": 1,
2755            "duration_ms": 221622,
2756            "explicit": true,
2757            "external_ids": {
2758                "isrc": "TCACR1606159"
2759            },
2760            "external_urls": {
2761                "spotify": "https://open.spotify.com/track/0lpRp9KzzMbC0w1uiL7H7f"
2762            },
2763            "href": "https://api.spotify.com/v1/tracks/0lpRp9KzzMbC0w1uiL7H7f",
2764            "id": "0lpRp9KzzMbC0w1uiL7H7f",
2765            "is_local": false,
2766            "is_playable": true,
2767            "name": "Fruit Punch",
2768            "popularity": 48,
2769            "preview_url": "https://p.scdn.co/mp3-preview/62b43baeb1993236dfc7e78557996514f64a3d9f?cid=b800bf59070c4b52a8917d2230d25bdc",
2770            "track_number": 1,
2771            "type": "track",
2772            "uri": "spotify:track:0lpRp9KzzMbC0w1uiL7H7f"
2773        },
2774        {
2775            "album": {
2776                "album_type": "SINGLE",
2777                "artists": [
2778                    {
2779                        "external_urls": {
2780                            "spotify": "https://open.spotify.com/artist/21dooacK2WGBB5amYvKyfM"
2781                        },
2782                        "href": "https://api.spotify.com/v1/artists/21dooacK2WGBB5amYvKyfM",
2783                        "id": "21dooacK2WGBB5amYvKyfM",
2784                        "name": "Smokepurpp",
2785                        "type": "artist",
2786                        "uri": "spotify:artist:21dooacK2WGBB5amYvKyfM"
2787                    }
2788                ],
2789                "external_urls": {
2790                    "spotify": "https://open.spotify.com/album/2TeGNWZYaj9yeM0mjiO8zL"
2791                },
2792                "href": "https://api.spotify.com/v1/albums/2TeGNWZYaj9yeM0mjiO8zL",
2793                "id": "2TeGNWZYaj9yeM0mjiO8zL",
2794                "images": [
2795                    {
2796                        "height": 640,
2797                        "url": "https://i.scdn.co/image/ab67616d0000b273069c2ee3bae4205c1fed2981",
2798                        "width": 640
2799                    },
2800                    {
2801                        "height": 300,
2802                        "url": "https://i.scdn.co/image/ab67616d00001e02069c2ee3bae4205c1fed2981",
2803                        "width": 300
2804                    },
2805                    {
2806                        "height": 64,
2807                        "url": "https://i.scdn.co/image/ab67616d00004851069c2ee3bae4205c1fed2981",
2808                        "width": 64
2809                    }
2810                ],
2811                "is_playable": true,
2812                "name": "Nephew (feat. Lil Pump)",
2813                "release_date": "2018-07-27",
2814                "release_date_precision": "day",
2815                "total_tracks": 1,
2816                "type": "album",
2817                "uri": "spotify:album:2TeGNWZYaj9yeM0mjiO8zL"
2818            },
2819            "artists": [
2820                {
2821                    "external_urls": {
2822                        "spotify": "https://open.spotify.com/artist/21dooacK2WGBB5amYvKyfM"
2823                    },
2824                    "href": "https://api.spotify.com/v1/artists/21dooacK2WGBB5amYvKyfM",
2825                    "id": "21dooacK2WGBB5amYvKyfM",
2826                    "name": "Smokepurpp",
2827                    "type": "artist",
2828                    "uri": "spotify:artist:21dooacK2WGBB5amYvKyfM"
2829                },
2830                {
2831                    "external_urls": {
2832                        "spotify": "https://open.spotify.com/artist/3wyVrVrFCkukjdVIdirGVY"
2833                    },
2834                    "href": "https://api.spotify.com/v1/artists/3wyVrVrFCkukjdVIdirGVY",
2835                    "id": "3wyVrVrFCkukjdVIdirGVY",
2836                    "name": "Lil Pump",
2837                    "type": "artist",
2838                    "uri": "spotify:artist:3wyVrVrFCkukjdVIdirGVY"
2839                }
2840            ],
2841            "disc_number": 1,
2842            "duration_ms": 202962,
2843            "explicit": true,
2844            "external_ids": {
2845                "isrc": "USUM71810095"
2846            },
2847            "external_urls": {
2848                "spotify": "https://open.spotify.com/track/67KvputYgCRghvDQYj5FMq"
2849            },
2850            "href": "https://api.spotify.com/v1/tracks/67KvputYgCRghvDQYj5FMq",
2851            "id": "67KvputYgCRghvDQYj5FMq",
2852            "is_local": false,
2853            "is_playable": true,
2854            "linked_from": {
2855                "external_urls": {
2856                    "spotify": "https://open.spotify.com/track/0ibOcbkp2XG46Do8jcy0bL"
2857                },
2858                "href": "https://api.spotify.com/v1/tracks/0ibOcbkp2XG46Do8jcy0bL",
2859                "id": "0ibOcbkp2XG46Do8jcy0bL",
2860                "type": "track",
2861                "uri": "spotify:track:0ibOcbkp2XG46Do8jcy0bL"
2862            },
2863            "name": "Nephew (feat. Lil Pump)",
2864            "popularity": 50,
2865            "preview_url": "https://p.scdn.co/mp3-preview/bc901043dd4bcb1c43f6e7b1642e2d9d93b9539a?cid=b800bf59070c4b52a8917d2230d25bdc",
2866            "track_number": 1,
2867            "type": "track",
2868            "uri": "spotify:track:67KvputYgCRghvDQYj5FMq"
2869        },
2870        {
2871            "album": {
2872                "album_type": "ALBUM",
2873                "artists": [
2874                    {
2875                        "external_urls": {
2876                            "spotify": "https://open.spotify.com/artist/5xtqw2B8z8JGfDYi2eAZHI"
2877                        },
2878                        "href": "https://api.spotify.com/v1/artists/5xtqw2B8z8JGfDYi2eAZHI",
2879                        "id": "5xtqw2B8z8JGfDYi2eAZHI",
2880                        "name": "Sonique",
2881                        "type": "artist",
2882                        "uri": "spotify:artist:5xtqw2B8z8JGfDYi2eAZHI"
2883                    }
2884                ],
2885                "external_urls": {
2886                    "spotify": "https://open.spotify.com/album/4LX27S3cszKEJW84BGa1Ff"
2887                },
2888                "href": "https://api.spotify.com/v1/albums/4LX27S3cszKEJW84BGa1Ff",
2889                "id": "4LX27S3cszKEJW84BGa1Ff",
2890                "images": [
2891                    {
2892                        "height": 640,
2893                        "url": "https://i.scdn.co/image/ab67616d0000b2732b30281b18d808c60135837c",
2894                        "width": 640
2895                    },
2896                    {
2897                        "height": 300,
2898                        "url": "https://i.scdn.co/image/ab67616d00001e022b30281b18d808c60135837c",
2899                        "width": 300
2900                    },
2901                    {
2902                        "height": 64,
2903                        "url": "https://i.scdn.co/image/ab67616d000048512b30281b18d808c60135837c",
2904                        "width": 64
2905                    }
2906                ],
2907                "is_playable": true,
2908                "name": "Hear My Cry",
2909                "release_date": "2000-08-24",
2910                "release_date_precision": "day",
2911                "total_tracks": 13,
2912                "type": "album",
2913                "uri": "spotify:album:4LX27S3cszKEJW84BGa1Ff"
2914            },
2915            "artists": [
2916                {
2917                    "external_urls": {
2918                        "spotify": "https://open.spotify.com/artist/5xtqw2B8z8JGfDYi2eAZHI"
2919                    },
2920                    "href": "https://api.spotify.com/v1/artists/5xtqw2B8z8JGfDYi2eAZHI",
2921                    "id": "5xtqw2B8z8JGfDYi2eAZHI",
2922                    "name": "Sonique",
2923                    "type": "artist",
2924                    "uri": "spotify:artist:5xtqw2B8z8JGfDYi2eAZHI"
2925                }
2926            ],
2927            "disc_number": 1,
2928            "duration_ms": 240866,
2929            "explicit": false,
2930            "external_ids": {
2931                "isrc": "USUR10300602"
2932            },
2933            "external_urls": {
2934                "spotify": "https://open.spotify.com/track/4Y8q64VnhD0vFYy9g2WFpi"
2935            },
2936            "href": "https://api.spotify.com/v1/tracks/4Y8q64VnhD0vFYy9g2WFpi",
2937            "id": "4Y8q64VnhD0vFYy9g2WFpi",
2938            "is_local": false,
2939            "is_playable": true,
2940            "name": "It Feels So Good",
2941            "popularity": 67,
2942            "preview_url": "https://p.scdn.co/mp3-preview/028068f83d3d988b1661c03e93ab0651f6dd5957?cid=b800bf59070c4b52a8917d2230d25bdc",
2943            "track_number": 1,
2944            "type": "track",
2945            "uri": "spotify:track:4Y8q64VnhD0vFYy9g2WFpi"
2946        }
2947    ],
2948    "seeds": [
2949        {
2950            "initialPoolSize": 378,
2951            "afterFilteringSize": 378,
2952            "afterRelinkingSize": 378,
2953            "id": "4NHQUGzhtTLFvgF5SZesLK",
2954            "type": "ARTIST",
2955            "href": "https://api.spotify.com/v1/artists/4NHQUGzhtTLFvgF5SZesLK"
2956        },
2957        {
2958            "initialPoolSize": 400,
2959            "afterFilteringSize": 400,
2960            "afterRelinkingSize": 400,
2961            "id": "0c6xIDDpzE81m2q797ordA",
2962            "type": "TRACK",
2963            "href": "https://api.spotify.com/v1/tracks/0c6xIDDpzE81m2q797ordA"
2964        },
2965        {
2966            "initialPoolSize": 404,
2967            "afterFilteringSize": 404,
2968            "afterRelinkingSize": 404,
2969            "id": "classical",
2970            "type": "GENRE",
2971            "href": null
2972        },
2973        {
2974            "initialPoolSize": 369,
2975            "afterFilteringSize": 369,
2976            "afterRelinkingSize": 369,
2977            "id": "hip-hop",
2978            "type": "GENRE",
2979            "href": null
2980        }
2981    ]
2982}
2983"""
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)