示例#1
0
    def _follow_unfollow_help(self, other, request_type):
        """ follow and unfollow are identical, except for the request type.

        This function implements that functionality to remove duplicate code.
        """
        # Validate input
        if not isinstance(other, list):
            other = [other]

        for elem in other:
            if type(elem) not in [Artist, User, Playlist]:
                raise TypeError(elem)

        # Split up input
        artists = utils.separate(other, Artist)
        users = utils.separate(other, User)
        playlists = utils.separate(other, Playlist)

        for batch in utils.create_batches(utils.map_ids(artists)):
            response_json, status_code = utils.request(
                self._session,
                request_type=request_type,
                endpoint=Endpoints.USER_FOLLOW_ARTIST_USER,
                body=None,
                uri_params={
                    'type': 'artist',
                    'ids': batch
                })

            if status_code != 204:
                raise utils.SpotifyError(status_code, response_json)

        for batch in utils.create_batches(utils.map_ids(users)):
            response_json, status_code = utils.request(
                self._session,
                request_type=request_type,
                endpoint=Endpoints.USER_FOLLOW_ARTIST_USER,
                body=None,
                uri_params={
                    'type': 'user',
                    'ids': batch
                })

            if status_code != 204:
                raise utils.SpotifyError(status_code, response_json)

        for playlist in playlists:
            response_json, status_code = utils.request(
                self._session,
                request_type=request_type,
                endpoint=Endpoints.USER_FOLLOW_PLAYLIST % playlist,
                body=None,
                uri_params=None)

            if status_code != 200:
                raise utils.SpotifyError(status_code, response_json)
示例#2
0
    def get_artists(self, artist_ids):
        """ Gets the artists with the given Spotify ids.

        Args:
            artist_ids (str, List[str): The Spotify artist id(s) to get.

        Returns:
            Union[Album, List[Album]]: The requested artist(s).

        Raises:
            TypeError: for invalid types in any argument.
            HTTPError: if failure or partial failure.

        Calls endpoints:
            - GET   /v1/artists

        Note: the following endpoint is not used.
            - GET   /v1/artists/{id}
        """

        # Type validation
        if not isinstance(artist_ids, str) and\
            not all(isinstance(x, str) for x in artist_ids):
            raise TypeError('artist_ids should be str or list of str')

        if isinstance(artist_ids, str):
            artist_ids = list(artist_ids)

        # Construct params for API call
        endpoint = Endpoints.SEARCH_ALBUMS
        uri_params = dict()

        # A maximum of 50 artists can be returned per API call
        batches = utils.create_batches(artist_ids, 50)

        result = list()
        for batch in batches:
            uri_params['ids'] = batch

            # Execute requests
            response_json, status_code = utils.request(
                session=self,
                request_type=const.REQUEST_GET,
                endpoint=endpoint,
                uri_params=uri_params)

            if status_code != 200:
                raise utils.SpotifyError(status_code, response_json)

            items = response_json['artists']
            for item in items:
                result.append(Artist(self, item))

        return result if len(result) != 1 else result[0]
示例#3
0
    def _save_remove_help(self, other, request_type):
        """ save and remove are identical, except for the request type and
        return codes.

        This function implements that functionality to remove duplicate code.
        """
        # Validate input
        if not isinstance(other, list):
            other = [other]

        for elem in other:
            if type(elem) not in [Album, Track]:
                raise TypeError(elem)

        # Split up input
        albums = utils.separate(other, Album)
        tracks = utils.separate(other, Track)

        for batch in utils.create_batches(utils.map_ids(albums)):
            response_json, status_code = utils.request(
                self._session,
                request_type=request_type,
                endpoint=Endpoints.USER_SAVE_ALBUMS,
                body=None,
                uri_params={'ids': batch})

            # All success codes are 200, except saving an album
            success = 201 if request_type == const.REQUEST_PUT else 200
            if status_code != success:
                raise utils.SpotifyError(status_code, response_json)

        for batch in utils.create_batches(utils.map_ids(tracks)):
            response_json, status_code = utils.request(
                self._session,
                request_type=request_type,
                endpoint=Endpoints.USER_SAVE_TRACKS,
                body=None,
                uri_params={'ids': batch})

            if status_code != 200:
                raise utils.SpotifyError(status_code, response_json)
示例#4
0
    def has_saved(self, other):
        """ Check if the user has one or more things saved to their library.

        Args:
            other: check if the current user has 'other' saved to the library.
                Other must be one of the following:

                    - Track
                    - Album
                    - List: can contain multiple of the above types

        Returns:
            List of tuples. Each tuple has an input object and whether the user
            has that object saved.

        Required token scopes:
            - user-library-read

        Calls endpoints:
            - GET     /v1/me/albums/contains
            - GET     /v1/me/tracks/contains
        """
        # Validate input
        if not isinstance(other, list):
            other = [other]

        for elem in other:
            if type(elem) not in [Track, Album]:
                raise TypeError(elem)

        # Split up input
        tracks = utils.separate(other, Track)
        albums = utils.separate(other, Album)

        # Get boolean values for whether the user has each item saved
        endpoint = Endpoints.USER_HAS_SAVED

        track_bools = []
        for batch in utils.create_batches(utils.map_ids(tracks)):
            response_json, status_code = utils.request(
                self._session,
                request_type=const.REQUEST_GET,
                endpoint=endpoint % 'tracks',
                body=None,
                uri_params={'ids': batch})

            if status_code != 200:
                raise utils.SpotifyError(status_code, response_json)

            track_bools.append(response_json)

        album_bools = []
        for batch in utils.create_batches(utils.map_ids(albums)):
            response_json, status_code = utils.request(
                self._session,
                request_type=const.REQUEST_GET,
                endpoint=endpoint % 'albums',
                body=None,
                uri_params={'ids': batch})

            if status_code != 200:
                raise utils.SpotifyError(status_code, response_json)

            album_bools.append(response_json)

        # Zip output with input to make tuples
        zipped_tracks = list(zip(tracks, track_bools))
        zipped_albums = list(zip(albums, album_bools))
        return zipped_tracks + zipped_albums
示例#5
0
    def is_following(self, other):
        """ Check if the current user is following something.

        Args:
            other: check if current user is following 'other'. Other must be
                one of the following:

                    - Artist
                    - User
                    - Playlist
                    - List: can contain multiple of the above types

        Required token scopes:
            - user-follow-read
            - playlist-read-private
            - playlist-read-collaborative

        Calls endpoints:
            - GET     /v1/me/following/contains
            - GET     /v1/users/{user_id}/playlists

        Returns:
            List of tuples. Each tuple has an input object and whether the user
            follows the object.
        """
        # Validate input
        if not isinstance(other, list):
            other = [other]

        for elem in other:
            if type(elem) not in [Artist, User, Playlist]:
                raise TypeError(elem)

        # Split up input
        artists = utils.separate(other, Artist)
        users = utils.separate(other, User)
        playlists = utils.separate(other, Playlist)

        # Get boolean values for whether the user follows each in 'other'
        endpoint = Endpoints.USER_FOLLOWING_CONTAINS
        artist_bools = []
        for batch in utils.create_batches(utils.map_ids(artists)):
            response_json, status_code = utils.request(
                self._session,
                request_type=const.REQUEST_GET,
                endpoint=endpoint,
                body=None,
                uri_params={
                    'type': 'artist',
                    'ids': batch
                })

            if status_code != 200:
                raise utils.SpotifyError(status_code, response_json)

            artist_bools.append(response_json)

        user_bools = []
        for batch in utils.create_batches(utils.map_ids(users)):
            response_json, status_code = utils.request(
                self._session,
                request_type=const.REQUEST_GET,
                endpoint=endpoint,
                body=None,
                uri_params={
                    'type': 'user',
                    'ids': batch
                })

            if status_code != 200:
                raise utils.SpotifyError(status_code, response_json)

            user_bools.append(response_json)

        # For each playlist in other, check if in the User's followed playlists
        followed_playlists = self.get_following(const.PLAYLISTS)
        playlist_bools = list(map(lambda p: p in followed_playlists,
                                  playlists))

        # Zip output with input to make tuples
        artists = list(zip(artists, artist_bools))
        users = list(zip(users, user_bools))
        playlists = list(zip(playlists, playlist_bools))
        return artists + users + playlists
示例#6
0
    def get_tracks(self, track_ids, market=const.TOKEN_REGION):
        """ Gets the tracks with the given Spotify ids.

        Args:
            track_ids (str, List[str]): The Spotify track id(s) to get.
            market (str): a :term:`market code <Market>` or sp.TOKEN_REGION,
                used for :term:`track relinking <Track Relinking>`. If None, no
                market is passed to Spotify's Web API, and its default behavior
                is invoked.

        Returns:
            Union[Track, List[Track]]: The requested track(s).

        Raises:
            TypeError: for invalid types in any argument.
            ValueError: if market type is invalid. TODO
            HTTPError: if failure or partial failure.

        Calls endpoints:
            - GET   /v1/tracks

        Note: the following endpoint is not used.
            - GET   /v1/tracks/{id}
        """

        # Type validation
        if not isinstance(track_ids, str) and\
            not all(isinstance(x, str) for x in track_ids):
            raise TypeError('track_ids should be str or list of str')
        if market is not None and not isinstance(market, str):
            raise TypeError('market should be None or str')

        # Argument validation
        if isinstance(track_ids, str):
            track_ids = list(track_ids)

        # Construct params for API call
        endpoint = Endpoints.SEARCH_TRACKS
        uri_params = dict()
        if market is not None:
            uri_params['market'] = market

        # A maximum of 50 tracks can be returned per API call
        batches = utils.create_batches(track_ids, 50)

        result = list()
        for batch in batches:
            uri_params['ids'] = ','.join(batch)

            # Execute requests
            response_json, status_code = utils.request(
                session=self,
                request_type=const.REQUEST_GET,
                endpoint=endpoint,
                uri_params=uri_params)

            if status_code != 200:
                raise utils.SpotifyError(status_code, response_json)

            items = response_json['tracks']
            for item in items:
                result.append(Track(self, item))

        return result if len(result) != 1 else result[0]