diff --git a/CHANGELOG.md b/CHANGELOG.md index c961176..e1c1c80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ### Changes +- Username and password login has been replaced with username and token - Genre metadata available for all tracks - Boolean command line options are now set like `--save-metadata` or `--no-save-metadata` for True or False - Setting `--config` (formerly `--config-location`) can be set to "None" to not use any config file diff --git a/setup.cfg b/setup.cfg index f0277eb..69e182e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = zotify -version = 0.9.6 +version = 0.9.7 author = Zotify Contributors description = A highly customizable music and podcast downloader long_description = file: README.md diff --git a/zotify/__init__.py b/zotify/__init__.py index 6e46395..9f95e53 100644 --- a/zotify/__init__.py +++ b/zotify/__init__.py @@ -70,8 +70,8 @@ class Session(LibrespotSession): def __init__( self, session_builder: LibrespotSession.Builder, - oauth: OAuth, language: str = "en", + oauth: OAuth | None = None, ) -> None: """ Authenticates user, saves credentials to a file and generates api token. @@ -96,7 +96,7 @@ class Session(LibrespotSession): self.authenticate(session_builder.login_credentials) @staticmethod - def from_file(auth: OAuth, cred_file: Path | str, language: str = "en") -> Session: + def from_file(cred_file: Path | str, language: str = "en") -> Session: """ Creates session using saved credentials file Args: @@ -107,17 +107,17 @@ class Session(LibrespotSession): """ if not isinstance(cred_file, Path): cred_file = Path(cred_file).expanduser() - conf = ( + config = ( LibrespotSession.Configuration.Builder() .set_store_credentials(False) .build() ) - session = LibrespotSession.Builder(conf).stored_file(str(cred_file)) - return Session(session, auth, language) # TODO + session = LibrespotSession.Builder(config).stored_file(str(cred_file)) + return Session(session, language) @staticmethod def from_oauth( - auth: OAuth, + oauth: OAuth, save_file: Path | str | None = None, language: str = "en", ) -> Session: @@ -129,24 +129,24 @@ class Session(LibrespotSession): Returns: Zotify session """ - builder = LibrespotSession.Configuration.Builder() + config = LibrespotSession.Configuration.Builder() if save_file: if not isinstance(save_file, Path): save_file = Path(save_file).expanduser() save_file.parent.mkdir(parents=True, exist_ok=True) - builder.set_stored_credential_file(str(save_file)) + config.set_stored_credential_file(str(save_file)) else: - builder.set_store_credentials(False) + config.set_store_credentials(False) - token = auth.await_token() + token = oauth.await_token() - session = LibrespotSession.Builder(builder.build()) - session.login_credentials = Authentication.LoginCredentials( - username=auth.username, + builder = LibrespotSession.Builder(config.build()) + builder.login_credentials = Authentication.LoginCredentials( + username=oauth.username, typ=Authentication.AuthenticationType.values()[3], auth_data=token.access_token.encode(), ) - return Session(session, auth, language) + return Session(builder, language, oauth) def __get_playable( self, playable_id: PlayableId, quality: Quality @@ -186,7 +186,7 @@ class Session(LibrespotSession): self.api(), ) - def oauth(self) -> OAuth: + def oauth(self) -> OAuth | None: """Returns OAuth service""" return self.__oauth @@ -282,7 +282,10 @@ class TokenProvider(LibrespotTokenProvider): self._session = session def get_token(self, *scopes) -> TokenProvider.StoredToken: - return self._session.oauth().get_token() + oauth = self._session.oauth() + if oauth is None: + return super().get_token(*scopes) + return oauth.get_token() class StoredToken(LibrespotTokenProvider.StoredToken): def __init__(self, obj): @@ -301,15 +304,15 @@ class OAuth: def __init__(self, username: str): self.username = username - self.__server_thread = Thread(target=self.__run_server) - self.__server_thread.start() - def get_authorization_url(self) -> str: + def auth_interactive(self) -> str: """ - Generate OAuth URL + Starts local server for token callback Returns: OAuth URL """ + self.__server_thread = Thread(target=self.__run_server) + self.__server_thread.start() self.__code_verifier = generate_code_verifier() code_challenge = get_code_challenge(self.__code_verifier) params = { diff --git a/zotify/__main__.py b/zotify/__main__.py index 2d6c5b6..1829942 100644 --- a/zotify/__main__.py +++ b/zotify/__main__.py @@ -7,7 +7,7 @@ from zotify.app import App from zotify.config import CONFIG_PATHS, CONFIG_VALUES from zotify.utils import OptionalOrFalse -VERSION = "0.9.6" +VERSION = "0.9.7" def main(): @@ -51,7 +51,7 @@ def main(): help="Searches for only this type", ) parser.add_argument("--username", type=str, default="", help="Account username") - parser.add_argument("--password", type=str, default="", help="Account password") + parser.add_argument("--token", type=str, default="", help="Account token") group = parser.add_mutually_exclusive_group(required=True) group.add_argument( "urls", @@ -127,8 +127,7 @@ def main(): args = parser.parse_args() if args.version: print(VERSION) - return - if args.debug: + elif args.debug: args.func(args) else: try: diff --git a/zotify/app.py b/zotify/app.py index e4b4785..d91fda1 100644 --- a/zotify/app.py +++ b/zotify/app.py @@ -149,28 +149,27 @@ class App: Logger(self.__config) # Create session - # if args.username != "" and args.password != "": - # self.__session = Session.from_userpass( - # args.username, - # args.password, - # self.__config.credentials_path, - # self.__config.language, - # ) - # elif self.__config.credentials_path.is_file(): - # self.__session = Session.from_file( - # self.__config.credentials_path, self.__config.language - # ) - # else: - # self.__session = Session.from_prompt( - # self.__config.credentials_path, self.__config.language - # ) - username = input("Username: ") - auth = OAuth(username) - auth_url = auth.get_authorization_url() - print(f"\nClick on the following link to login:\n{auth_url}") - self.__session = Session.from_oauth( - auth, self.__config.credentials_path, self.__config.language - ) + if args.username != "" and args.token != "": + oauth = OAuth(args.username) + oauth.set_token(args.token, OAuth.RequestType.REFRESH) + self.__session = Session.from_oauth( + oauth, self.__config.credentials_path, self.__config.language + ) + elif self.__config.credentials_path.is_file(): + self.__session = Session.from_file( + self.__config.credentials_path, + self.__config.language, + ) + else: + username = args.username + while username == "": + username = input("Username: ") + oauth = OAuth(username) + auth_url = oauth.auth_interactive() + print(f"\nClick on the following link to login:\n{auth_url}") + self.__session = Session.from_oauth( + oauth, self.__config.credentials_path, self.__config.language + ) # Get items to download ids = self.get_selection(args)