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