mirror of
https://github.com/Benexl/FastAnime.git
synced 2025-12-30 06:30:37 -08:00
183 lines
6.0 KiB
Python
183 lines
6.0 KiB
Python
import logging
|
|
import random
|
|
from typing import Callable, Dict, Tuple
|
|
|
|
from ....libs.api.params import ApiSearchParams, UserListParams
|
|
from ....libs.api.types import MediaSearchResult, MediaStatus, UserListStatusType
|
|
from ..session import Context, session
|
|
from ..state import ControlFlow, MediaApiState, State
|
|
|
|
logger = logging.getLogger(__name__)
|
|
MenuAction = Callable[
|
|
[],
|
|
Tuple[str, MediaSearchResult | None, ApiSearchParams | None, UserListParams | None],
|
|
]
|
|
|
|
|
|
@session.menu
|
|
def main(ctx: Context, state: State) -> State | ControlFlow:
|
|
"""
|
|
The main entry point menu for the interactive session.
|
|
Displays top-level categories for the user to browse and select.
|
|
"""
|
|
icons = ctx.config.general.icons
|
|
feedback = ctx.services.feedback
|
|
feedback.clear_console()
|
|
|
|
# TODO: Make them just return the modified state or control flow
|
|
options: Dict[str, MenuAction] = {
|
|
# --- Search-based Actions ---
|
|
f"{'🔥 ' if icons else ''}Trending": _create_media_list_action(
|
|
ctx, "TRENDING_DESC"
|
|
),
|
|
f"{'✨ ' if icons else ''}Popular": _create_media_list_action(
|
|
ctx, "POPULARITY_DESC"
|
|
),
|
|
f"{'💖 ' if icons else ''}Favourites": _create_media_list_action(
|
|
ctx, "FAVOURITES_DESC"
|
|
),
|
|
f"{'💯 ' if icons else ''}Top Scored": _create_media_list_action(
|
|
ctx, "SCORE_DESC"
|
|
),
|
|
f"{'🎬 ' if icons else ''}Upcoming": _create_media_list_action(
|
|
ctx, "POPULARITY_DESC", "NOT_YET_RELEASED"
|
|
),
|
|
f"{'🔔 ' if icons else ''}Recently Updated": _create_media_list_action(
|
|
ctx, "UPDATED_AT_DESC"
|
|
),
|
|
# --- special case media list --
|
|
f"{'🎲 ' if icons else ''}Random": _create_random_media_list(ctx),
|
|
f"{'🔎 ' if icons else ''}Search": _create_search_media_list(ctx),
|
|
# --- Authenticated User List Actions ---
|
|
f"{'📺 ' if icons else ''}Watching": _create_user_list_action(ctx, "watching"),
|
|
f"{'📑 ' if icons else ''}Planned": _create_user_list_action(ctx, "planning"),
|
|
f"{'✅ ' if icons else ''}Completed": _create_user_list_action(
|
|
ctx, "completed"
|
|
),
|
|
f"{'⏸️ ' if icons else ''}Paused": _create_user_list_action(ctx, "paused"),
|
|
f"{'🚮 ' if icons else ''}Dropped": _create_user_list_action(ctx, "dropped"),
|
|
f"{'🔁 ' if icons else ''}Rewatching": _create_user_list_action(
|
|
ctx, "repeating"
|
|
),
|
|
f"{'🔁 ' if icons else ''}Recent": lambda: (
|
|
"RESULTS",
|
|
ctx.services.media_registry.get_recently_watched(
|
|
ctx.config.anilist.per_page
|
|
),
|
|
None,
|
|
None,
|
|
),
|
|
f"{'❌ ' if icons else ''}Exit": lambda: ("EXIT", None, None, None),
|
|
}
|
|
|
|
choice_str = ctx.selector.choose(
|
|
prompt="Select Category",
|
|
choices=list(options.keys()),
|
|
)
|
|
|
|
if not choice_str:
|
|
return ControlFlow.EXIT
|
|
|
|
# --- Action Handling ---
|
|
selected_action = options[choice_str]
|
|
|
|
next_menu_name, result_data, api_params, user_list_params = selected_action()
|
|
|
|
if next_menu_name == "EXIT":
|
|
return ControlFlow.EXIT
|
|
if next_menu_name == "RELOAD_CONFIG":
|
|
return ControlFlow.CONFIG_EDIT
|
|
if next_menu_name == "SESSION_MANAGEMENT":
|
|
return State(menu_name="SESSION_MANAGEMENT")
|
|
if next_menu_name == "AUTH":
|
|
return State(menu_name="AUTH")
|
|
if next_menu_name == "ANILIST_LISTS":
|
|
return State(menu_name="ANILIST_LISTS")
|
|
if next_menu_name == "WATCH_HISTORY":
|
|
return State(menu_name="WATCH_HISTORY")
|
|
if next_menu_name == "CONTINUE":
|
|
return ControlFlow.CONTINUE
|
|
|
|
if not result_data:
|
|
feedback.error(
|
|
f"Failed to fetch data for '{choice_str.strip()}'",
|
|
"Please check your internet connection and try again.",
|
|
)
|
|
return ControlFlow.CONTINUE
|
|
|
|
# On success, transition to the RESULTS menu state.
|
|
return State(
|
|
menu_name="RESULTS",
|
|
media_api=MediaApiState(
|
|
search_results=result_data,
|
|
original_api_params=api_params,
|
|
original_user_list_params=user_list_params,
|
|
),
|
|
)
|
|
|
|
|
|
def _create_media_list_action(
|
|
ctx: Context, sort, status: MediaStatus | None = None
|
|
) -> MenuAction:
|
|
"""A factory to create menu actions for fetching media lists"""
|
|
|
|
def action():
|
|
# Create the search parameters
|
|
search_params = ApiSearchParams(
|
|
sort=sort, per_page=ctx.config.anilist.per_page, status=status
|
|
)
|
|
|
|
result = ctx.media_api.search_media(search_params)
|
|
|
|
return ("RESULTS", result, search_params, None)
|
|
|
|
return action
|
|
|
|
|
|
def _create_random_media_list(ctx: Context) -> MenuAction:
|
|
def action():
|
|
search_params = ApiSearchParams(
|
|
id_in=random.sample(range(1, 160000), k=50),
|
|
per_page=ctx.config.anilist.per_page,
|
|
)
|
|
|
|
result = ctx.media_api.search_media(search_params)
|
|
|
|
return ("RESULTS", result, search_params, None)
|
|
|
|
return action
|
|
|
|
|
|
def _create_search_media_list(ctx: Context) -> MenuAction:
|
|
def action():
|
|
query = ctx.selector.ask("Search for Anime")
|
|
if not query:
|
|
return "CONTINUE", None, None, None
|
|
|
|
search_params = ApiSearchParams(query=query)
|
|
result = ctx.media_api.search_media(search_params)
|
|
|
|
return ("RESULTS", result, search_params, None)
|
|
|
|
return action
|
|
|
|
|
|
def _create_user_list_action(ctx: Context, status: UserListStatusType) -> MenuAction:
|
|
"""A factory to create menu actions for fetching user lists, handling authentication."""
|
|
|
|
def action():
|
|
# Check authentication
|
|
if not ctx.media_api.is_authenticated():
|
|
logger.warning("Not authenticated")
|
|
return "CONTINUE", None, None, None
|
|
|
|
user_list_params = UserListParams(
|
|
status=status, per_page=ctx.config.anilist.per_page
|
|
)
|
|
|
|
result = ctx.media_api.fetch_user_list(user_list_params)
|
|
|
|
return ("RESULTS", result, None, user_list_params)
|
|
|
|
return action
|