diff --git a/tiddl/cli/commands/auth.py b/tiddl/cli/commands/auth.py index b1f7aee..afc6f8f 100644 --- a/tiddl/cli/commands/auth.py +++ b/tiddl/cli/commands/auth.py @@ -79,16 +79,35 @@ def login( @auth_command.command(help="Logout and remove token from app.") -def logout(): - loaded_auth_data = load_auth_data() +def logout( + force: Annotated[ + bool, + typer.Option( + "--force", + "-f", + help="Clears local auth data even if the server request fails.", + ), + ] = False, +): + auth_data = load_auth_data() - if loaded_auth_data.token: - auth_api = AuthAPI() - auth_api.logout_token(loaded_auth_data.token) + # If there's no token, we are effectively already logged out locally + if not auth_data.token: + console.print("[yellow]No active session found.") + return - save_auth_data(AuthData()) + try: + AuthAPI().logout_token(auth_data.token) + success = True + except Exception as error: + console.print(f"[bold red]Logout request failed: {error}") + success = False - console.print("[bold green]Logged out!") + if success or force: + save_auth_data(AuthData()) + console.print("[bold green]Logged out successfully!") + else: + console.print("[bold yellow]Local session retained. Use --force to override.") @auth_command.command(help="Refreshes your token in app.") diff --git a/tiddl/cli/commands/download/downloader.py b/tiddl/cli/commands/download/downloader.py index f6f925e..8213e92 100644 --- a/tiddl/cli/commands/download/downloader.py +++ b/tiddl/cli/commands/download/downloader.py @@ -151,17 +151,13 @@ class Downloader: ) return None, False - urls, actual_ext = parse_track_stream(stream) - if filename.suffix.lower() != actual_ext: - filename = filename.with_suffix(actual_ext) + urls, _ = parse_track_stream(stream) download_path = self.get_path(self.download_path, filename) quality = track_qualities_color[stream.audioQuality] if stream.audioQuality in ["HI_RES_LOSSLESS", "LOSSLESS"]: quality = f"{quality} {stream.bitDepth}-bit, {(stream.sampleRate or 0) / 1000:.1f} kHz" - - if stream.audioQuality == "HI_RES_LOSSLESS": should_extract_flac = True elif isinstance(item, Video): diff --git a/tiddl/cli/commands/subcommands/search.py b/tiddl/cli/commands/subcommands/search.py index 06ea0d4..c3b8889 100644 --- a/tiddl/cli/commands/subcommands/search.py +++ b/tiddl/cli/commands/subcommands/search.py @@ -18,8 +18,8 @@ search_subcommand = typer.Typer() ) def search( ctx: Context, - QUERY: Annotated[str, typer.Argument()], - RESOURCE_TYPES: Annotated[ + query: Annotated[str, typer.Argument()], + resource_types: Annotated[ list[str], typer.Option( "-t", @@ -28,7 +28,7 @@ def search( help="Narrow resource types, usage: -t track -t album etc. Available resources: track, video, album, playlist, artist.", ), ] = ["track", "video", "album", "playlist", "artist"], - NUMBER_TOP_RESULTS: Annotated[ + number_top_results: Annotated[ int, typer.Option( "--num-top", @@ -36,7 +36,7 @@ def search( help="Number of top results to display per resource type.", ), ] = 3, - PICK_TOP_HIT: Annotated[ + pick_top_hit: Annotated[ bool, typer.Option( "--top", @@ -51,15 +51,15 @@ def search( By default, it searches for all resource types. You can specify which resource types to search for using the `--type` option. """ - results: Search = ctx.obj.api.get_search(query=QUERY) - table = _prepare_table(QUERY) + results: Search = ctx.obj.api.get_search(query=query) + table = _prepare_table(query) results_to_display = [] if results.topHit is not None: top_hit = results.topHit top_hit_type = top_hit.type.rstrip("S").lower() # "ARTISTS" -> "artist" - if top_hit_type in RESOURCE_TYPES: - if PICK_TOP_HIT: + if top_hit_type in resource_types: + if pick_top_hit: ctx.obj.resources.append( TidalResource.from_string( f"{top_hit_type}/{_display_id(top_hit.value)}" @@ -87,10 +87,10 @@ def search( } for resource_type, items in type_to_items.items(): - if resource_type in RESOURCE_TYPES: + if resource_type in resource_types: results_to_display.extend( (resource_type.title(), _display_name(item), _display_id(item)) - for item in items[:NUMBER_TOP_RESULTS] + for item in items[:number_top_results] ) for i, (resource_type, name, id) in enumerate(results_to_display, start=1): @@ -106,7 +106,7 @@ def search( for num in selected_numbers: if num.lower() == "q": return - + if not num.isdigit() or int(num) < 1 or int(num) > len(results_to_display): ctx.obj.console.print(f"[red]Invalid selection: {num}") continue diff --git a/tiddl/core/auth/client.py b/tiddl/core/auth/client.py index d08e37f..d85c3c9 100644 --- a/tiddl/core/auth/client.py +++ b/tiddl/core/auth/client.py @@ -11,7 +11,7 @@ def get_auth_credentials() -> tuple[str, str]: client_id, client_secret = ( base64.b64decode( - "ZlgySnhkbW50WldLMGl4VDsxTm45QWZEQWp4cmdKRkpiS05XTGVBeUtHVkdtSU51WFBQTEhWWEF2eEFnPQ==" + "NE4zbjZRMXg5NUxMNUs3cDtvS09YZkpXMzcxY1g2eGFaMFB5aGdHTkJkTkxsQlpkNEFLS1lvdWdNamlrPQ==" ) .decode() .split(";") diff --git a/tiddl/core/metadata/track.py b/tiddl/core/metadata/track.py index a63fe41..1f39d86 100644 --- a/tiddl/core/metadata/track.py +++ b/tiddl/core/metadata/track.py @@ -36,6 +36,8 @@ class Metadata: def add_flac_metadata(track_path: Path, metadata: Metadata) -> None: + log.debug(f"{track_path=}") + mutagen = MutagenFLAC(track_path) if metadata.cover_data: