Authenticating services

This commit is contained in:
Ritiek Malhotra
2020-04-02 04:14:07 +05:30
parent 2bb9a965f5
commit 121fcdcdf6
13 changed files with 157 additions and 12 deletions

View File

@@ -16,8 +16,11 @@ setup(
"spotdl.lyrics.providers", "spotdl.lyrics.providers",
"spotdl.encode", "spotdl.encode",
"spotdl.encode.encoders", "spotdl.encode.encoders",
"spotdl.downloaders", "spotdl.metadata",
"spotdl.patch", "spotdl.metadata.embedders",
"spotdl.metadata.providers",
"spotdl.authorize",
"spotdl.authorize.services",
], ],
version=spotdl.__version__, version=spotdl.__version__,
install_requires=[ install_requires=[

View File

@@ -0,0 +1,6 @@
from spotdl.authorize.authorize_base import AuthorizeBase
from spotdl.authorize.exceptions import AuthorizationError
from spotdl.authorize.exceptions import SpotifyAuthorizationError
from spotdl.authorize.exceptions import YouTubeAuthorizationError

View File

@@ -0,0 +1,19 @@
from abc import ABC
from abc import abstractmethod
class AuthorizeBase(ABC):
"""
Defined service authenticators must inherit from this abstract
base class and implement their own functionality for the below
defined methods.
"""
@abstractmethod
def authorize(self):
"""
This method must authorize with the corresponding service
and return an object that can be utilized in making
authenticated requests.
"""
pass

View File

@@ -0,0 +1,20 @@
class AuthorizationError(Exception):
__module__ = Exception.__module__
def __init__(self, message=None):
super().__init__(message)
class SpotifyAuthorizationError(AuthorizationError):
__module__ = Exception.__module__
def __init__(self, message=None):
super().__init__(message)
class YouTubeAuthorizationError(AuthorizationError):
__module__ = Exception.__module__
def __init__(self, message=None):
super().__init__(message)

View File

@@ -0,0 +1,2 @@
from spotdl.authorize.services.spotify import AuthorizeSpotify

View File

@@ -0,0 +1,55 @@
from spotdl.authorize import AuthorizeBase
from spotdl.authorize.exceptions import SpotifyAuthorizationError
import spotipy
import spotipy.oauth2 as oauth2
# This global_client is used to keep the last logged-in client
# object in memory for for persistence. If credentials aren't
# provided when creating further objects, the last authenticated
# client object with correct credentials is returned when
# `AuthorizeSpotify().authorize()` is called.
global_client = None
class AuthorizeSpotify(AuthorizeBase):
def __init__(self):
global global_client
self._client = global_client
def _generate_token(self, client_id, client_secret):
""" Generate the token. """
credentials = oauth2.SpotifyClientCredentials(
client_id=client_id,
client_secret=client_secret,
)
token = credentials.get_access_token()
return token
def authorize(self, client_id=None, client_secret=None):
no_credentials_provided = client_id is None and client_secret is None
not_valid_input = no_credentials_provided and self._client is None
if not_valid_input:
raise SpotifyAuthorizationError(
"You must pass in client_id and client_secret to this method "
"when authenticating for the first time."
)
if no_credentials_provided:
return self._client
try:
token = self._generate_token(client_id, client_secret)
except spotipy.SpotifyOauthError:
raise SpotifyAuthorizeError(
"Failed to retrieve token. Perhaps you provided invalid credentials?"
)
spotify = spotipy.Spotify(auth=token)
self._client = spotify
global global_client
global_client = spotify
return spotify

View File

@@ -0,0 +1,19 @@
from spotdl.authorize.services import AuthorizeSpotify
import pytest
class TestSpotifyAuthorize:
# TODO: Test these once we a have config.py
# storing pre-defined default credentials.
#
# We'll use these credentials to create
# a spotipy object via below tests
@pytest.mark.xfail
def test_generate_token(self):
raise NotImplementedError
@pytest.mark.xfail
def test_authorize(self):
raise NotImplementedError

View File

@@ -0,0 +1,16 @@
from spotdl.authorize import AuthorizeBase
import pytest
class TestAbstractBaseClass:
def test_error_abstract_base_class_authorizebase(self):
with pytest.raises(TypeError):
AuthorizeBase()
def test_inherit_abstract_base_class_authorizebase(self):
class AuthorizeKid(AuthorizeBase):
def authorize(self):
pass
AuthorizeKid()

View File

@@ -0,0 +1,15 @@
from spotdl.authorize.exceptions import AuthorizationError
from spotdl.authorize.exceptions import SpotifyAuthorizationError
from spotdl.authorize.exceptions import YouTubeAuthorizationError
class TestEncoderNotFoundSubclass:
def test_authozation_error_subclass(self):
assert issubclass(AuthorizationError, Exception)
def test_spotify_authorization_error_subclass(self):
assert issubclass(SpotifyAuthorizationError, AuthorizationError)
def test_youtube_authorization_error_subclass(self):
assert issubclass(YouTubeAuthorizationError, AuthorizationError)

View File

@@ -17,16 +17,6 @@ from spotdl.lyrics.exceptions import LyricsNotFoundError
spotify = None spotify = None
def generate_token():
""" Generate the token. """
credentials = oauth2.SpotifyClientCredentials(
client_id=const.args.spotify_client_id,
client_secret=const.args.spotify_client_secret,
)
token = credentials.get_access_token()
return token
def must_be_authorized(func, spotify=spotify): def must_be_authorized(func, spotify=spotify):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
global spotify global spotify