I have a couple of things that are going wrong, and I have spent a considerable amount of time to fix it. I was first able to run the code below, Initially I did not pass the cache path as a parameter to the auth_manager. The code worked for an hour (since the token expires every hour), I then started running into errors regarding token refresh.
I then added the cache path as an added parameter and am getting two errors:
I have already checked the Redirect URI on my spotify developer dashboard and it matches what I have passed to the script.
Could I get a way to fix this as well as refresh the token if it's expired?
code
import configparser
import spotipy
from spotipy.oauth2 import SpotifyOAuth
import json
import os
import csv
class UserData():
def __init__(self, config_path):
config = configparser.ConfigParser()
config.read(config_path)
self.CLIENT_ID = config['AUTH']['cid']
self.CLIENT_SECRET = config['AUTH']['secret']
self.REDIRECT_URI = config['AUTH']['redirect_uri']
self.USERNAME = config['AUTH']['username']
self.CACHE = config['AUTH']['cache']
self.HOME_DIR = config['PATH']['home_dir']
self.top_artists = {}
self.top_tracks = {}
def get_top_artist(self, limit=None, time_range=None, offset=0):
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=self.CLIENT_ID,
client_secret=self.CLIENT_SECRET,
redirect_uri=self.REDIRECT_URI,
scope="user-top-read",
username=self.USERNAME,
cache_path=self.CACHE))
self.top_artists = sp.current_user_top_artists(limit=limit, offset=offset, time_range=time_range)
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)))+'/top_artist.csv', 'w' ,newline='') as csvfile:
writer = csv.writer(csvfile, delimiter = ',', quoting = csv.QUOTE_MINIMAL)
writer.writerow(['sno', 'id', 'name', 'popularity', 'genre', 'uri', 'image_ref', 'follower_count'])
for idx, item in enumerate(self.top_artists['items']):
sno = idx
id = item['id']
name = item['name']
popularity = item['popularity']
genre = item['genres']
uri = item['uri']
image_ref = item['images'][2]['url']
follower_count = item['followers']['total']
writer.writerow([sno, id, name, popularity, genre, uri, image_ref, follower_count])
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)))+'/top_artist.json', 'w') as myfile:
print(myfile)
json.dump(self.top_artists, myfile, indent=4, sort_keys=True)
return self.top_artists
data = UserData(config_path='/Users/siddharthnahar/Dev/py_spotify/config.ini')
data.get_top_artist(limit=1)
Output
siddharthnahar@Siddharths-MBP py_spotify % /Library/Frameworks/Python.framework/Versions/3.9/bin/python3.9 /Users/siddharthnahar/Dev/py_spotify/get_data.py
Couldn't read cache at: .cache-'21ranjgq5en4j53pcqfcedopi'
Enter the URL you were redirected to: /Library/Frameworks/Python.framework/Versions/3.9/bin/python3.9 /Users/siddharthnahar/Dev/py_spotify/get_data.py
Traceback (most recent call last):
File "/Users/siddharthnahar/Dev/py_spotify/get_data.py", line 74, in <module>
data = UserData(config_path='/Users/siddharthnahar/Dev/py_spotify/config.ini')
File "/Users/siddharthnahar/Dev/py_spotify/get_data.py", line 33, in get_top_artist
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/spotipy/client.py", line 1272, in current_user_top_artists
return self._get(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/spotipy/client.py", line 291, in _get
return self._internal_call("GET", url, payload, kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/spotipy/client.py", line 221, in _internal_call
headers = self._auth_headers()
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/spotipy/client.py", line 212, in _auth_headers
token = self.auth_manager.get_access_token(as_dict=False)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/spotipy/oauth2.py", line 504, in get_access_token
raise SpotifyOauthError(
spotipy.oauth2.SpotifyOauthError: error: invalid_request, error_description: code must be supplied
siddharthnahar@Siddharths-MBP py_spotify % /Library/Frameworks/Python.framework/Versions/3.9/bin/python3.9 /Users/siddharthnahar/Dev/py_spotify/get_data.py
Couldn't read cache at: '.cache-21ranjgq5en4j53pcqfcedopi'
Enter the URL you were redirected to:
Environment:
Do not create a new instance of Spotify each time you call get_top_artist. You should create it in the initializer for UserData instead. Your script should only ever create a single instance of Spotify for each Spotify user. The reason your are getting a "Couldn't read cache at Spotify the cache file does not exist. Have you checked whether it does exist? If the file does not exist and you are running the script for the first time (or the first time since you changed the cache path), then you can safely ignore this error.
In order to provide more help I will need to see what your config file looks like. If you post it here, make sure to redact sensitive information, such as your client id and client secret.
@stephanebruckert Is there a reason why a warning is emitted when the cache file does not exist at the specified path? When the script is being run for the first time, it should be expected that the cache file does not exist yet, so this shouldn't be considered an error condition. This behavior has confused me in the past as well.
@Peter-Schorn you are right it shouldn't show this warning if the file does not exist, only if it cannot be read (eg. no correct permission). We should change it, and possibly prepend all warnings with Warning: so that people don't think it's an error to worry too much about
@stephanebruckert I'll work on a PR to that effect.
Thank you, I will update as per your suggestion and share the output
Hi Peter,
I have made the changes that you suggested but I get the same error unfortunately. Here is my updated code:
import configparser
import spotipy
from spotipy.oauth2 import SpotifyOAuth
import json
import os
import csv
class UserData():
def __init__(self, config_path):
config = configparser.ConfigParser()
config.read(config_path)
self.CLIENT_ID = config['AUTH']['cid']
self.CLIENT_SECRET = config['AUTH']['secret']
self.REDIRECT_URI = config['AUTH']['redirect_uri']
self.USERNAME = config['AUTH']['username']
self.CACHE = config['AUTH']['cache']
self.HOME_DIR = config['PATH']['home_dir']
self.top_artists = {}
self.top_tracks = {}
self.sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=self.CLIENT_ID,
client_secret=self.CLIENT_SECRET,
redirect_uri=self.REDIRECT_URI,
scope="user-top-read",
username=self.USERNAME,
cache_path=self.CACHE))
def get_top_artist(self, limit=None, time_range=None, offset=0):
self.top_artists = self.sp.current_user_top_artists(limit=limit, offset=offset, time_range=time_range)
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)))+'/top_artist.csv', 'w' ,newline='') as csvfile:
writer = csv.writer(csvfile, delimiter = ',', quoting = csv.QUOTE_MINIMAL)
writer.writerow(['sno', 'id', 'name', 'popularity', 'genre', 'uri', 'image_ref', 'follower_count'])
for idx, item in enumerate(self.top_artists['items']):
sno = idx
id = item['id']
name = item['name']
popularity = item['popularity']
genre = item['genres']
uri = item['uri']
image_ref = item['images'][2]['url']
follower_count = item['followers']['total']
writer.writerow([sno, id, name, popularity, genre, uri, image_ref, follower_count])
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)))+'/top_artist.json', 'w') as myfile:
print(myfile)
json.dump(self.top_artists, myfile, indent=4, sort_keys=True)
return self.top_artists
data = UserData(config_path='/Users/siddharthnahar/Dev/py_spotify/config.ini')
data.get_top_artist(limit=1)
Below is the config file:
[PATH]
home_dir = '/Users/siddharthnahar/Dev/py_spotify/'
src_dir = '/Users/siddharthnahar/Dev/py_spotify/src'
[AUTH]
cid='xxx'
secret='xxx'
redirect_uri='http://localhost:8888/callback'
username='xxx'
cache ='.cache-21ranjgq5en4j53pcqfcedopi'
[SCOPES]
read_playlist=playlist-read-private
read_library=user-library-read
top_artists=user-top-read
When I ran this script, I already had an .cache file in my directory. But I still get the below error:
siddharthnahar@Siddharths-MBP py_spotify % /Library/Frameworks/Python.framework/Versions/3.9/bin/python3.9 /Users/siddharthnahar/Dev/py_spotify/get_data2.py
Couldn't read cache at: '.cache-21ranjgq5en4j53pcqfcedopi'
Enter the URL you were redirected to:
Here is the URL I'm directed to:
https://accounts.spotify.com/authorize?client_id=%
When I ran this script, I already had an .cache file in my directory. But I still get the below error:
What is the exact name of the cache file? Is it .cache or is it .cache-21ranjgq5en4j53pcqfcedopi? It should be the later according to your code
The PR by @Peter-Schorn was merged to master, please use that version so we get better warnings / error messages and let us know what is shows
pip install git+https://github.com/plamere/spotipy.git --upgrade
I haven't tested your code yet, but I don't see anything that is too wrong. I just see you are still using the following the following:
username=self.USERNAME,
cache_path=self.CACHE))
while these are optional. It _should_ work with it, but since some work was done around it lately, perhaps there is a bug. Can you please remove these 2 lines and try again?
@stephanebruckert @siddharthnahar The reason for the error is actually much simpler than you think. The config file should not have quotes around the values. If you print the values after you retrieve them from the file, you will see that the quotes are included as part of the values.
Take a look at one of the errors you received:
Couldn't read cache at: '.cache-21ranjgq5en4j53pcqfcedopi'
The logger does not enclose the file path in quotes; the quotes are part of the value, which is clearly not what you want.
Take a look at the documentation for configparser for how to properly format the config file.
Most helpful comment
@stephanebruckert @siddharthnahar The reason for the error is actually much simpler than you think. The config file should not have quotes around the values. If you print the values after you retrieve them from the file, you will see that the quotes are included as part of the values.