diff --git a/fastanime/cli/commands/anilist/commands/stats.py b/fastanime/cli/commands/anilist/commands/stats.py index fd1da94..04bbb21 100644 --- a/fastanime/cli/commands/anilist/commands/stats.py +++ b/fastanime/cli/commands/anilist/commands/stats.py @@ -16,22 +16,35 @@ def stats(config: "AppConfig"): from rich.markdown import Markdown from rich.panel import Panel - from fastanime.cli.utils.feedback import create_feedback_manager - from fastanime.core.exceptions import FastAnimeError - from fastanime.libs.media_api.api import create_api_client + from .....core.exceptions import FastAnimeError + from .....libs.media_api.api import create_api_client + from ....service.auth import AuthService + from ....service.feedback import FeedbackService + from ....service.registry import MediaRegistryService - feedback = create_feedback_manager(config.general.icons) console = Console() - try: - # Create API client and ensure authentication - api_client = create_api_client(config.general.media_api, config) + feedback = FeedbackService(config.general.icons) + auth = AuthService(config.general.media_api) + registry_service = MediaRegistryService( + config.general.media_api, config.media_registry + ) - if not api_client.user_profile: - feedback.error("Not authenticated", "Please run: fastanime anilist login") + media_api_client = create_api_client(config.general.media_api, config) + + # Check authentication + + if profile := auth.get_auth(): + if not media_api_client.authenticate(profile.token): + feedback.error( + "Authentication Required", + f"You must be logged in to {config.general.media_api} to sync your media list.", + ) + feedback.info("Run this command to authenticate:", f"fastanime {config.general.media_api} auth") raise click.Abort() - user_profile = api_client.user_profile + + # Check if kitten is available for image display KITTEN_EXECUTABLE = shutil.which("kitten") diff --git a/fastanime/cli/interactive/menu/media/downloads.py b/fastanime/cli/interactive/menu/media/downloads.py index 0f1cceb..dae1f0f 100644 --- a/fastanime/cli/interactive/menu/media/downloads.py +++ b/fastanime/cli/interactive/menu/media/downloads.py @@ -26,7 +26,9 @@ def downloads(ctx: Context, state: State) -> State | InternalDirective: f"{'🔥 ' if icons else ''}Trending (Local)": _create_local_media_list_action( ctx, state, MediaSort.TRENDING_DESC ), - f"{'🎞️ ' if icons else ''}Recent (Local)": _create_local_recent_media_action(ctx, state), + f"{'🎞️ ' if icons else ''}Recent (Local)": _create_local_recent_media_action( + ctx, state + ), f"{'📺 ' if icons else ''}Watching (Local)": _create_local_status_action( ctx, state, UserMediaListStatus.WATCHING ), @@ -39,7 +41,9 @@ def downloads(ctx: Context, state: State) -> State | InternalDirective: f"{'📑 ' if icons else ''}Planned (Local)": _create_local_status_action( ctx, state, UserMediaListStatus.PLANNING ), - f"{'🔎 ' if icons else ''}Search (Local)": _create_local_search_media_list(ctx, state), + f"{'🔎 ' if icons else ''}Search (Local)": _create_local_search_media_list( + ctx, state + ), f"{'🔔 ' if icons else ''}Recently Updated (Local)": _create_local_media_list_action( ctx, state, MediaSort.UPDATED_AT_DESC ), @@ -52,7 +56,9 @@ def downloads(ctx: Context, state: State) -> State | InternalDirective: f"{'💖 ' if icons else ''}Favourites (Local)": _create_local_media_list_action( ctx, state, MediaSort.FAVOURITES_DESC ), - f"{'🎲 ' if icons else ''}Random (Local)": _create_local_random_media_list(ctx, state), + f"{'🎲 ' if icons else ''}Random (Local)": _create_local_random_media_list( + ctx, state + ), f"{'🎬 ' if icons else ''}Upcoming (Local)": _create_local_media_list_action( ctx, state, MediaSort.POPULARITY_DESC, MediaStatus.NOT_YET_RELEASED ), @@ -71,7 +77,7 @@ def downloads(ctx: Context, state: State) -> State | InternalDirective: choices=list(options.keys()), ) if not choice: - return InternalDirective.BACK + return InternalDirective.RELOAD selected_action = options[choice] next_step = selected_action() @@ -82,6 +88,7 @@ def _create_local_media_list_action( ctx: Context, state: State, sort: MediaSort, status: MediaStatus | None = None ) -> MenuAction: """Create action for searching local media with sorting and optional status filter.""" + def action(): feedback = ctx.service.feedback search_params = MediaSearchParams(sort=sort, status=status) @@ -104,29 +111,30 @@ def _create_local_media_list_action( ) else: feedback.info("No media found in local registry") - return InternalDirective.BACK + return InternalDirective.RELOAD return action def _create_local_random_media_list(ctx: Context, state: State) -> MenuAction: """Create action for getting random local media.""" + def action(): feedback = ctx.service.feedback - + loading_message = "Getting random local media" with feedback.progress(loading_message): # Get all records and pick random ones all_records = list(ctx.service.media_registry.get_all_media_records()) - + if not all_records: feedback.info("No media found in local registry") return InternalDirective.BACK - + # Get up to 50 random records random_records = random.sample(all_records, min(50, len(all_records))) random_ids = [record.media_item.id for record in random_records] - + search_params = MediaSearchParams(id_in=random_ids) result = ctx.service.media_registry.search_for_media(search_params) @@ -143,13 +151,14 @@ def _create_local_random_media_list(ctx: Context, state: State) -> MenuAction: ) else: feedback.info("No media found in local registry") - return InternalDirective.BACK + return InternalDirective.RELOAD return action def _create_local_search_media_list(ctx: Context, state: State) -> MenuAction: """Create action for searching local media by query.""" + def action(): feedback = ctx.service.feedback @@ -177,7 +186,7 @@ def _create_local_search_media_list(ctx: Context, state: State) -> MenuAction: ) else: feedback.info("No media found in local registry") - return InternalDirective.BACK + return InternalDirective.RELOAD return action @@ -186,6 +195,7 @@ def _create_local_status_action( ctx: Context, state: State, status: UserMediaListStatus ) -> MenuAction: """Create action for getting local media by user status.""" + def action(): feedback = ctx.service.feedback @@ -206,13 +216,14 @@ def _create_local_status_action( ) else: feedback.info(f"No {status.value} media found in local registry") - return InternalDirective.BACK + return InternalDirective.RELOAD return action def _create_local_recent_media_action(ctx: Context, state: State) -> MenuAction: """Create action for getting recently watched local media.""" + def action(): result = ctx.service.media_registry.get_recently_watched() if result and result.media: @@ -226,7 +237,9 @@ def _create_local_recent_media_action(ctx: Context, state: State) -> MenuAction: ), ) else: - ctx.service.feedback.info("No recently watched media found in local registry") - return InternalDirective.BACK + ctx.service.feedback.info( + "No recently watched media found in local registry" + ) + return InternalDirective.RELOAD return action