def _get_authorization_token(self, cache_token=True) -> str: """ Step 2 """ logger.info('Get authorization token') code_verifier, code_challenge = self._generate_consts() data = { 'client_id': self.client_id, 'grant_type': 'authorization_code', 'code': self._get_authorization_code(code_challenge), 'redirect_uri': self.redirect_uri, 'code_verifier': code_verifier } resp = self._session.post(url=self.AUTH_TOKEN_URL, data=data) if resp.status_code != 200: result = resp.json() logger.error('Getting responce token error') raise AuthFlowRequestError(error=result['error'], error_descr=result['error_description'], code=resp.status_code) self.token_info = resp.json() self.token_info['expires_at'] = int( time.time()) + self.token_info["expires_in"] if cache_token: self._cache_token()
def _refresh_authorization_token(self, cache_token=True) -> None: """ Requesting a refreshed access token; Spotify returns a new access token to your app """ logger.info('Refresh expired token') headers = self._make_authorization_headers(self._client_id, self._client_secret) data = { 'grant_type': 'refresh_token', 'refresh_token': self.token_info['refresh_token'], 'redirect_uri': self.redirect_uri } resp = self._session.post(url=self.AUTH_TOKEN_URL, headers=headers, data=data) if resp.status_code != 200: result = resp.json() logger.error('Getting responce token error') raise AuthFlowRequestError(error=result['error'], error_descr=result['error_description'], code=resp.status_code) logger.debug(resp.text) self.token_info = resp.json() self.token_info['expires_at'] = int( time.time()) + self.token_info["expires_in"] if cache_token: self._cache_token()
def getUserCurrentPlayback(self): # logger.debug(f'Getting current playback') try: res = self.__api_request(method='GET', url_path='me/player') res.raise_for_status() except SpotifyRequestError as err: logger.error(err) raise if res.status_code == 204: raise SpotifyRequestNoContent return res.json()
def _get_authorization_token(self, cache_token=True) -> None: """ Step 2. Exchange code with an access token POST https://accounts.spotify.com/api/token The body must contain the following parameters encoded in application/x-www-form-urlencoded as defined in the OAuth 2.0 specification: POST data: grant_type=authorization_code, code, redirect_uri Headers: Base 64 encoded string that contains the client ID and client secret key. The field must have the format: "Authorization: Basic *<base64 encoded client_id:client_secret>*" Return: - access_token - token_type=“Bearer” - scope -- space-separated list of scopes which have been granted for this access_token - expires_in -- The time period (in seconds) for which the access token is valid - refresh_token -- a token that can be sent to the Spotify Accounts service in place of an authorization code. When the access code expires, send a POST request to the Accounts service /api/token endpoint, but use this code in place of an authorization code. A new access token will be returned. A new refresh token might be returned too.) """ logger.info('Get authorization token') headers = self._make_authorization_headers(self._client_id, self._client_secret) data = { 'grant_type': 'authorization_code', 'code': self._get_authorization_code(), 'redirect_uri': self.redirect_uri } resp = self._session.post(url=self.AUTH_TOKEN_URL, headers=headers, data=data) if resp.status_code != 200: result = resp.json() logger.error('Getting responce token error') raise AuthFlowRequestError(error=result['error'], error_descr=result['error_description'], code=resp.status_code) self.token_info = resp.json( ) # {'access_token': 'BQ...', 'token_type': 'Bearer', 'expires_in': 3600, 'refresh_token': 'AQ...', 'scope': '...'} self.token_info['expires_at'] = int( time.time()) + self.token_info["expires_in"] if cache_token: self._cache_token()
def search(self, raw_q, q_type, market=None, limit=None, offset=None, include_external=False): """ Search for an Item raw_q: String with operators and flters: q='album:arrival artist:abba' q="doom metal" q_type: String with one of many types Example: q_type=album, q_type=album,track Returns: For each type provided in the type parameter, the response body contains an array of artist objects / simplified album objects / track objects / simplified show objects / simplified episode objects wrapped in a paging object in JSON. """ avaliable_types = [ 'album', 'artist', 'playlist', 'track', 'show', 'episode' ] if q_type not in avaliable_types: raise SpotifyError( f'"q_type" must be {", ".join([x for x in avaliable_types])}') payload = {'q': raw_q, 'type': q_type} if market: payload.update({'market': market}) if limit: payload.update({'limit': limit}) if include_external: payload.update({'locale': include_external}) if offset: payload.update({'offset': offset}) try: resp = self.__api_request(method='GET', url_path='search', params=payload) resp.raise_for_status() except SpotifyRequestError as err: logger.error(err) raise return resp.json()
def startOrResumeUserPlayback(self, device_id=None, context_uri=None, uris=None, offset=None, position_ms=None): """ user-modify-playback-state context_uri: Spotify URI of the context to play (albums, artists, playlists). Example: {"context_uri": "spotify:album:1Je1IMUlBXcx1Fz0WE7oPT"} uris: Spotify track URIs to play. Example: {"uris": ["spotify:track:4iV5W9uYEdYUVa79Axb7Rh", "spotify:track:1301WleyT98MSxVHPZCA6M"]} offset: Indicates from where in the context playback should start. Avaliable when `context_uri` corresponds to an album or playlist object, or when the `uris` parameter is used. Example: "offset": {"position": 5} “uri” is a string representing the uri of the item to start at. Example: "offset": {"uri": "spotify:track:1301WleyT98MSxVHPZCA6M"} position_ms: Passing in a position that is greater than the length of the track will cause the player to start playing the next song. """ # logger.debug(f"Start/Resume a User's Playback") params = dict() if device_id: params.update({"device_id": device_id}) body = dict() if context_uri: body.update({"context_uri": context_uri}) if uris: body.update({"uris": uris}) if offset: body.update({"offset": offset}) if position_ms: body.update({"position_ms": position_ms}) if not body: body = {} try: res = self.__api_request(method='PUT', url_path='me/player/play', params=params, data=json.dumps(body)) except SpotifyRequestError as err: logger.error(err) raise return res
def getUserCurrentTrack(self, market=None): """ Get the object currently being played on the user’s Spotify account.""" # logger.debug(f"Get the User's Currently Playing Track") query = None if market: query = {'market': market} try: res = self.__api_request(method='GET', url_path='me/player/currently-playing', params=query) except SpotifyRequestError as err: logger.error(err) raise if res.status_code == 204: raise SpotifyRequestNoContent return res.json()
def __api_request(self, method, url_path, headers=None, params=None, data=None): headers = self._get_headers() url = urljoin(self.SPOTIFY_API_URL, url_path) try: resp = self._session.request(method=method, url=url, headers=headers, params=params, data=data) resp.raise_for_status() except requests.exceptions.HTTPError as err: logger.error(err) raise SpotifyRequestError(resp.text) return resp