Spotipy 401 исключение при отмене подписки на исполнителей - PullRequest
0 голосов
/ 08 июля 2020

Приношу извинения за объем, но я пытаюсь использовать Spotipy, чтобы отписаться от 1400 артистов по Artist ID. Я начинаю с подмножества 5 ID, используя большой кусок кода client.py из документации spotipy:

https://raw.githubusercontent.com/plamere/spotipy/master/spotipy/client.py

Он возвращает ошибку:

spotipy.exceptions.SpotifyException: http status: 401, code:-1... no token provided.

У меня сложилось впечатление, что если вы создадите приложение в Spotify для разработчиков, введете идентификатор клиента, секретный идентификатор и URI перенаправления, запустите его, и оно перенесет вас на страницу аутентификации Spotify в браузере и вы нажимаете ОК, что у вас все в порядке: он запоминает ваш токен.

На всякий случай я пытался перейти на https://developer.spotify.com/console/delete-following/, но когда я нажимаю, чтобы запросить токен «вручную», он просто загружается https://developer.spotify.com/callback/ и не дает мне никакой информации.

Кто-нибудь может сказать мне, что мне не хватает?

scope = 'user-follow-modify'
username = "half-truth"
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(username=username, scope=scope))  
try:
    token = util.prompt_for_user_token(username, scope)

except (AttributeError, JSONDecodeError):
    os.remove(f".cache-{username}")
    token = util.prompt_for_user_token(username, scope) 

class Spotify(object):
    max_retries = 3
    default_retry_codes = (429, 500, 502, 503, 504)
    country_codes = ["AD", "AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "SV", "EE", "FI", "FR", "DE", "GR", "GT", "HN", "HK", "HU", "IS", "ID", "IE", "IT", "JP", "LV", "LI", "LT", "LU", "MY", "MT", "MX", "MC", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "ES", "SK", "SE", "CH", "TW", "TR", "GB", "US", "UY"]

    def __init__(
        self,
        auth=None,
        requests_session=True,
        client_credentials_manager=None,
        oauth_manager=None,
        auth_manager=None,
        proxies=None,
        requests_timeout=5,
        status_forcelist=None,
        retries=max_retries,
        status_retries=max_retries,
        backoff_factor=0.3,
    ):
        self.prefix = "https://api.spotify.com/v1/"
        self._auth = auth
        self.client_credentials_manager = client_credentials_manager
        self.oauth_manager = oauth_manager
        self.auth_manager = auth_manager
        self.proxies = proxies
        self.requests_timeout = requests_timeout
        self.status_forcelist = status_forcelist or self.default_retry_codes
        self.backoff_factor = backoff_factor
        self.retries = retries
        self.status_retries = status_retries

        if isinstance(requests_session, requests.Session):
            self._session = requests_session
        else:
            if requests_session:  # Build a new session.
                self._build_session()
            else:  # Use the Requests API module as a "session".
                self._session = requests.api

    def set_auth(self, auth):
        self._auth = auth

    @property
    def auth_manager(self):
        return self._auth_manager

    @auth_manager.setter
    def auth_manager(self, auth_manager):
        if auth_manager is not None:
            self._auth_manager = auth_manager
        else:
            self._auth_manager = (
                self.client_credentials_manager or self.oauth_manager
            )

    def __del__(self):
        """Make sure the connection (pool) gets closed"""
        if isinstance(self._session, requests.Session):
            self._session.close()

    def _build_session(self):
        self._session = requests.Session()
        retry = urllib3.Retry(
            total=self.retries,
            connect=None,
            read=False,
            status=self.status_retries,
            backoff_factor=self.backoff_factor,
            status_forcelist=self.status_forcelist)

        adapter = requests.adapters.HTTPAdapter(max_retries=retry)
        self._session.mount('http://', adapter)
        self._session.mount('https://', adapter)

    def _auth_headers(self):
        if self._auth:
            return {"Authorization": "Bearer {0}".format(self._auth)}
        if not self.auth_manager:
            return {}
        try:
            token = self.auth_manager.get_access_token(as_dict=False)
        except TypeError:
            token = self.auth_manager.get_access_token()
        return {"Authorization": "Bearer {0}".format(token)}


    def _internal_call(self, method, url, payload, params):
        args = dict(params=params)
        if not url.startswith("http"):
            url = self.prefix + url
        headers = self._auth_headers()

        if "content_type" in args["params"]:
            headers["Content-Type"] = args["params"]["content_type"]
            del args["params"]["content_type"]
            if payload:
                args["data"] = payload
        else:
            headers["Content-Type"] = "application/json"
            if payload:
                args["data"] = json.dumps(payload)

        logging.debug('Sending %s to %s with Headers: %s and Body: %r ',
                     method, url, headers, args.get('data'))

        try:
            response = self._session.request(
                method, url, headers=headers, proxies=self.proxies,
                timeout=self.requests_timeout, **args
            )

            response.raise_for_status()
            results = response.json()
        except requests.exceptions.HTTPError:
            try:
                msg = response.json()["error"]["message"]
            except (ValueError, KeyError):
                msg = "error"

            logging.error('HTTP Error for %s to %s returned %s due to %s',
                         method, url, response.status_code, msg)

            raise SpotifyException(
                response.status_code,
                -1,
                "%s:\n %s" % (response.url, msg),
                headers=response.headers,
            )
        except requests.exceptions.RetryError:
            logging.error('Max Retries reached')
            raise SpotifyException(
                599,
                -1,
                "%s:\n %s" % (response.url, "Max Retries"),
                headers=response.headers,
            )
        except ValueError:
            results = None

        logging.debug('RESULTS: %s', results)
        return results

    def _get(self, url, args=None, payload=None, **kwargs):
        if args:
            kwargs.update(args)

        return self._internal_call("GET", url, payload, kwargs)

    def _post(self, url, args=None, payload=None, **kwargs):
        if args:
            kwargs.update(args)
        return self._internal_call("POST", url, payload, kwargs)

    def _delete(self, url, args=None, payload=None, **kwargs):
        if args:
            kwargs.update(args)
        return self._internal_call("DELETE", url, payload, kwargs)

    def _put(self, url, args=None, payload=None, **kwargs):
        if args:
            kwargs.update(args)
        return self._internal_call("PUT", url, payload, kwargs)

    def next(self, result):
        if result["next"]:
            return self._get(result["next"])
        else:
            return None

    def previous(self, result):
        if result["previous"]:
            return self._get(result["previous"])
        else:
            return None

    def user_unfollow_artists(self, ids=[]):
        return self._delete("me/following?type=artist&ids=" + ",".join(ids))

unfollow = Spotify()
unfollow.user_unfollow_artists(artist_ids[:5])
...