Closed alessiocelentano closed 3 years ago
There are several problems with your code:
spotify = spotipy.client.Spotify(
auth_manager=auth,
client_credentials_manager=SpotifyClientCredentials()
)
You are assigning two different authorization managers to Spotify
—SpotifyOAuth
and SpotifyClientCredentials
—which doesn't make sense. You only need one authorization manager. If you need to access user data, then you should use SpotifyOAuth
or SpotifyPKCE
. Don't ever use the oauth_manager
or client_credentials_manager
parameters of Spotify.init
. @stephanebruckert we should deprecate these parameters and emit a warning when anyone tries to use them; they just create confusion.
auth.get_auth_response(open_browser=False)
This method only performs the first step of the authorization process; you need to pass the authorization code that it returns into SpotifyOAuth.get_access_token
to complete the authorization process. If you don't retain the authorization code that get_auth_response
returns, then calling it is completely pointless. The way that spotipy works is that it will automatically start the authorization process for you when you make a call to an endpoint, such as Spotify.me
, if you are not authorized yet. It is this line that is authorizing your app, not the one above it.
The user that the instance of Spotify
returned by get_client
is authorized for is which ever one logs in to their Spotify account in the browser, unless the authorization information is already stored in a cache file. Is this cache file the same for everyone that uses your app? If so then it probably contains your authorization information, and this is the reason that everyone is seeing the stats for your account.
If, when you open the authorization URL, you are immediately redirected without being given a change to log in to your account, then it is because you are already logged in to your Spotify account on your browser. If you want to log in with a different account, then set show_dialog
to True
in SpotifyOAuth.init
.
and if I withdraw my authorization, it raises an error, although the user logged in with his account
What do you mean by this? Please be very specific about what you are doing in order to "withdraw my authorization".
Also, is everyone who uses your script supposed to get information about your Spotify account, instead of their Spotify account?
You need to provide more information about what you are trying to do. I'm very lost.
Also, you should only create one instance of Spotify
for each user. It looks like you're creating a new instance each time top_artists
is called and then re-authorizing the user. That doesn't make any sense. You only need to authorize the user once.
Hi. Thank you for answering me and sorry for the inaccuracy of the question.
You are assigning two different authorization managers to Spotify
Okay, so the line should be spotify = spotipy.client.Spotify(auth_manager=auth)
.
The way that spotipy works is that it will automatically start the authorization process for you when you make a call to an endpoint, such as Spotify.me
So I can keep only a Spotify.me() and it start automatically the authorization process, right?
Is this cache file the same for everyone that uses your app?
No, I pass an username in SpotifyOAuth(), so at the first authorization it creates .cache-<username>
. But if I have the username of the user who wants access to his data, how I get the right .cache? How do get_cached_token()
work in this case, with multiple caches?
What do you mean by this? Please be very specific about what you are doing in order to "withdraw my authorization".
Don't mind about that. I mean that if I delete the authorization on Spotify (Home > App > Remove access) and other users try to access, it gives an error, because it probably use my data stored in .cache-<myusername>
.
Also, is everyone who uses your script supposed to get information about your Spotify account, instead of their Spotify account?
No. They should get data about their account.
You need to provide more information about what you are trying to do. I'm very lost.
Simply this bot, once it gets authorization of the user and cached in .cache-<username>
, should give some user data (not of mine). There are many sites that do that, I wanted to implement that on a Telegram Bot.
Also, you should only create one instance of Spotify for each user
Perfect, my question is how I should get data of a specific .cache, instead of creating an instance every time. Is there a function for do that or I should do it manually?
If you provide the correct username when creating an instance of SpotifyOAuth
, then SpotifyOAuth.get_cached_token
should only access the cache file containing that username. You should print str(message.from_user.id)
to the console to check that it is what you expect. You can also print SpotifyOAuth.username
and SpotifyOAuth.cache_path
to see where the authorization manager is looking for the cached authorization information.
You don't need to make a call to Spotify.me()
if your app is not actually using the data that it returns. Just remove it entirely and spotipy will go through the authorization process if necessary when you make a call to current_user_top_tracks
or current_user_top_artists
or any of the other endpoints that your app ends up using.
Okay, one last thing: Once I get token = SpotifyOAuth.get_cached.token()["access_token"]
how should i do to get the Spotify()
instance? I did spotipy.client.Spotify(auth=token)
but it doesn't seem work.
You can get some inspiration from this example Flask app https://github.com/plamere/spotipy/blob/master/examples/app.py - it handles multiple users
When calling SpotifyOAuth you need to specify a cache_path, otherwise it will use the same cached token every time, therefore the one from the previous user:
https://github.com/plamere/spotipy/blob/94e164385e1b64f99e45053c6bdd638770c982e2/examples/app.py#L52
https://github.com/plamere/spotipy/blob/94e164385e1b64f99e45053c6bdd638770c982e2/examples/app.py#L43
I followed your advices and read the example, but it still doesn't work and I don't know why. You can take a look at the code here. I've been trying for days now and even with your help it doesn't seem to work, what am I doing wrong? Brief explanation: If the user is not logged, bot sends two buttons:
Spotify.me()
, so access token is cachedThen the user can get his data, here there aren't problems. But an instance of my account is still created
Did you add the print statements I suggested? What did you find? It would be extremely helpful if you actually did that.
The print are correct. I noticed an error that can be helpful:
[Errno 98] Address already in use
Traceback (most recent call last):
File "/home/cele/.local/lib/python3.8/site-packages/pyrogram/dispatcher.py", line 210, in handler_worker
await self.loop.run_in_executor(
File "/usr/lib/python3.8/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "main.py", line 46, in authorize
spotify = new_client(message)
File "/home/cele/dev/spotistats/src/client.py", line 28, in new_client
print(spotify.me())
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/client.py", line 1158, in me
return self._get("me/")
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/client.py", line 291, in _get
return self._internal_call("GET", url, payload, kwargs)
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/client.py", line 221, in _internal_call
headers = self._auth_headers()
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/client.py", line 212, in _auth_headers
token = self.auth_manager.get_access_token(as_dict=False)
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/oauth2.py", line 484, in get_access_token
"code": code or self.get_auth_response(),
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/oauth2.py", line 439, in get_auth_response
return self._get_auth_response_local_server(redirect_port)
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/oauth2.py", line 405, in _get_auth_response_local_server
server = start_local_http_server(redirect_port)
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/oauth2.py", line 1227, in start_local_http_server
server = HTTPServer(("127.0.0.1", port), handler)
File "/usr/lib/python3.8/socketserver.py", line 452, in __init__
self.server_bind()
File "/usr/lib/python3.8/http/server.py", line 138, in server_bind
socketserver.TCPServer.server_bind(self)
File "/usr/lib/python3.8/socketserver.py", line 466, in server_bind
self.socket.bind(self.server_address)
OSError: [Errno 98] Address already in use
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 60682)
Traceback (most recent call last):
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/oauth2.py", line 1186, in do_GET
state, auth_code = SpotifyOAuth.parse_auth_response_url(self.path)
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/oauth2.py", line 372, in parse_auth_response_url
raise SpotifyOauthError("Received error from auth server: "
spotipy.oauth2.SpotifyOauthError: Received error from auth server: access_denied
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.8/socketserver.py", line 316, in _handle_request_noblock
self.process_request(request, client_address)
File "/usr/lib/python3.8/socketserver.py", line 347, in process_request
self.finish_request(request, client_address)
File "/usr/lib/python3.8/socketserver.py", line 360, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python3.8/socketserver.py", line 720, in __init__
self.handle()
File "/usr/lib/python3.8/http/server.py", line 427, in handle
self.handle_one_request()
File "/usr/lib/python3.8/http/server.py", line 415, in handle_one_request
method()
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/oauth2.py", line 1190, in do_GET
self.server.state = err.state
AttributeError: 'SpotifyOauthError' object has no attribute 'state'
----------------------------------------
Server listening on localhost has not been accessed
Traceback (most recent call last):
File "/home/cele/.local/lib/python3.8/site-packages/pyrogram/dispatcher.py", line 210, in handler_worker
await self.loop.run_in_executor(
File "/usr/lib/python3.8/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "main.py", line 46, in authorize
spotify = new_client(message)
File "/home/cele/dev/spotistats/src/client.py", line 28, in new_client
print(spotify.me())
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/client.py", line 1158, in me
return self._get("me/")
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/client.py", line 291, in _get
return self._internal_call("GET", url, payload, kwargs)
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/client.py", line 221, in _internal_call
headers = self._auth_headers()
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/client.py", line 212, in _auth_headers
token = self.auth_manager.get_access_token(as_dict=False)
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/oauth2.py", line 484, in get_access_token
"code": code or self.get_auth_response(),
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/oauth2.py", line 439, in get_auth_response
return self._get_auth_response_local_server(redirect_port)
File "/home/cele/.local/lib/python3.8/site-packages/spotipy/oauth2.py", line 417, in _get_auth_response_local_server
raise SpotifyOauthError("Server listening on localhost has not been accessed")
spotipy.oauth2.SpotifyOauthError: Server listening on localhost has not been accessed
Can it be an error with the Redirect URI? SPOTIPY_REDIRECT_URI enviroment variable and redirect URI on Spotify for Developers are the same (http://localhost:8080), but after the user give the authorization, often the site give "ERR_CONNECTION_REFUSED"
The reason for these errors is probably because the automatic authorization process does not work in the environment that your app is running in. What environment is it running in? Is it running on a server?
Can it be an error with the Redirect URI?
Yes, I think the issue is related to the redirect URI. It shouldn't be "http://localhost:8080" if the app is running on an external server. After you open the url from SpotifyOAuth.get_authorize_url()
and the user logs in to their Spotify account and taps agree, Spotify will redirect to the redirect URI that you specified. The redirect URI should somehow redirect back to your bot. For example, a callback function in your code should be executed after Spotify redirects back to your app. Do you know how to do this? If you don't, than I can't help you because I've never used the telegram bot API before.
What environment is it running in? Is it running on a server?
It's running on my laptop with Arch Linux, so there shouldn't be problems, but the page with "Close" button is never loaded.
It shouldn't be "http://localhost:8080" if the app is running on an external server.
It is running on my PC and i read in the code that with localhost (and a port specified) I don't need to copy and paste the URL the browser is redirect to on the terminal.
a callback function in your code should be executed after Spotify redirects back to your app
What do you mean? What needs to be executed? I have a button that create a new spotipy.Spotify() instance for the user and store his data in a cache if the bot have the authorization, is not the same thing?
"OSError: [Errno 98] Address already in use" means that there is another process already using port 8080 (which is what appears in your redirect URI). You need to find that process and kill it. Alternatively, restart your computer. See https://stackoverflow.com/a/39557155/12394554
"spotipy.oauth2.SpotifyOauthError: Received error from auth server: access_denied" means that, after you opened the authorization URL in the browser and the user logged in to their Spotify account, the user tapped "cancel" instead of "agree", meaning that they denied your app access to their Spotify account.
It's hard for me to provide more help because I don't really understand how telegram bots work. You need to contact someone in the telegram community and ask them if it is possible to implement the OAuth authorization process, which is a widely recognized standard not specific to the Spotify web API.
Okay, thanks for the help, I'll ask to someone in Telegram community to fix this problem (if possible)
Specifically, you need to ask if you can setup a callback URL that redirects back to your application.
Hi! I asked this questions on StackOverflow but I didn't get an answer: I'm creating a Telegram Bot to get Spotify stats with Spotipy. This script will be used by multiple people, but after a user give authorizations he gets my stats. I have no idea why this happens.
No problem with the code above, Bot redirects the user to the link (auth.get_authorize_url()) and get authorization successfully.
I think the problem is here, the variable returned is always referred to my Spotify account (and if I withdraw my authorization, it raises an error, although the user logged in with his account). This function has to return the right variable, can anyone help me? You can read the full code on this link