Esempio n. 1
0
def get_saved_tracks(sp: Spotify) -> List[Dict[str, Any]]:
    """Returns the list of tracks saved in user library"""
    tracks = []  # type: List[Dict[str, Any]]
    results = sp.current_user_saved_tracks(limit=50)
    tracks.extend(results["items"])
    while results["next"]:
        results = sp.next(results)
        tracks.extend(results["items"])
    return tracks
    def likedSongsCreateVibe(self, token):
        # Authenticate
        spotifyObject = Spotify(auth=token)
        spotifyUser = spotifyObject.current_user()
        username = spotifyUser['id']

        # create genre dictionary
        genreDict = {}

        # get songs from LikedSongs
        playlistSongs = spotifyObject.current_user_saved_tracks(limit=50)
        pprint(playlistSongs)
        numberOfSongs = int(playlistSongs['total'])
        totalAdded = int(0)
        songObjectsList = []
        songID_List = []
        while (numberOfSongs > totalAdded):
            playlistSongs = spotifyObject.current_user_saved_tracks(limit=50, offset=totalAdded)
            for i in range(0, len(playlistSongs['items'])):
                try:
                    songURI = playlistSongs['items'][i]['track']['uri']
                    songID = playlistSongs['items'][i]['track']['id']
                    songID_List.append(songID)
                    songFeatures = spotifyObject.audio_features(songURI)

                    genreDict = self.genreVibe(spotifyObject=spotifyObject, songId=songID,
                                               genreDict=genreDict)

                    songObj = [songFeatures[0]['acousticness'],
                               songFeatures[0]['danceability'], songFeatures[0]['energy'],
                               songFeatures[0]['instrumentalness'], songFeatures[0]['liveness'],
                               songFeatures[0]['speechiness'],
                               round(songFeatures[0]['tempo'] / 180, 6), songFeatures[0]['valence']]
                    songObjectsList.append(songObj)
                except:
                    print("song was removed from spotify sorry")
            totalAdded = totalAdded + 50

        #Create Clusters and Return Answer
        centroidsAndError = self.KMeansVibe(data=songObjectsList)
        centroidsAndError_GenreDict = [centroidsAndError, genreDict, songID_List]
        return centroidsAndError_GenreDict
Esempio n. 3
0
def get_library(username: str, sp: spotipy.Spotify) -> list:
    print("Getting tracks from user library..")
    trackList = []
    library = sp.current_user_saved_tracks()
    for item in library['items']:
        track = item['track']
        trackList.append(
            dict(id=track['id'],
                 artist=track['artists'][0]['name'],
                 name=track['name']))
    return trackList
Esempio n. 4
0
def __clear_favorites(spot_client: spotipy.Spotify):
    with yaspin(text='Removing favorites...', color='yellow') as spinner:
        while True:
            response = spot_client.current_user_saved_tracks(limit=50)
            if not response:
                break

            favorites = []
            for item in response['items']:
                favorites.append(item['track']['id'])
            if len(favorites) > 0:
                spot_client.current_user_saved_tracks_delete(favorites)
            else:
                break
        spinner.ok('✅ ')
Esempio n. 5
0
def get_unadded_songs(dt_threshold: dt, client: spotipy.Spotify) -> deque:
    """
    finds all songs that were added past the last date
    """
    song_ids = deque()
    chunks, offset = 20, 0
    while True:
        songs_liked = client.current_user_saved_tracks(chunks, offset)
        for song in songs_liked['items']:
            if dt_threshold < dt.strptime(
                    song['added_at'],
                    "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=tz.utc):
                song_ids.append(song['track']['id'])
            else:
                return song_ids
        # edge case: user has less liked songs than the chunk size
        if len(songs_liked['items']) < chunks:
            return song_ids
        offset += chunks
Esempio n. 6
0
def get_library(spotify: spotipy.Spotify):
    """Load library from the users saved songs."""
    try:
        with open("artists.json", "r") as f:
            artists = set(json.load(f))
            artists_loaded = True
    except FileNotFoundError:
        artists_loaded = False
    try:
        with open("songs.json", "r") as f:
            songs = tuple(tuple(song) for song in json.load(f))
            songs_loaded = True
    except FileNotFoundError:
        songs_loaded = False

    if songs_loaded and artists_loaded:
        return artists, songs

    # 50 is max limit for api
    results = get_all(spotify, spotify.current_user_saved_tracks(limit=50))
    if not artists_loaded:
        artists = set()
    if not songs_loaded:
        songs = []
    for result in results:
        track = result["track"]
        artist = track["artists"][0]["name"].lower()
        if not artists_loaded:
            artists.add(artist)

    if not songs_loaded:
        songs = get_songs(results)
        results = get_all(spotify,
                          spotify.user_playlist_tracks(None, INSTR_ID))
        inst_songs = get_songs(results)
        songs = tuple(song for song in songs if song not in inst_songs)

    with open("artists.json", "w") as f:
        json.dump(list(artists), f)
    with open("songs.json", "w") as f:
        json.dump(songs, f)

    return artists, tuple(songs)
Esempio n. 7
0
class SpotifyDumper:
    def __init__(self):
        self.sp = Spotify(auth_manager=SpotifyOAuth(scope="user-library-read"))

    def dump_saved_songs(self, spotify_user_id: str):
        with track_writer() as w:
            for track in self._get_liked_artists():
                w.write_track(track)

    def _get_liked_artists(self) -> Iterable[Track]:
        results = self.sp.current_user_saved_tracks()
        yield from self._consume_all(_parse_saved_tracks_chunk, results)

    def _consume_all(self, parser: Callable[[dict], Iterable[T]],
                     result: dict) -> Iterable[T]:
        yield from parser(result)
        while result['next']:
            result = self.sp.next(result)
            yield from parser(result)
Esempio n. 8
0
class AuthTestSpotipy(unittest.TestCase):
    """
    These tests require user authentication - provide client credentials using
    the following environment variables

    ::

        'SPOTIPY_CLIENT_USERNAME'
        'SPOTIPY_CLIENT_ID'
        'SPOTIPY_CLIENT_SECRET'
        'SPOTIPY_REDIRECT_URI'
    """

    playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
    playlist_new_id = "spotify:playlist:7GlxpQjjxRjmbb3RP2rDqI"
    four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
                   "spotify:track:7IHOIqZUUInxjVkko181PB",
                   "4VrWlk8IQxevMvERoX08iC",
                   "http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]

    two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
                  "spotify:track:7IHOIqZUUInxjVkko181PB"]

    other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
                    "spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
                    "spotify:track:1PB7gRWcvefzu7t3LJLUlf"]

    album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU",
                 "spotify:album:6RTzC0rDbvagTSJLlY7AKl"]

    bad_id = 'BAD_ID'

    @classmethod
    def setUpClass(self):
        if sys.version_info >= (3, 2):
            # >= Python3.2 only
            warnings.filterwarnings(
                "ignore",
                category=ResourceWarning,  # noqa
                message="unclosed.*<ssl.SSLSocket.*>")

        missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))

        if missing:
            raise Exception(
                ('Please set the client credentials for the test application'
                 ' using the following environment variables: {}').format(
                    CCEV.values()))

        self.username = os.getenv(CCEV['client_username'])

        self.scope = (
            'playlist-modify-public '
            'user-library-read '
            'user-follow-read '
            'user-library-modify '
            'user-read-private '
            'user-top-read '
            'user-follow-modify '
            'user-read-recently-played '
            'ugc-image-upload'
        )

        self.token = prompt_for_user_token(self.username, scope=self.scope)

        self.spotify = Spotify(auth=self.token)

    # Helper
    def get_or_create_spotify_playlist(self, playlist_name):
        playlists = self.spotify.user_playlists(self.username)
        while playlists:
            for item in playlists['items']:
                if item['name'] == playlist_name:
                    return item
            playlists = self.spotify.next(playlists)
        return self.spotify.user_playlist_create(
            self.username, playlist_name)

    # Helper
    def get_as_base64(self, url):
        import base64
        return base64.b64encode(requests.get(url).content).decode("utf-8")

    def test_track_bad_id(self):
        try:
            self.spotify.track(self.bad_id)
            self.assertTrue(False)
        except SpotifyException:
            self.assertTrue(True)

    def test_basic_user_profile(self):
        user = self.spotify.user(self.username)
        self.assertTrue(user['id'] == self.username.lower())

    def test_current_user(self):
        user = self.spotify.current_user()
        self.assertTrue(user['id'] == self.username.lower())

    def test_me(self):
        user = self.spotify.me()
        self.assertTrue(user['id'] == self.username.lower())

    def test_user_playlists(self):
        playlists = self.spotify.user_playlists(self.username, limit=5)
        self.assertTrue('items' in playlists)
        self.assertTrue(len(playlists['items']) == 5)

    def test_user_playlist_tracks(self):
        playlists = self.spotify.user_playlists(self.username, limit=5)
        self.assertTrue('items' in playlists)
        for playlist in playlists['items']:
            user = playlist['owner']['id']
            pid = playlist['id']
            results = self.spotify.user_playlist_tracks(user, pid)
            self.assertTrue(len(results['items']) >= 0)

    def test_current_user_saved_albums(self):
        # List
        albums = self.spotify.current_user_saved_albums()
        self.assertTrue(len(albums['items']) > 1)

        # Add
        self.spotify.current_user_saved_albums_add(self.album_ids)

        # Contains
        self.assertTrue(
            self.spotify.current_user_saved_albums_contains(
                self.album_ids) == [
                True, True])

        # Remove
        self.spotify.current_user_saved_albums_delete(self.album_ids)
        albums = self.spotify.current_user_saved_albums()
        self.assertTrue(len(albums['items']) > 1)

    def test_current_user_playlists(self):
        playlists = self.spotify.current_user_playlists(limit=10)
        self.assertTrue('items' in playlists)
        self.assertTrue(len(playlists['items']) == 10)

    def test_user_playlist_follow(self):
        self.spotify.user_playlist_follow_playlist(
            'plamere', '4erXB04MxwRAVqcUEpu30O')
        follows = self.spotify.user_playlist_is_following(
            'plamere', '4erXB04MxwRAVqcUEpu30O', [
                self.spotify.current_user()['id']])

        self.assertTrue(len(follows) == 1, 'proper follows length')
        self.assertTrue(follows[0], 'is following')
        self.spotify.user_playlist_unfollow(
            'plamere', '4erXB04MxwRAVqcUEpu30O')

        follows = self.spotify.user_playlist_is_following(
            'plamere', '4erXB04MxwRAVqcUEpu30O', [
                self.spotify.current_user()['id']])
        self.assertTrue(len(follows) == 1, 'proper follows length')
        self.assertFalse(follows[0], 'is no longer following')

    def test_current_user_saved_tracks(self):
        tracks = self.spotify.current_user_saved_tracks()
        self.assertTrue(len(tracks['items']) > 0)

    def test_current_user_save_and_unsave_tracks(self):
        tracks = self.spotify.current_user_saved_tracks()
        total = tracks['total']
        self.spotify.current_user_saved_tracks_add(self.four_tracks)

        tracks = self.spotify.current_user_saved_tracks()
        new_total = tracks['total']
        self.assertTrue(new_total - total == len(self.four_tracks))

        tracks = self.spotify.current_user_saved_tracks_delete(
            self.four_tracks)
        tracks = self.spotify.current_user_saved_tracks()
        new_total = tracks['total']
        self.assertTrue(new_total == total)

    def test_categories(self):
        response = self.spotify.categories()
        self.assertTrue(len(response['categories']) > 0)

    def test_category_playlists(self):
        response = self.spotify.categories()
        for cat in response['categories']['items']:
            cat_id = cat['id']
            response = self.spotify.category_playlists(category_id=cat_id)
            if len(response['playlists']["items"]) > 0:
                break
        self.assertTrue(True)

    def test_new_releases(self):
        response = self.spotify.new_releases()
        self.assertTrue(len(response['albums']) > 0)

    def test_featured_releases(self):
        response = self.spotify.featured_playlists()
        self.assertTrue(len(response['playlists']) > 0)

    def test_current_user_follows(self):
        response = self.spotify.current_user_followed_artists()
        artists = response['artists']
        self.assertTrue(len(artists['items']) > 0)

    def test_current_user_top_tracks(self):
        response = self.spotify.current_user_top_tracks()
        items = response['items']
        self.assertTrue(len(items) > 0)

    def test_current_user_top_artists(self):
        response = self.spotify.current_user_top_artists()
        items = response['items']
        self.assertTrue(len(items) > 0)

    def test_current_user_recently_played(self):
        # No cursor
        res = self.spotify.current_user_recently_played()
        self.assertTrue(len(res['items']) <= 50)
        played_at = res['items'][0]['played_at']

        # Using `before` gives tracks played before
        res = self.spotify.current_user_recently_played(
            before=res['cursors']['after'])
        self.assertTrue(len(res['items']) <= 50)
        self.assertTrue(res['items'][0]['played_at'] < played_at)
        played_at = res['items'][0]['played_at']

        # Using `after` gives tracks played after
        res = self.spotify.current_user_recently_played(
            after=res['cursors']['before'])
        self.assertTrue(len(res['items']) <= 50)
        self.assertTrue(res['items'][0]['played_at'] > played_at)

    def test_user_playlist_ops(self):
        sp = self.spotify
        # create empty playlist
        playlist = self.get_or_create_spotify_playlist(
            'spotipy-testing-playlist-1')
        playlist_id = playlist['id']

        # remove all tracks from it
        sp.user_playlist_replace_tracks(
            self.username, playlist_id, [])
        playlist = sp.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 0)
        self.assertTrue(len(playlist['tracks']['items']) == 0)

        # add tracks to it
        sp.user_playlist_add_tracks(
            self.username, playlist_id, self.four_tracks)
        playlist = sp.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 4)
        self.assertTrue(len(playlist['tracks']['items']) == 4)

        # remove two tracks from it

        sp.user_playlist_remove_all_occurrences_of_tracks(self.username,
                                                          playlist_id,
                                                          self.two_tracks)
        playlist = sp.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 2)
        self.assertTrue(len(playlist['tracks']['items']) == 2)

        # replace with 3 other tracks
        sp.user_playlist_replace_tracks(self.username,
                                        playlist_id,
                                        self.other_tracks)
        playlist = sp.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 3)
        self.assertTrue(len(playlist['tracks']['items']) == 3)

    def test_playlist(self):
        # New playlist ID
        pl = self.spotify.playlist(self.playlist_new_id)
        self.assertTrue(pl["tracks"]["total"] > 0)

        # Old playlist ID
        pl = self.spotify.playlist(self.playlist)
        self.assertTrue(pl["tracks"]["total"] > 0)

    def test_playlist_tracks(self):
        # New playlist ID
        pl = self.spotify.playlist_tracks(self.playlist_new_id, limit=2)
        self.assertTrue(len(pl["items"]) == 2)
        self.assertTrue(pl["total"] > 0)

        # Old playlist ID
        pl = self.spotify.playlist_tracks(self.playlist, limit=2)
        self.assertTrue(len(pl["items"]) == 2)
        self.assertTrue(pl["total"] > 0)

    def test_playlist_upload_cover_image(self):
        pl1 = self.get_or_create_spotify_playlist('spotipy-testing-playlist-1')
        plid = pl1['uri']
        old_b64 = pl1['images'][0]['url']

        # Upload random dog image
        r = requests.get('https://dog.ceo/api/breeds/image/random')
        dog_base64 = self.get_as_base64(r.json()['message'])
        self.spotify.playlist_upload_cover_image(plid, dog_base64)

        # Image must be different
        pl1 = self.spotify.playlist(plid)
        new_b64 = self.get_as_base64(pl1['images'][0]['url'])
        self.assertTrue(old_b64 != new_b64)

    def test_playlist_cover_image(self):
        pl = self.get_or_create_spotify_playlist('spotipy-testing-playlist-1')
        plid = pl['uri']
        res = self.spotify.playlist_cover_image(plid)

        self.assertTrue(len(res) > 0)
        first_image = res[0]
        self.assertTrue('width' in first_image)
        self.assertTrue('height' in first_image)
        self.assertTrue('url' in first_image)

    def test_user_follows_and_unfollows_artist(self):
        # Initially follows 1 artist
        res = self.spotify.current_user_followed_artists()
        self.assertTrue(res['artists']['total'] == 1)

        # Follow 2 more artists
        artists = ["6DPYiyq5kWVQS4RGwxzPC7", "0NbfKEOTQCcwd6o7wSDOHI"]
        self.spotify.user_follow_artists(artists)
        res = self.spotify.current_user_followed_artists()
        self.assertTrue(res['artists']['total'] == 3)

        # Unfollow these 2 artists
        self.spotify.user_unfollow_artists(artists)
        res = self.spotify.current_user_followed_artists()
        self.assertTrue(res['artists']['total'] == 1)

    def test_user_follows_and_unfollows_user(self):
        # TODO improve after implementing `me/following/contains`
        users = ["11111204", "xlqeojt6n7on0j7coh9go8ifd"]

        # Follow 2 more users
        self.spotify.user_follow_users(users)

        # Unfollow these 2 users
        self.spotify.user_unfollow_users(users)

    def test_deprecated_starred(self):
        pl = self.spotify.user_playlist(self.username)
        self.assertTrue(pl["tracks"] is None)
        self.assertTrue(pl["owner"] is None)

    def test_deprecated_user_playlist(self):
        # Test without user due to change from
        # https://developer.spotify.com/community/news/2018/06/12/changes-to-playlist-uris/
        pl = self.spotify.user_playlist(None, self.playlist)
        self.assertTrue(pl["tracks"]["total"] > 0)

    def test_deprecated_user_playlis(self):
        # Test without user due to change from
        # https://developer.spotify.com/community/news/2018/06/12/changes-to-playlist-uris/
        pl = self.spotify.user_playlist_tracks(None, self.playlist, limit=2)
        self.assertTrue(len(pl["items"]) == 2)
        self.assertTrue(pl["total"] > 0)
Esempio n. 9
0
def main():

    clientRedirect = "http://localhost/"

    username = "******"

    scope = "playlist-read-collaborative " \
            "playlist-read-private " \
            "user-library-read " \
            "playlist-modify-public " \
            "playlist-modify-private"

    token = util.prompt_for_user_token(username, scope, clientID, clientSecret,
                                       clientRedirect)

    spotify = Spotify(auth=token)

    result = spotify.current_user_saved_tracks(offset=0, limit=50)
    data = {}

    songs = {}

    exceptions = ("Depeche Mode", "Grant Miller", "Madonna", "Ministry",
                  "The Beach Boys", "Mickey & Sylvia", "The Clovers",
                  "Village People", "Frank Sinatra", "Rodríguez",
                  "The Bangles", "U2", "UB40", "Tom Petty", "Faces",
                  "Bobby McFerrin", "Dion", "Fancy", "Eddy Huntington",
                  "Michael Jackson", "OutKast", "Gorillaz", "Diddy",
                  "Lipps Inc.", "Chuck Berry", "Marvin Gaye", "The Kinks",
                  "Count Basie", "Player", "Steve Lawrence", "Nelly",
                  "The Killers", "Billy Idol", "Haddaway", "Blondie")
    dontwant = ("Emile Van Krieken")
    '''while result["next"]:
        for track in result["items"]:
            songs.update(track["track"]["name"])
        result = spotify.next(result)

    data = {username: songs}'''
    num = 0
    playlist_id = ""
    for playlist in spotify.current_user_playlists()["items"]:
        if playlist["name"] == "Computer Generated Old 2":
            playlist_id = playlist["id"]

    exceptions_list = []

    while result["next"]:
        for track in result["items"]:
            num = num + 1
            print(num)

            track = track["track"]
            '''songs.update({track["uri"]:
                              {"track": track["name"],
                               "artist": track["artists"][0]["name"],
                               "artist uri": track["artists"][0]["uri"],
                               "album": track["album"]["name"],
                               "album uri": track["album"]["uri"]
                              }
                          })'''

            album = spotify.album(track["album"]["id"])
            '''if (int(album["release_date"][0:4]) < 2000 or track["artists"][0]["name"] in exceptions): #and int(album["release_date"][0:4]) > 2006)\

                    #print(track["uri"])
                    print(track["id"])
                    print(track["name"])
                    spotify.user_playlist_add_tracks("karan.arora.28", playlist_id, [track["uri"]])'''

            if (int(album["release_date"][0:4]) <
                    2006) or track["artists"][0]["name"] in exceptions:
                spotify.user_playlist_add_tracks("karan.arora.28", playlist_id,
                                                 [track["uri"]])

                if track["artists"][0]["name"] not in exceptions_list:
                    exceptions_list.append(track["artists"][0]["name"])

            print(exceptions_list)
            '''else:
                #pid = getPlaylistIDByName(spotify, "Old??")
                pid = "2qSyS6sDfEGSS38cn4GR8U"
                if trackInPlaylist(spotify, track["name"], pid):
                    print(track["name"])
                    print(track["artists"][0]["name"])
                    num = num +1
                    print(num)'''

        result = spotify.next(result)

        #spotify.
        #spotify.user_playlist_create(clientID, "Python Old", False, "")

    #albumuri
    #artist Name and URI
    #when track was added
    #track name and URI

    #From this data, get when album was released, get genres,

    #username -> playlists -> songs -> songs contain all the data about genres and artists, etc.
    '''data = songs
Esempio n. 10
0
class AuthTestSpotipy(unittest.TestCase):
    """
    These tests require user authentication - provide client credentials using the
    following environment variables

    ::

        'SPOTIPY_CLIENT_USERNAME'
        'SPOTIPY_CLIENT_ID'
        'SPOTIPY_CLIENT_SECRET'
        'SPOTIPY_REDIRECT_URI'
    """

    playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
    four_tracks = [
        "spotify:track:6RtPijgfPKROxEzTHNRiDp",
        "spotify:track:7IHOIqZUUInxjVkko181PB", "4VrWlk8IQxevMvERoX08iC",
        "http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"
    ]

    two_tracks = [
        "spotify:track:6RtPijgfPKROxEzTHNRiDp",
        "spotify:track:7IHOIqZUUInxjVkko181PB"
    ]

    other_tracks = [
        "spotify:track:2wySlB6vMzCbQrRnNGOYKa",
        "spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
        "spotify:track:1PB7gRWcvefzu7t3LJLUlf"
    ]

    bad_id = 'BAD_ID'

    @classmethod
    def setUpClass(self):

        missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))

        if missing:
            raise Exception(
                'Please set the client credentials for the test application using the following environment variables: {}'
                .format(CCEV.values()))

        self.username = os.getenv(CCEV['client_username'])

        self.scope = ('playlist-modify-public '
                      'user-library-read '
                      'user-follow-read '
                      'user-library-modify '
                      'user-read-private '
                      'user-top-read')

        self.token = prompt_for_user_token(self.username, scope=self.scope)

        self.spotify = Spotify(auth=self.token)

    def test_track_bad_id(self):
        try:
            track = self.spotify.track(self.bad_id)
            self.assertTrue(False)
        except SpotifyException:
            self.assertTrue(True)

    def test_basic_user_profile(self):
        user = self.spotify.user(self.username)
        self.assertTrue(user['id'] == self.username.lower())

    def test_current_user(self):
        user = self.spotify.current_user()
        self.assertTrue(user['id'] == self.username.lower())

    def test_me(self):
        user = self.spotify.me()
        self.assertTrue(user['id'] == self.username.lower())

    def test_user_playlists(self):
        playlists = self.spotify.user_playlists(self.username, limit=5)
        self.assertTrue('items' in playlists)
        self.assertTrue(len(playlists['items']) == 5)

    def test_user_playlist_tracks(self):
        playlists = self.spotify.user_playlists(self.username, limit=5)
        self.assertTrue('items' in playlists)
        for playlist in playlists['items']:
            user = playlist['owner']['id']
            pid = playlist['id']
            results = self.spotify.user_playlist_tracks(user, pid)
            self.assertTrue(len(results['items']) >= 0)

    def user_playlist_tracks(self,
                             user,
                             playlist_id=None,
                             fields=None,
                             limit=100,
                             offset=0):

        # known API issue currently causes this test to fail
        # the issue is that the API doesn't currently respect the
        # limit paramter

        self.assertTrue(len(playlists['items']) == 5)

    def test_current_user_saved_tracks(self):
        tracks = self.spotify.current_user_saved_tracks()
        self.assertTrue(len(tracks['items']) > 0)

    def test_current_user_saved_albums(self):
        albums = self.spotify.current_user_saved_albums()
        self.assertTrue(len(albums['items']) > 0)

    def test_current_user_playlists(self):
        playlists = self.spotify.current_user_playlists(limit=10)
        self.assertTrue('items' in playlists)
        self.assertTrue(len(playlists['items']) == 10)

    def test_user_playlist_follow(self):
        self.spotify.user_playlist_follow_playlist('plamere',
                                                   '4erXB04MxwRAVqcUEpu30O')
        follows = self.spotify.user_playlist_is_following(
            'plamere', '4erXB04MxwRAVqcUEpu30O',
            [self.spotify.current_user()['id']])

        self.assertTrue(len(follows) == 1, 'proper follows length')
        self.assertTrue(follows[0], 'is following')
        self.spotify.user_playlist_unfollow('plamere',
                                            '4erXB04MxwRAVqcUEpu30O')

        follows = self.spotify.user_playlist_is_following(
            'plamere', '4erXB04MxwRAVqcUEpu30O',
            [self.spotify.current_user()['id']])
        self.assertTrue(len(follows) == 1, 'proper follows length')
        self.assertFalse(follows[0], 'is no longer following')

    def test_current_user_save_and_unsave_tracks(self):
        tracks = self.spotify.current_user_saved_tracks()
        total = tracks['total']

        self.spotify.current_user_saved_tracks_add(self.four_tracks)

        tracks = self.spotify.current_user_saved_tracks()
        new_total = tracks['total']
        self.assertTrue(new_total - total == len(self.four_tracks))

        tracks = self.spotify.current_user_saved_tracks_delete(
            self.four_tracks)
        tracks = self.spotify.current_user_saved_tracks()
        new_total = tracks['total']
        self.assertTrue(new_total == total)

    def test_categories(self):
        response = self.spotify.categories()
        self.assertTrue(len(response['categories']) > 0)

    def test_category_playlists(self):
        response = self.spotify.categories()
        for cat in response['categories']['items']:
            cat_id = cat['id']
            response = self.spotify.category_playlists(category_id=cat_id)
            if len(response['playlists']["items"]) > 0:
                break
        self.assertTrue(True)

    def test_new_releases(self):
        response = self.spotify.new_releases()
        self.assertTrue(len(response['albums']) > 0)

    def test_featured_releases(self):
        response = self.spotify.featured_playlists()
        self.assertTrue(len(response['playlists']) > 0)

    def test_current_user_follows(self):
        response = self.spotify.current_user_followed_artists()
        artists = response['artists']
        self.assertTrue(len(artists['items']) > 0)

    def test_current_user_top_tracks(self):
        response = self.spotify.current_user_top_tracks()
        items = response['items']
        self.assertTrue(len(items) > 0)

    def test_current_user_top_artists(self):
        response = self.spotify.current_user_top_artists()
        items = response['items']
        self.assertTrue(len(items) > 0)

    def get_or_create_spotify_playlist(self, playlist_name):
        playlists = self.spotify.user_playlists(self.username)
        while playlists:
            for item in playlists['items']:
                if item['name'] == playlist_name:
                    return item['id']
            playlists = self.spotify.next(playlists)
        playlist = self.spotify.user_playlist_create(self.username,
                                                     playlist_name)
        playlist_id = playlist['uri']
        return playlist_id

    def test_user_playlist_ops(self):
        # create empty playlist
        playlist_id = self.get_or_create_spotify_playlist(
            'spotipy-testing-playlist-1')

        # remove all tracks from it

        self.spotify.user_playlist_replace_tracks(self.username, playlist_id,
                                                  [])

        playlist = self.spotify.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 0)
        self.assertTrue(len(playlist['tracks']['items']) == 0)

        # add tracks to it

        self.spotify.user_playlist_add_tracks(self.username, playlist_id,
                                              self.four_tracks)
        playlist = self.spotify.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 4)
        self.assertTrue(len(playlist['tracks']['items']) == 4)

        # remove two tracks from it

        self.spotify.user_playlist_remove_all_occurrences_of_tracks(
            self.username, playlist_id, self.two_tracks)

        playlist = self.spotify.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 2)
        self.assertTrue(len(playlist['tracks']['items']) == 2)

        # replace with 3 other tracks
        self.spotify.user_playlist_replace_tracks(self.username, playlist_id,
                                                  self.other_tracks)

        playlist = self.spotify.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 3)
        self.assertTrue(len(playlist['tracks']['items']) == 3)
Esempio n. 11
0
import spotipy.util as util
from spotipy import Spotify
from youtube_dl import YoutubeDL
import os

username = os.environ.get('SPOTIFY_USERNAME')
scope = 'user-library-read'
client_id = os.environ.get('CLIENT_ID')
client_secret = os.environ.get('CLIENT_SECRET')

token = util.prompt_for_user_token(username, scope, client_id=client_id, client_secret=client_secret,\
     redirect_uri='http://localhost:5000')

sp = Spotify(auth=token)

saved_tracks = sp.current_user_saved_tracks(limit=20)

songs = list()

while saved_tracks:
    for track in saved_tracks['items']:
        name = track['track']['name']
        artists = list()
        for artist in track['track']['artists']:
            artists.append(artist['name'])
        songs.append(name + ' ' + ' '.join(artists))
        print('done....')
    if saved_tracks['next']:
        saved_tracks = sp.next(saved_tracks)
    else:
        saved_tracks = None
class SpotifySubscriber:
    """
    Main class. Description necessary.

    Default storage dir: ../storage
    """
    def __init__(
        self,
        user_id: str = None,
        storage_dir: str = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), "storage"),
    ):
        self.user_id: str = user_id

        # Playlists are stored by ID in dictionaries for quick lookup
        self.user_playlists: dict = {}
        self.followed_playlists: dict = {}
        self.subscribed_playlists: dict = {}

        # This is the playlist in which all new songs will be pushed
        self.subscription_feed: SubscriptionFeed = None

        loaded = False
        save_path = os.path.join(storage_dir, "storage.p")
        # If a save file exists, load it.
        if os.path.isfile(save_path):
            self._load(save_path)
            loaded = True

        # Since we need the user_id, we cannot continue if it was not specified and we did not obtain it from a save file.
        elif user_id is None:
            raise Exception(
                "No save file found and no user_id specified! Please specify user_id."
            )

        # If there is no save file, there may not be a storage directory either
        elif not os.path.isdir(storage_dir):
            os.mkdir(storage_dir)

        # We deliberately set these after loading, so they may be updated if we move the save file to a different location.
        self.storage_dir = storage_dir
        self._save_path = save_path
        self._cache_path = os.path.join(self.storage_dir,
                                        ".cache-{}".format(self.user_id))
        self._feed_log_path = os.path.join(self.storage_dir, "feed_log.npy")

        # If no save file exists, load the client secret and ID from file so that we can request a token.
        if not loaded:
            self._load_client_secrets()

        # Refresh token and create spotify object
        self.token = self._get_token(self.user_id)
        self.sp = Spotify(auth=self.token)

        # If not loaded from save file, perform initial setup
        if not loaded:
            if self.user_id != "jneeven":
                self._follow_user("jneeven")

            self.subscription_feed = SubscriptionFeed(self.sp, self.user_id)
            self.refresh_user_playlists()
            self._save()

    # Load a token from the cache or request one from the spotify API. Will open the browser to ask for permission if necessary.
    def _get_token(self, username: str):
        """
        Alternatively, I can set these variables using the command line too:
        export SPOTIPY_CLIENT_ID='your-spotify-client-id'
        export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
        export SPOTIPY_REDIRECT_URI='your-app-redirect-url'
        """
        scopes = " ".join([
            "user-read-recently-played",
            "user-library-modify",
            "playlist-read-private",
            "playlist-modify-public",
            "playlist-modify-private",
            "user-library-read",
            "playlist-read-collaborative",
            "user-read-playback-state",
            "user-follow-read",
            "user-top-read",
            "user-read-currently-playing",
            "user-follow-modify",
        ])

        token = sp_util.prompt_for_user_token(
            username,
            scopes,
            client_id=self._client_id,
            client_secret=self._client_secret,
            redirect_uri="http://localhost",
            cache_path=self._cache_path,
        )
        return token

    # Load the client secret and ID from client_data.json
    def _load_client_secrets(self):
        data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                 "client_data.json")
        if not os.path.isfile(data_path):
            raise FileNotFoundError(
                "client_data.json does not exist in src folder!")

        with open(data_path, "r") as data_file:
            info = json.load(data_file)

        self._client_id = info["client_id"]
        self._client_secret = info["client_secret"]

    # Save the entire object to a storage file
    def _save(self):
        pickle.dump(self, open(self._save_path, "wb"))

    # Load the storage file and overwrite the current object attributes
    def _load(self, save_path: str):
        load_obj = pickle.load(open(save_path, "rb"))

        # Overwrite own attributes with the ones we just loaded
        for attr, val in load_obj.__dict__.items():
            self.__dict__[attr] = val

    # Obtain the playlists the user owns or follows (both private and public)
    def refresh_user_playlists(self):
        self.user_playlists = {}
        self.followed_playlists = {}

        # Only obtains 50 playlists at a time, is API limit
        playlists_data = self.sp.user_playlists(self.user_id)

        while playlists_data:
            for playlist in playlists_data["items"]:
                # If we own a playlist but it's collaborative, we treat it as a followed one since we might be interested in updates.
                if playlist["owner"]["id"] != self.user_id or playlist[
                        "collaborative"]:
                    self.followed_playlists[playlist["id"]] = playlist
                else:
                    self.user_playlists[playlist["id"]] = playlist

            # If there were more playlists than we just received, query the next batch
            if playlists_data["next"]:
                playlists_data = self.sp.next(playlists_data)
            else:
                break

    # Subscribe to multiple playlists based on their ID or patterns in their names.
    def subscribe_to_playlists(self,
                               playlist_ids: list = [],
                               contains: list = []):
        new_subscriptions = False

        for playlist_id in playlist_ids:
            if playlist_id not in self.followed_playlists.keys():
                raise Exception(
                    "Cannot subscribe to playlist with id {}. Either the user owns it or does not follow it."
                    .format(playlist_id))

            if playlist_id not in self.subscribed_playlists.keys():
                playlist = self.followed_playlists[playlist_id]
                tracks = self._get_playlist_tracks(playlist["owner"]["id"],
                                                   playlist_id)
                self.subscribed_playlists[playlist_id] = SubscribedPlaylist(
                    playlist, tracks)
                new_subscriptions = True
                safe_print("Subscribed to playlist {} by {}".format(
                    playlist["name"], playlist["owner"]["id"]))

        # Lowercase pattern matching with the playlist name
        for pattern in contains:
            pattern = pattern.lower()
            for playlist in self.followed_playlists.values():
                if (pattern in playlist["name"].lower() and playlist["id"]
                        not in self.subscribed_playlists.keys()):
                    tracks = self._get_playlist_tracks(playlist["owner"]["id"],
                                                       playlist["id"])
                    self.subscribed_playlists[
                        playlist["id"]] = SubscribedPlaylist(playlist, tracks)
                    new_subscriptions = True
                    safe_print("Subscribed to playlist {} by {}".format(
                        playlist["name"], playlist["owner"]["id"]))

        # Only save if we actually changed something. TODO: Save these in a separate file.
        if new_subscriptions:
            self._save()

    # Unsubscribe from multiple playlists based on their ID or patterns in their names.
    def unsubscribe_from_playlists(self,
                                   playlist_ids: list = [],
                                   contains: list = []):
        removed_subscriptions = False

        for playlist_id in playlist_ids:
            if playlist_id not in self.subscribed_playlists.keys():
                raise Exception(
                    "Cannot unsubscribe from playlist with id {}, because the user is not subscripted to it."
                    .format(playlist_id))

            playlist = self.subscribed_playlists[playlist_id]
            removed_subscriptions = True
            safe_print("Unsubscribed from playlist {} by {}".format(
                playlist.name, playlist.owner_id))
            del self.subscribed_playlists[playlist_id]

        # Lowercase pattern matching with the playlist name
        subscribed_playlists = list(self.subscribed_playlists.values())
        for pattern in contains:
            pattern = pattern.lower()
            for playlist in subscribed_playlists:
                if pattern in playlist.name.lower():
                    removed_subscriptions = True
                    safe_print("Unsubscribed from playlist {} by {}".format(
                        playlist.name, playlist.owner_id))
                    del self.subscribed_playlists[playlist.id]

        # Only save if we actually changed something. TODO: Save these in a separate file.
        if removed_subscriptions:
            self._save()

    # Print an overview of the playlist the user owns, follows and is subscribed to.
    def print_playlists(self, own=False, follow=False, subscribed=True):
        if own:
            safe_print("Own playlists:")
            for playlist in self.user_playlists.values():
                safe_print(playlist["name"])

        if follow:
            safe_print("\nFollowed playlists:")
            for playlist in self.followed_playlists.values():
                safe_print(playlist["name"], playlist["owner"]["id"])

        if subscribed:
            safe_print("\nCurrently subscribed to the following playlists:")
            for playlist in self.subscribed_playlists.values():
                safe_print(playlist)

        safe_print()

    # Check the subscribed playlists for new songs and add them to the feed list.
    def update_feed(self, add_own=False):
        """
        Add_own denotes whether to add songs that the user added to a playlist themselves.
        This may happen for example in collaborative playlists.
        """

        last_update = self.subscription_feed.last_update

        track_ids = []
        num_added_tracks = 0

        for playlist_id, playlist in self.subscribed_playlists.items():
            # safe_print("Checking playlist {}".format(playlist.name))
            new_tracks, snapshot = self._get_playlist_tracks(
                playlist.owner_id,
                playlist_id,
                min_timestamp=last_update,
                compare_snapshot=playlist.snapshot_id,
                return_snapshot=True,
            )
            # Update the playlist snapshot so that we quickly know if it has changed next time
            playlist.snapshot_id = snapshot

            added = 0
            for track in new_tracks:
                if track.id == None:
                    print(f"Track with id None: {track}")
                if add_own or track.added_by != self.user_id:
                    try:
                        # Only add the track if it wasn't already in the list when we subbed
                        if track.id not in playlist.track_ids.keys():
                            track_ids.append(track.id)
                            # Add the ID to the track ID list so we know not to add it in the future
                            playlist.track_ids[track.id] = datetime.utcnow()
                            added += 1
                    # TODO: correctly upgrade objects if storage consists of SubscribedPlaylists without ID list.
                    except AttributeError:
                        track_ids.append(track.id)
                        added += 1

            if added > 0:
                safe_print("Obtained {} new tracks from playlist {}!".format(
                    added, playlist.name))

        if len(track_ids) > 0:
            unique_ids = np.unique(track_ids)

            # If a feed log exists, filter all track IDs that have already been added to the feed before.
            if os.path.exists(self._feed_log_path):
                feed_log = pickle.load(open(self._feed_log_path, "rb"))
                filtered_indices = np.where(
                    ~np.isin(unique_ids, feed_log["track_ids"]))
                unique_ids = unique_ids[filtered_indices]

            # We can add at most 100 tracks to a playlist in a single request.
            if unique_ids.size <= 100:
                self.sp.user_playlist_add_tracks(self.user_id,
                                                 self.subscription_feed.id,
                                                 unique_ids)
            else:
                # Split array into near-equal sections that are smaller than 100 tracks
                for id_array in np.array_split(
                        unique_ids,
                        np.ceil(unique_ids.size / 100).astype(int)):
                    self.sp.user_playlist_add_tracks(self.user_id,
                                                     self.subscription_feed.id,
                                                     id_array)

            num_added_tracks = unique_ids.size
            self._log_feed_updates(unique_ids)

        # Update the timestamp and save to file
        self.subscription_feed.last_update = datetime.utcnow()
        self._save()

        return num_added_tracks

    # Get all tracks in the specified playlist, added after min_timestamp.
    # If snapshot is provided, ignore playlists of which the snapshot hasn't changed.
    def _get_playlist_tracks(
        self,
        playlist_owner_id: str,
        playlist_id: str,
        min_timestamp: datetime = None,
        compare_snapshot: str = None,
        return_snapshot=False,
    ):
        data = self.sp.user_playlist(playlist_owner_id,
                                     playlist_id,
                                     fields="tracks, snapshot_id")

        return_tracks = []
        if not min_timestamp:
            min_timestamp = datetime.fromtimestamp(0)

        # If the snapshot is still the same, there is nothing interesting for us to see.
        # NOTE: certain playlists like 'Brain Food' seem to have a different snapshot every time.
        if compare_snapshot and data["snapshot_id"] == compare_snapshot:
            # safe_print("Snapshot still the same, ignoring list contents.")
            return [], data["snapshot_id"]

        tracks = data["tracks"]
        while tracks:
            for track in tracks["items"]:
                added_at = track["added_at"]

                # Somehow, it's possible that we receive an empty track. IDK if this is a spotipy bug or what
                if track["track"] is None or track["track"]["id"] is None:
                    print("WARNING: encountered None track! Ignoring.")
                    continue

                timestamp = datetime.strptime(added_at, "%Y-%m-%dT%H:%M:%SZ")
                if timestamp > min_timestamp:
                    return_tracks.append(Track(track, playlist_id))
                    # safe_print("Found track with name {} and timestamp {} ( > {})".format(track_name, timestamp, min_timestamp))

            if tracks["next"]:
                tracks = self.sp.next(tracks)
            else:
                break

        if return_snapshot:
            return return_tracks, data["snapshot_id"]

        return return_tracks

    # Get all tracks from the users library and own playlists (including sub feed).
    def _get_all_user_tracks(self):
        tracks = {}

        self._get_user_library_tracks()

        for playlist_id, playlist in self.user_playlists.items():
            tracks = self._get_playlist_tracks(playlist["owner"]["id"],
                                               playlist_id)
            for track in tracks:
                tracks[track.id] = track

    def _get_user_library_tracks(self):
        tracks = {}

        data = self.sp.current_user_saved_tracks()

        while data:
            for track in data["items"]:
                print(track["track"].keys())
            exit(0)
            exit(0)
            # for playlist in playlists_data['items']:
            #     # If we own a playlist but it's collaborative, we treat it as a followed one since we might be interested in updates.
            #     if playlist['owner']['id'] != self.user_id or playlist['collaborative']:
            #         self.followed_playlists[playlist['id']] = playlist
            #     else:
            #         self.user_playlists[playlist['id']] = playlist

            # # If there were more playlists than we just received, query the next batch
            # if playlists_data['next']:
            #     playlists_data = self.sp.next(playlists_data)
            # else:
            #     break

    # Store the track ids we just added to the feed in the log file.
    def _log_feed_updates(self, track_ids: np.ndarray):
        """
        Log is dict with the following info:
            track_ids: numpy array of track ids that were added to the feed
            timestamps: timestamp at which each of the tracks was added to the feed
        """
        if os.path.exists(self._feed_log_path):
            feed_log = pickle.load(open(self._feed_log_path, "rb"))
        else:
            feed_log = {"track_ids": [], "timestamps": []}

        # Create, append and overwrite timestamps
        new_timestamps = np.repeat(datetime.utcnow(), track_ids.size)
        timestamp_array = np.append(feed_log["timestamps"], new_timestamps)
        feed_log["timestamps"] = timestamp_array

        # Append and overwrite track_ids
        track_id_array = np.append(feed_log["track_ids"], track_ids)
        feed_log["track_ids"] = track_id_array

        pickle.dump(feed_log, open(self._feed_log_path, "wb"))

    # Print the tracks and timestamps saved in the feed log.
    def print_feed_log(self):
        if not os.path.exists(self._feed_log_path):
            print("No feed log exists yet!")
            return

        feed_log = pickle.load(open(self._feed_log_path, "rb"))
        num_tracks = len(feed_log["track_ids"])
        print("Found {} tracks in log.".format(num_tracks))

        batch_size = 50
        tracks = []
        start_idx = 0
        print("Requesting track info...")
        for start_idx in tqdm(range(0, num_tracks, batch_size)):
            end_idx = start_idx + batch_size
            track_ids = feed_log["track_ids"][start_idx:end_idx]
            tracks += self.sp.tracks(track_ids)["tracks"]
            start_idx = end_idx

        for track, timestamp in zip(tracks, feed_log["timestamps"]):
            safe_print("{} - {} - {} - {}".format(track["artists"][0]["name"],
                                                  track["name"], timestamp,
                                                  track["id"]))

    # Follow a user
    def _follow_user(self, username: str):
        self.sp.user_follow_users([username])

    """    STUBS
Esempio n. 13
0
class SpotifyTracks:
    def __init__(self):
        self.spotify = Spotify(auth=client_manager.get_token)

    def get_cleaned_tracks_data(self, results):
        ''' Get useful information from the results

        Parameters:
            - results: json/dictionary containing tracks data
        '''
        songs = []
        for item in results['items']:
            track = item['track'] if 'track' in item else item

            album = track['album']['name']
            artist = track['artists'][0]['name']
            title = track['name']
            image = track['album']['images'][0]['url']
            songs.append(Song(title, artist, album, image))

        return songs

    def get_playlist_tracks(self, playlist_id):
        ''' Get a list of tracks of a playlist.

        Parameters:
            - playlist_id: the id of the playlist
        '''
        query = f"https://api.spotify.com/v1/playlists/{playlist_id}/tracks"
        response = requests.get(url=query,
                                headers={
                                    "Content-Type":
                                    "application/json",
                                    "Authorization":
                                    f'Bearer {client_manager.get_token}'
                                })

        results = response.json()
        return self.get_cleaned_tracks_data(results)

    def get_user_saved_tracks(self, limit=10):
        ''' Get a list of the user saved tracks.

        Parameters:
            - playlist_id: the id of the playlist
            - limit: the number of tracks to return (max=50, default=10)
        '''
        offset = 0
        saved_tracks = []
        while offset < limit:
            results = self.spotify.current_user_saved_tracks(limit=50,
                                                             offset=offset)
            partial_results = self.get_cleaned_tracks_data(results)

            if not partial_results:
                break

            saved_tracks += partial_results
            offset += 50

        return saved_tracks

    def search_track(self, artist_name, song_name):
        ''' Get a particular track info

        Parameters:
            - artist_name: the name of the artist
            - song_name: the name of the song
        '''
        results = self.spotify.search(
            q=f'artist:{artist_name} track:{song_name}', type='track', limit=1)

        return self.get_cleaned_tracks_data(results['tracks'])
Esempio n. 14
0
class SpotifyTracks:
    def __init__(self):
        self.spotify = Spotify(auth=token)

    def get_cleaned_track_data(self, item: dict) -> Union[Song, None]:
        ''' Get required useful information from the results
        Eg: Title, artist, album, imgurl

        Parameters:
            - item: json/dictionary containing track data
        '''
        try:
            track = item['track'] if 'track' in item else item
            album = track['album']['name']
            artist = track['artists'][0]['name']
            title = track['name']
            imgurl = track['album']['images'][0]['url']
            return Song(vidurl=None,
                        title=title,
                        artist=artist,
                        album=album,
                        imgurl=imgurl)

        except Exception as e:
            print(e)
            return None

    def get_playlist_tracks(self,
                            playlist_id: str,
                            limit: int = None) -> Iterator[Song]:
        ''' Get a list of tracks of a playlist.

        Parameters:
            - playlist_id: the id of the playlist
        '''
        offset = 0
        if limit is None:
            limit = 10000

        fetched = 0
        while offset < limit:
            query = f"https://api.spotify.com/v1/playlists/{playlist_id}/tracks?offset={offset}&limit=50"
            response = requests.get(url=query,
                                    headers={
                                        "Content-Type": "application/json",
                                        "Authorization": f'Bearer {token}'
                                    })

            results = response.json()
            if not response.ok:
                break

            if "items" not in results or not results["items"]:
                return

            for item in results['items']:
                fetched += 1
                yield self.get_cleaned_track_data(item)

                if fetched >= limit:
                    return

            offset += 50

    def get_user_saved_tracks(self, limit: int = None) -> Iterator[Song]:
        ''' Get a list of the user saved tracks.

        Parameters:
            - playlist_id: the id of the playlist
            - limit: the number of tracks to return. defualt: gets all liked songs
        '''
        offset = 0
        if limit is None:
            limit = 10000

        fetched = 0
        while offset < limit:
            results = self.spotify.current_user_saved_tracks(offset=offset,
                                                             limit=50)

            if "items" not in results or not results["items"]:
                return

            for item in results['items']:
                fetched += 1
                yield self.get_cleaned_track_data(item)

                if fetched >= limit:
                    return

            offset += 50

    def search_track(self, artist_name: str, song_name: str) -> Song:
        ''' Get a particular track info

        Parameters:
            - artist_name: the name of the artist
            - song_name: the name of the song
        '''
        results = self.spotify.search(
            q=f'artist:{artist_name} track:{song_name}', type='track', limit=1)

        return self.get_cleaned_track_data(results['tracks']['items'][0])
Esempio n. 15
0
class AuthTestSpotipy(unittest.TestCase):
    """
    These tests require user authentication - provide client credentials using
    the following environment variables

    ::

        'SPOTIPY_CLIENT_USERNAME'
        'SPOTIPY_CLIENT_ID'
        'SPOTIPY_CLIENT_SECRET'
        'SPOTIPY_REDIRECT_URI'
    """

    playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
    playlist_new_id = "spotify:playlist:7GlxpQjjxRjmbb3RP2rDqI"
    four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
                   "spotify:track:7IHOIqZUUInxjVkko181PB",
                   "4VrWlk8IQxevMvERoX08iC",
                   "http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]

    two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
                  "spotify:track:7IHOIqZUUInxjVkko181PB"]

    other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
                    "spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
                    "spotify:track:1PB7gRWcvefzu7t3LJLUlf"]

    album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU",
                 "spotify:album:6RTzC0rDbvagTSJLlY7AKl"]

    bad_id = 'BAD_ID'

    @classmethod
    def setUpClass(self):

        missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))

        if missing:
            raise Exception(
                ('Please set the client credentials for the test application'
                 ' using the following environment variables: {}').format(
                    CCEV.values()))

        self.username = os.getenv(CCEV['client_username'])

        self.scope = (
            'playlist-modify-public '
            'user-library-read '
            'user-follow-read '
            'user-library-modify '
            'user-read-private '
            'user-top-read '
            'user-follow-modify'
        )

        self.token = prompt_for_user_token(self.username, scope=self.scope)

        self.spotify = Spotify(auth=self.token)

    def test_track_bad_id(self):
        try:
            self.spotify.track(self.bad_id)
            self.assertTrue(False)
        except SpotifyException:
            self.assertTrue(True)

    def test_basic_user_profile(self):
        user = self.spotify.user(self.username)
        self.assertTrue(user['id'] == self.username.lower())

    def test_current_user(self):
        user = self.spotify.current_user()
        self.assertTrue(user['id'] == self.username.lower())

    def test_me(self):
        user = self.spotify.me()
        self.assertTrue(user['id'] == self.username.lower())

    def test_user_playlists(self):
        playlists = self.spotify.user_playlists(self.username, limit=5)
        self.assertTrue('items' in playlists)
        self.assertTrue(len(playlists['items']) == 5)

    def test_user_playlist_tracks(self):
        playlists = self.spotify.user_playlists(self.username, limit=5)
        self.assertTrue('items' in playlists)
        for playlist in playlists['items']:
            user = playlist['owner']['id']
            pid = playlist['id']
            results = self.spotify.user_playlist_tracks(user, pid)
            self.assertTrue(len(results['items']) >= 0)

    # known API issue currently causes this test to fail
    # the issue is that the API doesn't currently respect the
    # limit parameter
    # def user_playlist_tracks(self, user, playlist_id=None, fields=None,
    #                          limit=100, offset=0):
    #     self.assertTrue(len(playlists['items']) == 5)

    def test_current_user_saved_albums(self):
        # List
        albums = self.spotify.current_user_saved_albums()
        self.assertTrue(len(albums['items']) == 1)

        # Add
        self.spotify.current_user_saved_albums_add(self.album_ids)

        # Contains
        self.assertTrue(
            self.spotify.current_user_saved_albums_contains(
                self.album_ids) == [
                True, True])

        # Remove
        self.spotify.current_user_saved_albums_delete(self.album_ids)
        albums = self.spotify.current_user_saved_albums()
        self.assertTrue(len(albums['items']) == 1)

    def test_current_user_playlists(self):
        playlists = self.spotify.current_user_playlists(limit=10)
        self.assertTrue('items' in playlists)
        self.assertTrue(len(playlists['items']) == 10)

    def test_user_playlist_follow(self):
        self.spotify.user_playlist_follow_playlist(
            'plamere', '4erXB04MxwRAVqcUEpu30O')
        follows = self.spotify.user_playlist_is_following(
            'plamere', '4erXB04MxwRAVqcUEpu30O', [
                self.spotify.current_user()['id']])

        self.assertTrue(len(follows) == 1, 'proper follows length')
        self.assertTrue(follows[0], 'is following')
        self.spotify.user_playlist_unfollow(
            'plamere', '4erXB04MxwRAVqcUEpu30O')

        follows = self.spotify.user_playlist_is_following(
            'plamere', '4erXB04MxwRAVqcUEpu30O', [
                self.spotify.current_user()['id']])
        self.assertTrue(len(follows) == 1, 'proper follows length')
        self.assertFalse(follows[0], 'is no longer following')

    def test_current_user_saved_tracks(self):
        tracks = self.spotify.current_user_saved_tracks()
        self.assertTrue(len(tracks['items']) > 0)

    def test_current_user_save_and_unsave_tracks(self):
        tracks = self.spotify.current_user_saved_tracks()
        total = tracks['total']
        self.spotify.current_user_saved_tracks_add(self.four_tracks)

        tracks = self.spotify.current_user_saved_tracks()
        new_total = tracks['total']
        self.assertTrue(new_total - total == len(self.four_tracks))

        tracks = self.spotify.current_user_saved_tracks_delete(
            self.four_tracks)
        tracks = self.spotify.current_user_saved_tracks()
        new_total = tracks['total']
        self.assertTrue(new_total == total)

    def test_categories(self):
        response = self.spotify.categories()
        self.assertTrue(len(response['categories']) > 0)

    def test_category_playlists(self):
        response = self.spotify.categories()
        for cat in response['categories']['items']:
            cat_id = cat['id']
            response = self.spotify.category_playlists(category_id=cat_id)
            if len(response['playlists']["items"]) > 0:
                break
        self.assertTrue(True)

    def test_new_releases(self):
        response = self.spotify.new_releases()
        self.assertTrue(len(response['albums']) > 0)

    def test_featured_releases(self):
        response = self.spotify.featured_playlists()
        self.assertTrue(len(response['playlists']) > 0)

    def test_current_user_follows(self):
        response = self.spotify.current_user_followed_artists()
        artists = response['artists']
        self.assertTrue(len(artists['items']) > 0)

    def test_current_user_top_tracks(self):
        response = self.spotify.current_user_top_tracks()
        items = response['items']
        self.assertTrue(len(items) > 0)

    def test_current_user_top_artists(self):
        response = self.spotify.current_user_top_artists()
        items = response['items']
        self.assertTrue(len(items) > 0)

    def get_or_create_spotify_playlist(self, playlist_name):
        playlists = self.spotify.user_playlists(self.username)
        while playlists:
            for item in playlists['items']:
                if item['name'] == playlist_name:
                    return item['id']
            playlists = self.spotify.next(playlists)
        playlist = self.spotify.user_playlist_create(
            self.username, playlist_name)
        playlist_id = playlist['uri']
        return playlist_id

    def test_user_playlist_ops(self):
        sp = self.spotify
        # create empty playlist
        playlist_id = self.get_or_create_spotify_playlist(
            'spotipy-testing-playlist-1')

        # remove all tracks from it
        sp.user_playlist_replace_tracks(
            self.username, playlist_id, [])
        playlist = sp.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 0)
        self.assertTrue(len(playlist['tracks']['items']) == 0)

        # add tracks to it
        sp.user_playlist_add_tracks(
            self.username, playlist_id, self.four_tracks)
        playlist = sp.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 4)
        self.assertTrue(len(playlist['tracks']['items']) == 4)

        # remove two tracks from it

        sp.user_playlist_remove_all_occurrences_of_tracks(self.username,
                                                          playlist_id,
                                                          self.two_tracks)
        playlist = sp.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 2)
        self.assertTrue(len(playlist['tracks']['items']) == 2)

        # replace with 3 other tracks
        sp.user_playlist_replace_tracks(self.username,
                                        playlist_id,
                                        self.other_tracks)
        playlist = sp.user_playlist(self.username, playlist_id)
        self.assertTrue(playlist['tracks']['total'] == 3)
        self.assertTrue(len(playlist['tracks']['items']) == 3)

    def test_playlist(self):
        # New playlist ID
        pl = self.spotify.playlist(self.playlist_new_id)
        self.assertTrue(pl["tracks"]["total"] > 0)

        # Old playlist ID
        pl = self.spotify.playlist(self.playlist)
        self.assertTrue(pl["tracks"]["total"] > 0)

    def test_user_follows_and_unfollows_artist(self):
        # Initially follows 1 artist
        res = self.spotify.current_user_followed_artists()
        self.assertTrue(res['artists']['total'] == 1)

        # Follow 2 more artists
        artists = ["6DPYiyq5kWVQS4RGwxzPC7", "0NbfKEOTQCcwd6o7wSDOHI"]
        self.spotify.user_follow_artists(artists)
        res = self.spotify.current_user_followed_artists()
        self.assertTrue(res['artists']['total'] == 3)

        # Unfollow these 2 artists
        self.spotify.user_unfollow_artists(artists)
        res = self.spotify.current_user_followed_artists()
        self.assertTrue(res['artists']['total'] == 1)

    def test_user_follows_and_unfollows_user(self):
        # TODO improve after implementing `me/following/contains`
        users = ["11111204", "xlqeojt6n7on0j7coh9go8ifd"]

        # Follow 2 more users
        self.spotify.user_follow_users(users)

        # Unfollow these 2 users
        self.spotify.user_unfollow_users(users)
Esempio n. 16
0
# ------------------------------------------------------------------------
# Setup
# ------------------------------------------------------------------------
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

username = os.getenv("SPOTIFY_USER_ID")
SCOPE = "user-library-read"

token = util.prompt_for_user_token(username, SCOPE)
sp = Spotify(token)
app = dash.Dash(__name__,
                external_stylesheets=external_stylesheets,
                title="Reminiscify")

r = sp.current_user_saved_tracks()
df = get_liked_songs(sp)

# df = pd.read_csv("liked_songs.csv")
df["Added At"] = pd.to_datetime(df["Added At"])
df["Day Num"] = df["Added At"].dt.weekday
df["Day"] = df["Added At"].dt.day_name()

days_df = df.groupby(["Day Num", "Day"]).size().reset_index(name="Songs Saved")

fig = px.bar(days_df, x="Day", y="Songs Saved")

# ------------------------------------------------------------------------
# Layout
# ------------------------------------------------------------------------
app.layout = html.Div([