diff --git a/fastanime/cli/interactive/menus/main.py b/fastanime/cli/interactive/menus/main.py index 4f3df2b..aeb1a6c 100644 --- a/fastanime/cli/interactive/menus/main.py +++ b/fastanime/cli/interactive/menus/main.py @@ -67,6 +67,12 @@ def main(ctx: Context, state: State) -> State | ControlFlow: None, None, ), + f"{'📝 ' if icons else ''}Edit Config": lambda: ( + "CONFIG_EDIT", + None, + None, + None, + ), f"{'❌ ' if icons else ''}Exit": lambda: ("EXIT", None, None, None), } @@ -85,7 +91,7 @@ def main(ctx: Context, state: State) -> State | ControlFlow: if next_menu_name == "EXIT": return ControlFlow.EXIT - if next_menu_name == "RELOAD_CONFIG": + if next_menu_name == "CONFIG_EDIT": return ControlFlow.CONFIG_EDIT if next_menu_name == "SESSION_MANAGEMENT": return State(menu_name="SESSION_MANAGEMENT") @@ -123,9 +129,7 @@ def _create_media_list_action( def action(): # Create the search parameters - search_params = ApiSearchParams( - sort=sort, per_page=ctx.config.anilist.per_page, status=status - ) + search_params = ApiSearchParams(sort=sort, status=status) result = ctx.media_api.search_media(search_params) @@ -136,10 +140,7 @@ def _create_media_list_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, - ) + search_params = ApiSearchParams(id_in=random.sample(range(1, 15000), k=50)) result = ctx.media_api.search_media(search_params) @@ -171,9 +172,7 @@ def _create_user_list_action(ctx: Context, status: UserListStatusType) -> MenuAc logger.warning("Not authenticated") return "CONTINUE", None, None, None - user_list_params = UserListParams( - status=status, per_page=ctx.config.anilist.per_page - ) + user_list_params = UserListParams(status=status) result = ctx.media_api.search_media_list(user_list_params) diff --git a/fastanime/libs/api/anilist/api.py b/fastanime/libs/api/anilist/api.py index cdaabf3..4c17932 100644 --- a/fastanime/libs/api/anilist/api.py +++ b/fastanime/libs/api/anilist/api.py @@ -24,6 +24,37 @@ status_map = { "repeating": "REPEATING", } +# TODO: Just remove and have consistent variable naming between the two +search_params_map = { + # Custom Name: AniList Variable Name + "query": "query", + "page": "page", + "per_page": "per_page", + "sort": "sort", + "id_in": "id_in", + "genre_in": "genre_in", + "genre_not_in": "genre_not_in", + "tag_in": "tag_in", + "tag_not_in": "tag_not_in", + "status_in": "status_in", + "status": "status", + "status_not_in": "status_not_in", + "popularity_greater": "popularity_greater", + "popularity_lesser": "popularity_lesser", + "averageScore_greater": "averageScore_greater", + "averageScore_lesser": "averageScore_lesser", + "seasonYear": "seasonYear", + "season": "season", + "startDate_greater": "startDate_greater", + "startDate_lesser": "startDate_lesser", + "startDate": "startDate", + "endDate_greater": "endDate_greater", + "endDate_lesser": "endDate_lesser", + "format_in": "format_in", + "type": "type", + "on_list": "on_list", +} + class AniListApi(BaseApiClient): """AniList API implementation of the BaseApiClient contract.""" @@ -54,8 +85,16 @@ class AniListApi(BaseApiClient): return mapper.to_generic_user_profile(response.json()) def search_media(self, params: ApiSearchParams) -> Optional[MediaSearchResult]: - variables = {k: v for k, v in params.__dict__.items() if v is not None} - variables["perPage"] = params.per_page or self.config.per_page + variables = { + search_params_map[k]: v for k, v in params.__dict__.items() if v is not None + } + variables["per_page"] = params.per_page or self.config.per_page + + # ignore hentai by default + variables["genre_not_in"] = params.genre_not_in or ["Hentai"] + + # anime by default + variables["type"] = params.type or "ANIME" response = execute_graphql( ANILIST_ENDPOINT, self.http_client, gql.SEARCH_MEDIA, variables ) @@ -65,12 +104,16 @@ class AniListApi(BaseApiClient): if not self.user_profile: logger.error("Cannot fetch user list: user is not authenticated.") return None + + # TODO: use consistent variable naming btw graphql and params + # so variables can be dynamically filled variables = { "sort": params.sort or self.config.media_list_sort_by, "userId": self.user_profile.id, "status": status_map[params.status] if params.status else None, "page": params.page, "perPage": params.per_page or self.config.per_page, + "type": params.type or "ANIME", } response = execute_graphql( ANILIST_ENDPOINT, self.http_client, gql.GET_USER_MEDIA_LIST, variables diff --git a/fastanime/libs/api/anilist/queries/search.gql b/fastanime/libs/api/anilist/queries/search.gql index 4848d95..eadd225 100644 --- a/fastanime/libs/api/anilist/queries/search.gql +++ b/fastanime/libs/api/anilist/queries/search.gql @@ -1,6 +1,6 @@ query ( $query: String - $max_results: Int + $per_page: Int $page: Int $sort: [MediaSort] $id_in: [Int] @@ -26,7 +26,7 @@ query ( $season: MediaSeason $on_list: Boolean ) { - Page(perPage: $max_results, page: $page) { + Page(perPage: $per_page, page: $page) { pageInfo { total currentPage diff --git a/fastanime/libs/api/params.py b/fastanime/libs/api/params.py index 017f0b3..2ddc84f 100644 --- a/fastanime/libs/api/params.py +++ b/fastanime/libs/api/params.py @@ -8,7 +8,7 @@ from .types import UserListStatusType class ApiSearchParams: query: Optional[str] = None page: int = 1 - per_page: int = 20 + per_page: Optional[int] = None sort: Optional[Union[str, List[str]]] = None # IDs @@ -59,9 +59,10 @@ class ApiSearchParams: @dataclass(frozen=True) class UserListParams: status: UserListStatusType - sort: Optional[str] = None page: int = 1 - per_page: int = 20 + type: Optional[str] = None + sort: Optional[str] = None + per_page: Optional[int] = None @dataclass(frozen=True)