def get_user_recently_played(user): """ Get recently played songs from Spotify for specified user. This uses the 'me/player/recently-played' endpoint, which only allows us to get the last 50 plays for one user. Args: user (spotify.Spotify): the user whose plays are to be imported. Returns: the response from the spotify API consisting of the list of recently played songs. Raises: spotify.SpotifyAPIError: if we encounter errors from the Spotify API. spotify.SpotifyListenBrainzError: if we encounter a rate limit, even after retrying. """ retries = 10 delay = 1 tried_to_refresh_token = False while retries > 0: try: recently_played = user.get_spotipy_client()._get("me/player/recently-played", limit=50) break except SpotifyException as e: retries -= 1 if e.http_status == 429: # Rate Limit Problems -- the client handles these, but it can still give up # after a certain number of retries, so we look at the header and try the # request again, if the error is raised time_to_sleep = e.headers.get('Retry-After', delay) current_app.logger.warn('Encountered a rate limit, sleeping %d seconds and trying again...', time_to_sleep) time.sleep(time_to_sleep) delay += 1 if retries == 0: raise spotify.SpotifyListenBrainzError('Encountered a rate limit.') elif e.http_status in (400, 403, 404): current_app.logger.critical('Error from the Spotify API for user %s: %s', str(user), str(e), exc_info=True) raise spotify.SpotifyAPIError('Error from the Spotify API while getting listens: %s', str(e)) elif e.http_status >= 500 and e.http_status < 600: # these errors are not our fault, most probably. so just log them and retry. current_app.logger.error('Error while trying to get listens for user %s: %s', str(user), str(e), exc_info=True) if retries == 0: raise spotify.SpotifyAPIError('Error from the spotify API while getting listens: %s', str(e)) elif e.http_status == 401: # if we get 401 Unauthorized from Spotify, that means our token might have expired. # In that case, try to refresh the token, if there is an error even while refreshing # give up and report to the user. # We only try to refresh the token once, if we still get 401 after that, we give up. if not tried_to_refresh_token: try: user = spotify.refresh_user_token(user) except SpotifyError as err: raise spotify.SpotifyAPIError('Could not authenticate with Spotify, please unlink and link your account again.') tried_to_refresh_token = True else: raise spotify.SpotifyAPIError('Could not authenticate with Spotify, please unlink and link your account again.') except Exception as e: retries -= 1 current_app.logger.error('Unexpected error while getting listens: %s', str(e), exc_info=True) if retries == 0: raise spotify.SpotifyListenBrainzError('Unexpected error while getting listens: %s' % str(e)) return recently_played
def make_api_request(user, spotipy_call, **kwargs): """ Make an request to the Spotify API for particular user at specified endpoint with args. Args: user (spotify.Spotify): the user whose plays are to be imported. spotipy_call (function): the Spotipy function which makes request to the required API endpoint Returns: the response from the spotify API Raises: spotify.SpotifyAPIError: if we encounter errors from the Spotify API. spotify.SpotifyListenBrainzError: if we encounter a rate limit, even after retrying. """ retries = 10 delay = 1 tried_to_refresh_token = False while retries > 0: try: recently_played = spotipy_call(**kwargs) break except SpotifyException as e: retries -= 1 if e.http_status == 429: # Rate Limit Problems -- the client handles these, but it can still give up # after a certain number of retries, so we look at the header and try the # request again, if the error is raised try: time_to_sleep = int(e.headers.get('Retry-After', delay)) except ValueError: time_to_sleep = delay current_app.logger.warn( 'Encountered a rate limit, sleeping %d seconds and trying again...', time_to_sleep) time.sleep(time_to_sleep) delay += 1 if retries == 0: raise spotify.SpotifyListenBrainzError( 'Encountered a rate limit.') elif e.http_status in (400, 403): current_app.logger.critical( 'Error from the Spotify API for user %s: %s', str(user), str(e), exc_info=True) raise spotify.SpotifyAPIError( 'Error from the Spotify API while getting listens: %s', str(e)) elif e.http_status >= 500 and e.http_status < 600: # these errors are not our fault, most probably. so just log them and retry. current_app.logger.error( 'Error while trying to get listens for user %s: %s', str(user), str(e), exc_info=True) if retries == 0: raise spotify.SpotifyAPIError( 'Error from the spotify API while getting listens: %s', str(e)) elif e.http_status == 401: # if we get 401 Unauthorized from Spotify, that means our token might have expired. # In that case, try to refresh the token, if there is an error even while refreshing # give up and report to the user. # We only try to refresh the token once, if we still get 401 after that, we give up. if not tried_to_refresh_token: user = spotify.refresh_user_token(user) tried_to_refresh_token = True else: raise spotify.SpotifyAPIError( 'Could not authenticate with Spotify, please unlink and link your account again.' ) elif e.http_status == 404: current_app.logger.error( "404 while trying to get listens for user %s", str(user), exc_info=True) if retries == 0: raise spotify.SpotifyListenBrainzError( "404 while trying to get listens for user %s" % str(user)) except Exception as e: retries -= 1 current_app.logger.error( 'Unexpected error while getting listens: %s', str(e), exc_info=True) if retries == 0: raise spotify.SpotifyListenBrainzError( 'Unexpected error while getting listens: %s' % str(e)) return recently_played