code time
This commit is contained in:
parent
789a5e0b02
commit
ae28da8d60
153 changed files with 56768 additions and 1 deletions
5
resources/lib/deps/spotipy/__init__.py
Normal file
5
resources/lib/deps/spotipy/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from .cache_handler import * # noqa
|
||||
from .client import * # noqa
|
||||
from .exceptions import * # noqa
|
||||
from .oauth2 import * # noqa
|
||||
from .util import * # noqa
|
173
resources/lib/deps/spotipy/cache_handler.py
Normal file
173
resources/lib/deps/spotipy/cache_handler.py
Normal file
|
@ -0,0 +1,173 @@
|
|||
__all__ = [
|
||||
'CacheHandler',
|
||||
'CacheFileHandler',
|
||||
'DjangoSessionCacheHandler',
|
||||
'FlaskSessionCacheHandler',
|
||||
'MemoryCacheHandler']
|
||||
|
||||
import errno
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from spotipy.util import CLIENT_CREDS_ENV_VARS
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CacheHandler():
|
||||
"""
|
||||
An abstraction layer for handling the caching and retrieval of
|
||||
authorization tokens.
|
||||
|
||||
Custom extensions of this class must implement get_cached_token
|
||||
and save_token_to_cache methods with the same input and output
|
||||
structure as the CacheHandler class.
|
||||
"""
|
||||
|
||||
def get_cached_token(self):
|
||||
"""
|
||||
Get and return a token_info dictionary object.
|
||||
"""
|
||||
# return token_info
|
||||
raise NotImplementedError()
|
||||
|
||||
def save_token_to_cache(self, token_info):
|
||||
"""
|
||||
Save a token_info dictionary object to the cache and return None.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
return None
|
||||
|
||||
|
||||
class CacheFileHandler(CacheHandler):
|
||||
"""
|
||||
Handles reading and writing cached Spotify authorization tokens
|
||||
as json files on disk.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
cache_path=None,
|
||||
username=None,
|
||||
encoder_cls=None):
|
||||
"""
|
||||
Parameters:
|
||||
* cache_path: May be supplied, will otherwise be generated
|
||||
(takes precedence over `username`)
|
||||
* username: May be supplied or set as environment variable
|
||||
(will set `cache_path` to `.cache-{username}`)
|
||||
* encoder_cls: May be supplied as a means of overwriting the
|
||||
default serializer used for writing tokens to disk
|
||||
"""
|
||||
self.encoder_cls = encoder_cls
|
||||
if cache_path:
|
||||
self.cache_path = cache_path
|
||||
else:
|
||||
cache_path = ".cache"
|
||||
username = (username or os.getenv(CLIENT_CREDS_ENV_VARS["client_username"]))
|
||||
if username:
|
||||
cache_path += "-" + str(username)
|
||||
self.cache_path = cache_path
|
||||
|
||||
def get_cached_token(self):
|
||||
token_info = None
|
||||
|
||||
try:
|
||||
f = open(self.cache_path)
|
||||
token_info_string = f.read()
|
||||
f.close()
|
||||
token_info = json.loads(token_info_string)
|
||||
|
||||
except IOError as error:
|
||||
if error.errno == errno.ENOENT:
|
||||
logger.debug("cache does not exist at: %s", self.cache_path)
|
||||
else:
|
||||
logger.warning("Couldn't read cache at: %s", self.cache_path)
|
||||
|
||||
return token_info
|
||||
|
||||
def save_token_to_cache(self, token_info):
|
||||
try:
|
||||
f = open(self.cache_path, "w")
|
||||
f.write(json.dumps(token_info, cls=self.encoder_cls))
|
||||
f.close()
|
||||
except IOError:
|
||||
logger.warning('Couldn\'t write token to cache at: %s',
|
||||
self.cache_path)
|
||||
|
||||
|
||||
class MemoryCacheHandler(CacheHandler):
|
||||
"""
|
||||
A cache handler that simply stores the token info in memory as an
|
||||
instance attribute of this class. The token info will be lost when this
|
||||
instance is freed.
|
||||
"""
|
||||
|
||||
def __init__(self, token_info=None):
|
||||
"""
|
||||
Parameters:
|
||||
* token_info: The token info to store in memory. Can be None.
|
||||
"""
|
||||
self.token_info = token_info
|
||||
|
||||
def get_cached_token(self):
|
||||
return self.token_info
|
||||
|
||||
def save_token_to_cache(self, token_info):
|
||||
self.token_info = token_info
|
||||
|
||||
|
||||
class DjangoSessionCacheHandler(CacheHandler):
|
||||
"""
|
||||
A cache handler that stores the token info in the session framework
|
||||
provided by Django.
|
||||
|
||||
Read more at https://docs.djangoproject.com/en/3.2/topics/http/sessions/
|
||||
"""
|
||||
|
||||
def __init__(self, request):
|
||||
"""
|
||||
Parameters:
|
||||
* request: HttpRequest object provided by Django for every
|
||||
incoming request
|
||||
"""
|
||||
self.request = request
|
||||
|
||||
def get_cached_token(self):
|
||||
token_info = None
|
||||
try:
|
||||
token_info = self.request.session['token_info']
|
||||
except KeyError:
|
||||
logger.debug("Token not found in the session")
|
||||
|
||||
return token_info
|
||||
|
||||
def save_token_to_cache(self, token_info):
|
||||
try:
|
||||
self.request.session['token_info'] = token_info
|
||||
except Exception as e:
|
||||
logger.warning("Error saving token to cache: " + str(e))
|
||||
|
||||
|
||||
class FlaskSessionCacheHandler(CacheHandler):
|
||||
"""
|
||||
A cache handler that stores the token info in the session framework
|
||||
provided by flask.
|
||||
"""
|
||||
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
||||
def get_cached_token(self):
|
||||
token_info = None
|
||||
try:
|
||||
token_info = self.session["token_info"]
|
||||
except KeyError:
|
||||
logger.debug("Token not found in the session")
|
||||
|
||||
return token_info
|
||||
|
||||
def save_token_to_cache(self, token_info):
|
||||
try:
|
||||
self.session["token_info"] = token_info
|
||||
except Exception as e:
|
||||
logger.warning("Error saving token to cache: " + str(e))
|
2035
resources/lib/deps/spotipy/client.py
Normal file
2035
resources/lib/deps/spotipy/client.py
Normal file
File diff suppressed because it is too large
Load diff
16
resources/lib/deps/spotipy/exceptions.py
Normal file
16
resources/lib/deps/spotipy/exceptions.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
class SpotifyException(Exception):
|
||||
|
||||
def __init__(self, http_status, code, msg, reason=None, headers=None):
|
||||
self.http_status = http_status
|
||||
self.code = code
|
||||
self.msg = msg
|
||||
self.reason = reason
|
||||
# `headers` is used to support `Retry-After` in the event of a
|
||||
# 429 status code.
|
||||
if headers is None:
|
||||
headers = {}
|
||||
self.headers = headers
|
||||
|
||||
def __str__(self):
|
||||
return 'http status: {0}, code:{1} - {2}, reason: {3}'.format(
|
||||
self.http_status, self.code, self.msg, self.reason)
|
1308
resources/lib/deps/spotipy/oauth2.py
Normal file
1308
resources/lib/deps/spotipy/oauth2.py
Normal file
File diff suppressed because it is too large
Load diff
135
resources/lib/deps/spotipy/util.py
Normal file
135
resources/lib/deps/spotipy/util.py
Normal file
|
@ -0,0 +1,135 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
""" Shows a user's playlists (need to be authenticated via oauth) """
|
||||
|
||||
__all__ = ["CLIENT_CREDS_ENV_VARS", "prompt_for_user_token"]
|
||||
|
||||
import logging
|
||||
import os
|
||||
import warnings
|
||||
|
||||
import spotipy
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CLIENT_CREDS_ENV_VARS = {
|
||||
"client_id": "SPOTIPY_CLIENT_ID",
|
||||
"client_secret": "SPOTIPY_CLIENT_SECRET",
|
||||
"client_username": "SPOTIPY_CLIENT_USERNAME",
|
||||
"redirect_uri": "SPOTIPY_REDIRECT_URI",
|
||||
}
|
||||
|
||||
|
||||
def prompt_for_user_token(
|
||||
username=None,
|
||||
scope=None,
|
||||
client_id=None,
|
||||
client_secret=None,
|
||||
redirect_uri=None,
|
||||
cache_path=None,
|
||||
oauth_manager=None,
|
||||
show_dialog=False
|
||||
):
|
||||
warnings.warn(
|
||||
"'prompt_for_user_token' is deprecated."
|
||||
"Use the following instead: "
|
||||
" auth_manager=SpotifyOAuth(scope=scope)"
|
||||
" spotipy.Spotify(auth_manager=auth_manager)",
|
||||
DeprecationWarning
|
||||
)
|
||||
""" prompts the user to login if necessary and returns
|
||||
the user token suitable for use with the spotipy.Spotify
|
||||
constructor
|
||||
|
||||
Parameters:
|
||||
|
||||
- username - the Spotify username (optional)
|
||||
- scope - the desired scope of the request (optional)
|
||||
- client_id - the client id of your app (required)
|
||||
- client_secret - the client secret of your app (required)
|
||||
- redirect_uri - the redirect URI of your app (required)
|
||||
- cache_path - path to location to save tokens (optional)
|
||||
- oauth_manager - Oauth manager object (optional)
|
||||
- show_dialog - If true, a login prompt always shows (optional, defaults to False)
|
||||
|
||||
"""
|
||||
if not oauth_manager:
|
||||
if not client_id:
|
||||
client_id = os.getenv("SPOTIPY_CLIENT_ID")
|
||||
|
||||
if not client_secret:
|
||||
client_secret = os.getenv("SPOTIPY_CLIENT_SECRET")
|
||||
|
||||
if not redirect_uri:
|
||||
redirect_uri = os.getenv("SPOTIPY_REDIRECT_URI")
|
||||
|
||||
if not client_id:
|
||||
LOGGER.warning(
|
||||
"""
|
||||
You need to set your Spotify API credentials.
|
||||
You can do this by setting environment variables like so:
|
||||
|
||||
export SPOTIPY_CLIENT_ID='your-spotify-client-id'
|
||||
export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
|
||||
export SPOTIPY_REDIRECT_URI='your-app-redirect-url'
|
||||
|
||||
Get your credentials at
|
||||
https://developer.spotify.com/my-applications
|
||||
"""
|
||||
)
|
||||
raise spotipy.SpotifyException(550, -1, "no credentials set")
|
||||
|
||||
sp_oauth = oauth_manager or spotipy.SpotifyOAuth(
|
||||
client_id,
|
||||
client_secret,
|
||||
redirect_uri,
|
||||
scope=scope,
|
||||
cache_path=cache_path,
|
||||
username=username,
|
||||
show_dialog=show_dialog
|
||||
)
|
||||
|
||||
# try to get a valid token for this user, from the cache,
|
||||
# if not in the cache, then create a new (this will send
|
||||
# the user to a web page where they can authorize this app)
|
||||
|
||||
token_info = sp_oauth.validate_token(sp_oauth.cache_handler.get_cached_token())
|
||||
|
||||
if not token_info:
|
||||
code = sp_oauth.get_auth_response()
|
||||
token = sp_oauth.get_access_token(code, as_dict=False)
|
||||
else:
|
||||
return token_info["access_token"]
|
||||
|
||||
# Auth'ed API request
|
||||
if token:
|
||||
return token
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_host_port(netloc):
|
||||
if ":" in netloc:
|
||||
host, port = netloc.split(":", 1)
|
||||
port = int(port)
|
||||
else:
|
||||
host = netloc
|
||||
port = None
|
||||
|
||||
return host, port
|
||||
|
||||
|
||||
def normalize_scope(scope):
|
||||
if scope:
|
||||
if isinstance(scope, str):
|
||||
scopes = scope.split(',')
|
||||
elif isinstance(scope, list) or isinstance(scope, tuple):
|
||||
scopes = scope
|
||||
else:
|
||||
raise Exception(
|
||||
"Unsupported scope value, please either provide a list of scopes, "
|
||||
"or a string of scopes separated by commas"
|
||||
)
|
||||
return " ".join(sorted(scopes))
|
||||
else:
|
||||
return None
|
Loading…
Add table
Add a link
Reference in a new issue