mirror of
https://github.com/spotipy-dev/spotipy.git
synced 2026-06-19 09:13:53 +00:00
Merge branch 'master' of github.com:spotipy-dev/spotipy into v3_rebase_rebase
This commit is contained in:
commit
935e3c16d7
@ -52,6 +52,7 @@ Rebasing master onto v3 doesn't require a changelog update.
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added examples for audiobooks, shows and episodes methods to examples directory
|
- Added examples for audiobooks, shows and episodes methods to examples directory
|
||||||
|
- Use newer string formatters (https://pyformat.info)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|||||||
@ -145,7 +145,7 @@ class SpotifyClientCredentials that can be used to authenticate requests like so
|
|||||||
playlists = sp.user_playlists('spotify')
|
playlists = sp.user_playlists('spotify')
|
||||||
while playlists:
|
while playlists:
|
||||||
for i, playlist in enumerate(playlists['items']):
|
for i, playlist in enumerate(playlists['items']):
|
||||||
print("%4d %s %s" % (i + 1 + playlists['offset'], playlist['uri'], playlist['name']))
|
print(f"{i + 1 + playlists['offset']:4d} {playlist['uri']} {playlist['name']}")
|
||||||
if playlists['next']:
|
if playlists['next']:
|
||||||
playlists = sp.next(playlists)
|
playlists = sp.next(playlists)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
Sphinx~=7.4.7
|
Sphinx~=8.1.3
|
||||||
sphinx-rtd-theme~=2.0.0
|
sphinx-rtd-theme~=3.0.2
|
||||||
redis>=3.5.3
|
redis>=3.5.3
|
||||||
|
|||||||
@ -20,7 +20,7 @@ def get_args():
|
|||||||
def get_artist(name):
|
def get_artist(name):
|
||||||
results = sp.search(q=f'artist:{name}', type='artist')
|
results = sp.search(q=f'artist:{name}', type='artist')
|
||||||
items = results['artists']['items']
|
items = results['artists']['items']
|
||||||
return items[0] if len(items) > 0 else None
|
return items[0] if items else None
|
||||||
|
|
||||||
|
|
||||||
def show_artist_albums(artist):
|
def show_artist_albums(artist):
|
||||||
@ -35,7 +35,7 @@ def show_artist_albums(artist):
|
|||||||
for album in albums:
|
for album in albums:
|
||||||
name = album['name']
|
name = album['name']
|
||||||
if name not in seen:
|
if name not in seen:
|
||||||
logger.info('ALBUM: %s', name)
|
logger.info(f'ALBUM: {name}')
|
||||||
seen.add(name)
|
seen.add(name)
|
||||||
|
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ def main():
|
|||||||
if artist:
|
if artist:
|
||||||
show_artist_albums(artist)
|
show_artist_albums(artist)
|
||||||
else:
|
else:
|
||||||
logger.error("Can't find artist: %s", artist)
|
logger.error(f"Can't find artist: {artist}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@ -20,7 +20,7 @@ def get_args():
|
|||||||
def get_artist(name):
|
def get_artist(name):
|
||||||
results = sp.search(q=f'artist:{name}', type='artist')
|
results = sp.search(q=f'artist:{name}', type='artist')
|
||||||
items = results['artists']['items']
|
items = results['artists']['items']
|
||||||
return items[0] if len(items) > 0 else None
|
return items[0] if items else None
|
||||||
|
|
||||||
|
|
||||||
def show_album_tracks(album):
|
def show_album_tracks(album):
|
||||||
@ -31,7 +31,7 @@ def show_album_tracks(album):
|
|||||||
results = sp.next(results)
|
results = sp.next(results)
|
||||||
tracks.extend(results['items'])
|
tracks.extend(results['items'])
|
||||||
for i, track in enumerate(tracks):
|
for i, track in enumerate(tracks):
|
||||||
logger.info('%s. %s', i + 1, track['name'])
|
logger.info(f'{i + 1}. {track["name"]}')
|
||||||
|
|
||||||
|
|
||||||
def show_artist_albums(artist):
|
def show_artist_albums(artist):
|
||||||
@ -41,21 +41,21 @@ def show_artist_albums(artist):
|
|||||||
while results['next']:
|
while results['next']:
|
||||||
results = sp.next(results)
|
results = sp.next(results)
|
||||||
albums.extend(results['items'])
|
albums.extend(results['items'])
|
||||||
logger.info('Total albums: %s', len(albums))
|
logger.info(f'Total albums: {len(albums)}')
|
||||||
unique = set() # skip duplicate albums
|
unique = set() # skip duplicate albums
|
||||||
for album in albums:
|
for album in albums:
|
||||||
name = album['name'].lower()
|
name = album['name'].lower()
|
||||||
if name not in unique:
|
if name not in unique:
|
||||||
logger.info('ALBUM: %s', name)
|
logger.info(f'ALBUM: {name}')
|
||||||
unique.add(name)
|
unique.add(name)
|
||||||
show_album_tracks(album)
|
show_album_tracks(album)
|
||||||
|
|
||||||
|
|
||||||
def show_artist(artist):
|
def show_artist(artist):
|
||||||
logger.info('====%s====', artist['name'])
|
logger.info(f'===={artist["name"]}====')
|
||||||
logger.info('Popularity: %s', artist['popularity'])
|
logger.info(f'Popularity: {artist["popularity"]}')
|
||||||
if len(artist['genres']) > 0:
|
if len(artist['genres']) > 0:
|
||||||
logger.info('Genres: %s', ','.join(artist['genres']))
|
logger.info(f"Genres: {', '.join(artist['genres'])}")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@ -22,14 +22,13 @@ def get_args():
|
|||||||
def get_artist(name):
|
def get_artist(name):
|
||||||
results = sp.search(q=f'artist:{name}', type='artist')
|
results = sp.search(q=f'artist:{name}', type='artist')
|
||||||
items = results['artists']['items']
|
items = results['artists']['items']
|
||||||
return items[0] if len(items) > 0 else None
|
return items[0] if items else None
|
||||||
|
|
||||||
|
|
||||||
def show_recommendations_for_artist(artist):
|
def show_recommendations_for_artist(artist):
|
||||||
results = sp.recommendations(seed_artists=[artist['id']])
|
results = sp.recommendations(seed_artists=[artist['id']])
|
||||||
for track in results['tracks']:
|
for track in results['tracks']:
|
||||||
logger.info('Recommendation: %s - %s', track['name'],
|
logger.info(f'Recommendation: {track["name"]} - {track["artists"][0]["name"]}')
|
||||||
track['artists'][0]['name'])
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@ -16,7 +16,9 @@ def get_args():
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
args = get_args()
|
args = get_args()
|
||||||
sp.current_user_follow_playlist(args.playlist)
|
# Uses Lofi Girl playlist
|
||||||
|
playlist = args.playlist or '0vvXsWCC9xrXsKd4FyS8kM'
|
||||||
|
spotipy.Spotify(auth_manager=SpotifyOAuth()).current_user_follow_playlist(playlist)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
@ -8,4 +8,4 @@ sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope))
|
|||||||
|
|
||||||
results = sp.current_user_playlists(limit=50)
|
results = sp.current_user_playlists(limit=50)
|
||||||
for i, item in enumerate(results['items']):
|
for i, item in enumerate(results['items']):
|
||||||
print("%d %s" % (i, item['name']))
|
print(f"{i} {item['name']}")
|
||||||
|
|||||||
@ -9,7 +9,7 @@ scope = 'user-library-read'
|
|||||||
def show_tracks(results):
|
def show_tracks(results):
|
||||||
for item in results['items']:
|
for item in results['items']:
|
||||||
track = item['track']
|
track = item['track']
|
||||||
print("%32.32s %s" % (track['artists'][0]['name'], track['name']))
|
print(f"{track['artists'][0]['name']:>32.32} {track['name']}")
|
||||||
|
|
||||||
|
|
||||||
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope))
|
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope))
|
||||||
|
|||||||
@ -38,6 +38,5 @@ recommendations = sp.recommendations(
|
|||||||
|
|
||||||
# Display the recommendations
|
# Display the recommendations
|
||||||
for i, track in enumerate(recommendations['tracks']):
|
for i, track in enumerate(recommendations['tracks']):
|
||||||
print(
|
print(f"{i+1}. {track['name']} by "
|
||||||
f"{i+1}. {track['name']} by {', '.join([artist['name'] for artist in track['artists']])}"
|
f"{', '.join([artist['name'] for artist in track['artists']])}")
|
||||||
)
|
|
||||||
|
|||||||
@ -7,9 +7,7 @@ from spotipy.oauth2 import SpotifyOAuth
|
|||||||
def show_tracks(results):
|
def show_tracks(results):
|
||||||
for i, item in enumerate(results['items']):
|
for i, item in enumerate(results['items']):
|
||||||
track = item['track']
|
track = item['track']
|
||||||
print(
|
print(f" {i} {track['artists'][0]['name']:>32.32} {track['name']}")
|
||||||
" %d %32.32s %s" %
|
|
||||||
(i, track['artists'][0]['name'], track['name']))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@ -14,11 +14,8 @@ playlists = sp.user_playlists(user)
|
|||||||
|
|
||||||
while playlists:
|
while playlists:
|
||||||
for i, playlist in enumerate(playlists['items']):
|
for i, playlist in enumerate(playlists['items']):
|
||||||
print(
|
print(f"{i + 1 + playlists['offset']:4d} {playlist['uri']} {playlist['name']}")
|
||||||
"%4d %s %s" %
|
if playlists['next']:
|
||||||
(i +
|
playlists = sp.next(playlists)
|
||||||
1 +
|
else:
|
||||||
playlists['offset'],
|
playlists = None
|
||||||
playlist['uri'],
|
|
||||||
playlist['name']))
|
|
||||||
playlists = sp.next(playlists) if playlists['next'] else None
|
|
||||||
|
|||||||
@ -94,7 +94,7 @@ class CacheFileHandler(CacheHandler):
|
|||||||
f.write(json.dumps(token_info, cls=self.encoder_cls))
|
f.write(json.dumps(token_info, cls=self.encoder_cls))
|
||||||
f.close()
|
f.close()
|
||||||
except OSError:
|
except OSError:
|
||||||
logger.warning(f'Couldn\'t write token to cache at: {self.cache_path}')
|
logger.warning(f"Couldn't write token to cache at: {self.cache_path}")
|
||||||
|
|
||||||
|
|
||||||
class MemoryCacheHandler(CacheHandler):
|
class MemoryCacheHandler(CacheHandler):
|
||||||
@ -147,7 +147,7 @@ class DjangoSessionCacheHandler(CacheHandler):
|
|||||||
try:
|
try:
|
||||||
self.request.session['token_info'] = token_info
|
self.request.session['token_info'] = token_info
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Error saving token to cache: {str(e)}")
|
logger.warning(f"Error saving token to cache: {e}")
|
||||||
|
|
||||||
|
|
||||||
class FlaskSessionCacheHandler(CacheHandler):
|
class FlaskSessionCacheHandler(CacheHandler):
|
||||||
@ -172,7 +172,7 @@ class FlaskSessionCacheHandler(CacheHandler):
|
|||||||
try:
|
try:
|
||||||
self.session["token_info"] = token_info
|
self.session["token_info"] = token_info
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Error saving token to cache: {str(e)}")
|
logger.warning(f"Error saving token to cache: {e}")
|
||||||
|
|
||||||
|
|
||||||
class RedisCacheHandler(CacheHandler):
|
class RedisCacheHandler(CacheHandler):
|
||||||
@ -198,7 +198,7 @@ class RedisCacheHandler(CacheHandler):
|
|||||||
if token_info:
|
if token_info:
|
||||||
return json.loads(token_info)
|
return json.loads(token_info)
|
||||||
except RedisError as e:
|
except RedisError as e:
|
||||||
logger.warning(f'Error getting token from cache: {str(e)}')
|
logger.warning(f"Error getting token from cache: {e}")
|
||||||
|
|
||||||
return token_info
|
return token_info
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ class RedisCacheHandler(CacheHandler):
|
|||||||
try:
|
try:
|
||||||
self.redis.set(self.key, json.dumps(token_info))
|
self.redis.set(self.key, json.dumps(token_info))
|
||||||
except RedisError as e:
|
except RedisError as e:
|
||||||
logger.warning(f'Error saving token to cache: {str(e)}')
|
logger.warning(f"Error saving token to cache: {e}")
|
||||||
|
|
||||||
|
|
||||||
class MemcacheCacheHandler(CacheHandler):
|
class MemcacheCacheHandler(CacheHandler):
|
||||||
@ -231,11 +231,11 @@ class MemcacheCacheHandler(CacheHandler):
|
|||||||
if token_info:
|
if token_info:
|
||||||
return json.loads(token_info.decode())
|
return json.loads(token_info.decode())
|
||||||
except MemcacheError as e:
|
except MemcacheError as e:
|
||||||
logger.warning(f'Error getting token from cache: {str(e)}')
|
logger.warning(f"Error getting token to cache: {e}")
|
||||||
|
|
||||||
def save_token_to_cache(self, token_info):
|
def save_token_to_cache(self, token_info):
|
||||||
from pymemcache import MemcacheError
|
from pymemcache import MemcacheError
|
||||||
try:
|
try:
|
||||||
self.memcache.set(self.key, json.dumps(token_info))
|
self.memcache.set(self.key, json.dumps(token_info))
|
||||||
except MemcacheError as e:
|
except MemcacheError as e:
|
||||||
logger.warning(f'Error saving token to cache: {str(e)}')
|
logger.warning(f"Error saving token to cache: {e}")
|
||||||
|
|||||||
@ -247,8 +247,8 @@ class Spotify:
|
|||||||
if self.language is not None:
|
if self.language is not None:
|
||||||
headers["Accept-Language"] = self.language
|
headers["Accept-Language"] = self.language
|
||||||
|
|
||||||
logger.debug('Sending %s to %s with Params: %s Headers: %s and Body: %r ',
|
logger.debug(f"Sending {method} to {url} with Params: "
|
||||||
method, url, args.get("params"), headers, args.get('data'))
|
f"{args.get('params')} Headers: {headers} and Body: {args.get('data')!r}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = self._session.request(
|
response = self._session.request(
|
||||||
@ -273,10 +273,8 @@ class Spotify:
|
|||||||
msg = response.text or None
|
msg = response.text or None
|
||||||
reason = None
|
reason = None
|
||||||
|
|
||||||
logger.error(
|
logger.error(f"HTTP Error for {method} to {url} with Params: "
|
||||||
'HTTP Error for %s to %s with Params: %s returned %s due to %s',
|
f"{args.get('params')} returned {response.status_code} due to {msg}")
|
||||||
method, url, args.get("params"), response.status_code, msg
|
|
||||||
)
|
|
||||||
|
|
||||||
raise SpotifyException(
|
raise SpotifyException(
|
||||||
response.status_code,
|
response.status_code,
|
||||||
@ -301,7 +299,7 @@ class Spotify:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
results = None
|
results = None
|
||||||
|
|
||||||
logger.debug('RESULTS: %s', results)
|
logger.debug(f'RESULTS: {results}')
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def _get(self, url, args=None, payload=None, **kwargs):
|
def _get(self, url, args=None, payload=None, **kwargs):
|
||||||
@ -1723,10 +1721,9 @@ class Spotify:
|
|||||||
def _search_multiple_markets(self, q, limit, offset, type, markets, total):
|
def _search_multiple_markets(self, q, limit, offset, type, markets, total):
|
||||||
if total and limit > total:
|
if total and limit > total:
|
||||||
limit = total
|
limit = total
|
||||||
warnings.warn(
|
warnings.warn(f"limit was auto-adjusted to equal {total} "
|
||||||
f"limit was auto-adjusted to equal {total} as it must not be higher than total",
|
f"as it must not be higher than total",
|
||||||
UserWarning,
|
UserWarning)
|
||||||
)
|
|
||||||
|
|
||||||
results = defaultdict(dict)
|
results = defaultdict(dict)
|
||||||
item_types = [f"{item_type}s" for item_type in type.split(",")]
|
item_types = [f"{item_type}s" for item_type in type.split(",")]
|
||||||
|
|||||||
@ -16,8 +16,9 @@ class SpotifyException(SpotifyBaseException):
|
|||||||
self.headers = headers
|
self.headers = headers
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'http status: {}, code:{} - {}, reason: {}'.format(
|
return (f"http status: {self.http_status}, "
|
||||||
self.http_status, self.code, self.msg, self.reason)
|
f"code: {self.code} - {self.msg}, "
|
||||||
|
f"reason: {self.reason}")
|
||||||
|
|
||||||
|
|
||||||
class SpotifyOauthError(SpotifyBaseException):
|
class SpotifyOauthError(SpotifyBaseException):
|
||||||
|
|||||||
@ -241,10 +241,8 @@ class SpotifyClientCredentials(SpotifyAuthBase):
|
|||||||
self.client_id, self.client_secret
|
self.client_id, self.client_secret
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(f"Sending POST request to {self.OAUTH_TOKEN_URL} with Headers: "
|
||||||
"sending POST request to %s with Headers: %s and Body: %r",
|
f"{headers} and Body: {payload}")
|
||||||
self.OAUTH_TOKEN_URL, headers, payload
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = self._session.post(
|
response = self._session.post(
|
||||||
@ -404,9 +402,9 @@ class SpotifyOAuth(SpotifyAuthBase):
|
|||||||
auth_url = self.get_authorize_url()
|
auth_url = self.get_authorize_url()
|
||||||
try:
|
try:
|
||||||
webbrowser.open(auth_url)
|
webbrowser.open(auth_url)
|
||||||
logger.info("Opened %s in your browser", auth_url)
|
logger.info(f"Opened {auth_url} in your browser")
|
||||||
except webbrowser.Error:
|
except webbrowser.Error:
|
||||||
logger.error("Please navigate here: %s", auth_url)
|
logger.error(f"Please navigate here: {auth_url}")
|
||||||
|
|
||||||
def _get_auth_response_interactive(self, open_browser=False):
|
def _get_auth_response_interactive(self, open_browser=False):
|
||||||
if open_browser:
|
if open_browser:
|
||||||
@ -414,7 +412,10 @@ class SpotifyOAuth(SpotifyAuthBase):
|
|||||||
prompt = "Enter the URL you were redirected to: "
|
prompt = "Enter the URL you were redirected to: "
|
||||||
else:
|
else:
|
||||||
url = self.get_authorize_url()
|
url = self.get_authorize_url()
|
||||||
prompt = f"Go to the following URL: {url}\nEnter the URL you were redirected to: "
|
prompt = (
|
||||||
|
f"Go to the following URL: {url}\n"
|
||||||
|
"Enter the URL you were redirected to: "
|
||||||
|
)
|
||||||
response = self._get_user_input(prompt)
|
response = self._get_user_input(prompt)
|
||||||
state, code = SpotifyOAuth.parse_auth_response_url(response)
|
state, code = SpotifyOAuth.parse_auth_response_url(response)
|
||||||
if self.state is not None and self.state != state:
|
if self.state is not None and self.state != state:
|
||||||
@ -457,12 +458,11 @@ class SpotifyOAuth(SpotifyAuthBase):
|
|||||||
if redirect_port:
|
if redirect_port:
|
||||||
return self._get_auth_response_local_server(redirect_port)
|
return self._get_auth_response_local_server(redirect_port)
|
||||||
else:
|
else:
|
||||||
logger.warning('Using `%s` as redirect URI without a port. '
|
logger.warning(f'Using `{redirect_host}` as redirect URI without a port. '
|
||||||
'Specify a port (e.g. `%s:8080`) to allow '
|
f'Specify a port (e.g. `{redirect_host}:8080`) to allow '
|
||||||
'automatic retrieval of authentication code '
|
'automatic retrieval of authentication code '
|
||||||
'instead of having to copy and paste '
|
'instead of having to copy and paste '
|
||||||
'the URL your browser is redirected to.',
|
'the URL your browser is redirected to.')
|
||||||
redirect_host, redirect_host)
|
|
||||||
|
|
||||||
return self._get_auth_response_interactive(open_browser=open_browser)
|
return self._get_auth_response_interactive(open_browser=open_browser)
|
||||||
|
|
||||||
@ -500,10 +500,8 @@ class SpotifyOAuth(SpotifyAuthBase):
|
|||||||
|
|
||||||
headers = self._make_authorization_headers()
|
headers = self._make_authorization_headers()
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(f"Sending POST request to {self.OAUTH_TOKEN_URL} with Headers: "
|
||||||
"sending POST request to %s with Headers: %s and Body: %r",
|
f"{headers} and Body: {payload}")
|
||||||
self.OAUTH_TOKEN_URL, headers, payload
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = self._session.post(
|
response = self._session.post(
|
||||||
@ -530,10 +528,8 @@ class SpotifyOAuth(SpotifyAuthBase):
|
|||||||
|
|
||||||
headers = self._make_authorization_headers()
|
headers = self._make_authorization_headers()
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(f"Sending POST request to {self.OAUTH_TOKEN_URL} with Headers: "
|
||||||
"sending POST request to %s with Headers: %s and Body: %r",
|
f"{headers} and Body: {payload}")
|
||||||
self.OAUTH_TOKEN_URL, headers, payload
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = self._session.post(
|
response = self._session.post(
|
||||||
@ -696,9 +692,9 @@ class SpotifyPKCE(SpotifyAuthBase):
|
|||||||
auth_url = self.get_authorize_url(state)
|
auth_url = self.get_authorize_url(state)
|
||||||
try:
|
try:
|
||||||
webbrowser.open(auth_url)
|
webbrowser.open(auth_url)
|
||||||
logger.info("Opened %s in your browser", auth_url)
|
logger.info(f"Opened {auth_url} in your browser")
|
||||||
except webbrowser.Error:
|
except webbrowser.Error:
|
||||||
logger.error("Please navigate here: %s", auth_url)
|
logger.error(f"Please navigate here: {auth_url}")
|
||||||
|
|
||||||
def _get_auth_response(self, open_browser=None):
|
def _get_auth_response(self, open_browser=None):
|
||||||
logger.info('User authentication requires interaction with your '
|
logger.info('User authentication requires interaction with your '
|
||||||
@ -722,12 +718,11 @@ class SpotifyPKCE(SpotifyAuthBase):
|
|||||||
if redirect_port:
|
if redirect_port:
|
||||||
return self._get_auth_response_local_server(redirect_port)
|
return self._get_auth_response_local_server(redirect_port)
|
||||||
else:
|
else:
|
||||||
logger.warning('Using `%s` as redirect URI without a port. '
|
logger.warning(f'Using `{redirect_host}` as redirect URI without a port. '
|
||||||
'Specify a port (e.g. `%s:8080`) to allow '
|
f'Specify a port (e.g. `{redirect_host}:8080`) to allow '
|
||||||
'automatic retrieval of authentication code '
|
'automatic retrieval of authentication code '
|
||||||
'instead of having to copy and paste '
|
'instead of having to copy and paste '
|
||||||
'the URL your browser is redirected to.',
|
'the URL your browser is redirected to.')
|
||||||
redirect_host, redirect_host)
|
|
||||||
return self._get_auth_response_interactive(open_browser=open_browser)
|
return self._get_auth_response_interactive(open_browser=open_browser)
|
||||||
|
|
||||||
def _get_auth_response_local_server(self, redirect_port):
|
def _get_auth_response_local_server(self, redirect_port):
|
||||||
@ -751,7 +746,8 @@ class SpotifyPKCE(SpotifyAuthBase):
|
|||||||
prompt = "Enter the URL you were redirected to: "
|
prompt = "Enter the URL you were redirected to: "
|
||||||
else:
|
else:
|
||||||
url = self.get_authorize_url()
|
url = self.get_authorize_url()
|
||||||
prompt = f"Go to the following URL: {url}\nEnter the URL you were redirected to: "
|
prompt = (f"Go to the following URL: {url}\n"
|
||||||
|
f"Enter the URL you were redirected to: ")
|
||||||
response = self._get_user_input(prompt)
|
response = self._get_user_input(prompt)
|
||||||
state, code = self.parse_auth_response_url(response)
|
state, code = self.parse_auth_response_url(response)
|
||||||
if self.state is not None and self.state != state:
|
if self.state is not None and self.state != state:
|
||||||
@ -827,10 +823,8 @@ class SpotifyPKCE(SpotifyAuthBase):
|
|||||||
|
|
||||||
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(f"Sending POST request to {self.OAUTH_TOKEN_URL} with Headers: "
|
||||||
"sending POST request to %s with Headers: %s and Body: %r",
|
f"{headers} and Body: {payload}")
|
||||||
self.OAUTH_TOKEN_URL, headers, payload
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = self._session.post(
|
response = self._session.post(
|
||||||
@ -858,10 +852,8 @@ class SpotifyPKCE(SpotifyAuthBase):
|
|||||||
|
|
||||||
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(f"Sending POST request to {self.OAUTH_TOKEN_URL} with Headers: "
|
||||||
"sending POST request to %s with Headers: %s and Body: %r",
|
f"{headers} and Body: {payload}")
|
||||||
self.OAUTH_TOKEN_URL, headers, payload
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = self._session.post(
|
response = self._session.post(
|
||||||
|
|||||||
@ -533,7 +533,7 @@ class SpotifyQueueApiTests(unittest.TestCase):
|
|||||||
self.spotify.add_to_queue(test_uri)
|
self.spotify.add_to_queue(test_uri)
|
||||||
|
|
||||||
# Check if the correct endpoint is called
|
# Check if the correct endpoint is called
|
||||||
endpoint = "me/player/queue?uri=%s" % test_uri
|
endpoint = f"me/player/queue?uri={test_uri}"
|
||||||
mock_post.assert_called_with(endpoint)
|
mock_post.assert_called_with(endpoint)
|
||||||
|
|
||||||
def test_add_to_queue_with_device_id(self, mock_post):
|
def test_add_to_queue_with_device_id(self, mock_post):
|
||||||
@ -544,5 +544,5 @@ class SpotifyQueueApiTests(unittest.TestCase):
|
|||||||
self.spotify.add_to_queue(test_uri, device_id=device_id)
|
self.spotify.add_to_queue(test_uri, device_id=device_id)
|
||||||
|
|
||||||
# Check if the correct endpoint is called
|
# Check if the correct endpoint is called
|
||||||
endpoint = "me/player/queue?uri=%s&device_id=%s" % (test_uri, device_id)
|
endpoint = f"me/player/queue?uri={test_uri}&device_id={device_id}"
|
||||||
mock_post.assert_called_with(endpoint)
|
mock_post.assert_called_with(endpoint)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user