From dddf59ea254a8309f1d03e4c4495d3a83d77c1dd Mon Sep 17 00:00:00 2001 From: Benex254 Date: Mon, 5 Aug 2024 09:47:04 +0300 Subject: [PATCH] feat(anilist): implement viewing of your anilist animelist --- fastanime/cli/commands/anilist/__init__.py | 15 ++++++++ fastanime/cli/commands/anilist/completed.py | 30 +++++++++++++++ fastanime/cli/commands/anilist/dropped.py | 30 +++++++++++++++ fastanime/cli/commands/anilist/login.py | 6 +++ fastanime/cli/commands/anilist/paused.py | 30 +++++++++++++++ fastanime/cli/commands/anilist/planning.py | 30 +++++++++++++++ fastanime/cli/commands/anilist/repeating.py | 30 +++++++++++++++ fastanime/cli/commands/anilist/watchlist.py | 30 +++++++++++++++ .../cli/interfaces/anilist_interfaces.py | 37 ++++++++++++++++++- fastanime/libs/anilist/anilist_data_schema.py | 1 + fastanime/libs/anilist/api.py | 6 ++- 11 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 fastanime/cli/commands/anilist/completed.py create mode 100644 fastanime/cli/commands/anilist/dropped.py create mode 100644 fastanime/cli/commands/anilist/paused.py create mode 100644 fastanime/cli/commands/anilist/planning.py create mode 100644 fastanime/cli/commands/anilist/repeating.py create mode 100644 fastanime/cli/commands/anilist/watchlist.py diff --git a/fastanime/cli/commands/anilist/__init__.py b/fastanime/cli/commands/anilist/__init__.py index 8a5f244..bc643be 100644 --- a/fastanime/cli/commands/anilist/__init__.py +++ b/fastanime/cli/commands/anilist/__init__.py @@ -1,16 +1,23 @@ import click +from ....anilist import AniList from ...interfaces.anilist_interfaces import anilist as anilist_interface from ...utils.tools import QueryDict +from .completed import completed +from .dropped import dropped from .favourites import favourites from .login import loggin +from .paused import paused +from .planning import planning from .popular import popular from .random_anime import random_anime from .recent import recent +from .repeating import repeating from .scores import scores from .search import search from .trending import trending from .upcoming import upcoming +from .watchlist import watch_list commands = { "trending": trending, @@ -22,6 +29,12 @@ commands = { "favourites": favourites, "random": random_anime, "loggin": loggin, + "watching": watch_list, + "paused": paused, + "repeating": repeating, + "dropped": dropped, + "completed": completed, + "planning": planning, } @@ -33,6 +46,8 @@ commands = { ) @click.pass_context def anilist(ctx: click.Context): + if user := ctx.obj.user: + AniList.update_login_info(user, user["token"]) if ctx.invoked_subcommand is None: anilist_config = QueryDict() anilist_interface(ctx.obj, anilist_config) diff --git a/fastanime/cli/commands/anilist/completed.py b/fastanime/cli/commands/anilist/completed.py new file mode 100644 index 0000000..3d3c211 --- /dev/null +++ b/fastanime/cli/commands/anilist/completed.py @@ -0,0 +1,30 @@ +import click + +from fastanime.cli.config import Config +from fastanime.cli.interfaces import anilist_interfaces +from fastanime.cli.utils.tools import QueryDict, exit_app + +from ....anilist import AniList + + +@click.command(help="View anime you completed") +@click.pass_obj +def completed(config: Config): + if not config.user: + print("Not authenticated") + print("Please run: fastanime anilist loggin") + exit_app() + anime_list = AniList.get_anime_list("COMPLETED") + if not anime_list: + return + if not anime_list[0]: + return + media = [ + mediaListItem["media"] + for mediaListItem in anime_list[1]["data"]["Page"]["mediaList"] + ] # pyright:ignore + anime_list[1]["data"]["Page"]["media"] = media # pyright:ignore + print(config.user) + anilist_config = QueryDict() + anilist_config.data = anime_list[1] + anilist_interfaces.select_anime(config, anilist_config) diff --git a/fastanime/cli/commands/anilist/dropped.py b/fastanime/cli/commands/anilist/dropped.py new file mode 100644 index 0000000..8e279bc --- /dev/null +++ b/fastanime/cli/commands/anilist/dropped.py @@ -0,0 +1,30 @@ +import click + +from fastanime.cli.config import Config +from fastanime.cli.interfaces import anilist_interfaces +from fastanime.cli.utils.tools import QueryDict, exit_app + +from ....anilist import AniList + + +@click.command(help="View anime you dropped") +@click.pass_obj +def dropped(config: Config): + if not config.user: + print("Not authenticated") + print("Please run: fastanime anilist loggin") + exit_app() + anime_list = AniList.get_anime_list("DROPPED") + if not anime_list: + return + if not anime_list[0]: + return + media = [ + mediaListItem["media"] + for mediaListItem in anime_list[1]["data"]["Page"]["mediaList"] + ] # pyright:ignore + anime_list[1]["data"]["Page"]["media"] = media # pyright:ignore + print(config.user) + anilist_config = QueryDict() + anilist_config.data = anime_list[1] + anilist_interfaces.select_anime(config, anilist_config) diff --git a/fastanime/cli/commands/anilist/login.py b/fastanime/cli/commands/anilist/login.py index b13bbd1..556743e 100644 --- a/fastanime/cli/commands/anilist/login.py +++ b/fastanime/cli/commands/anilist/login.py @@ -19,6 +19,7 @@ def loggin(config: Config, status): "You are logged in :happy:" if is_logged_in else "You arent logged in :sad:" ) print(message) + print(config.user) exit_app() if config.user: print("Already logged in :confused:") @@ -29,6 +30,11 @@ def loggin(config: Config, status): print("Please paste the token provided here") token = Prompt.ask("Enter token") user = AniList.login_user(token) + if not user: + print("Sth went wrong", user) + exit_app() + return + user["token"] = token config.update_user(user) print("Successfully saved credentials") print(user) diff --git a/fastanime/cli/commands/anilist/paused.py b/fastanime/cli/commands/anilist/paused.py new file mode 100644 index 0000000..bcf1899 --- /dev/null +++ b/fastanime/cli/commands/anilist/paused.py @@ -0,0 +1,30 @@ +import click + +from fastanime.cli.config import Config +from fastanime.cli.interfaces import anilist_interfaces +from fastanime.cli.utils.tools import QueryDict, exit_app + +from ....anilist import AniList + + +@click.command(help="View anime you paused on watching") +@click.pass_obj +def paused(config: Config): + if not config.user: + print("Not authenticated") + print("Please run: fastanime anilist loggin") + exit_app() + anime_list = AniList.get_anime_list("PAUSED") + if not anime_list: + return + if not anime_list[0]: + return + media = [ + mediaListItem["media"] + for mediaListItem in anime_list[1]["data"]["Page"]["mediaList"] + ] # pyright:ignore + anime_list[1]["data"]["Page"]["media"] = media # pyright:ignore + print(config.user) + anilist_config = QueryDict() + anilist_config.data = anime_list[1] + anilist_interfaces.select_anime(config, anilist_config) diff --git a/fastanime/cli/commands/anilist/planning.py b/fastanime/cli/commands/anilist/planning.py new file mode 100644 index 0000000..d8a4151 --- /dev/null +++ b/fastanime/cli/commands/anilist/planning.py @@ -0,0 +1,30 @@ +import click + +from fastanime.cli.config import Config +from fastanime.cli.interfaces import anilist_interfaces +from fastanime.cli.utils.tools import QueryDict, exit_app + +from ....anilist import AniList + + +@click.command(help="View anime you are planning on watching") +@click.pass_obj +def planning(config: Config): + if not config.user: + print("Not authenticated") + print("Please run: fastanime anilist loggin") + exit_app() + anime_list = AniList.get_anime_list("PLANNING") + if not anime_list: + return + if not anime_list[0]: + return + media = [ + mediaListItem["media"] + for mediaListItem in anime_list[1]["data"]["Page"]["mediaList"] + ] # pyright:ignore + anime_list[1]["data"]["Page"]["media"] = media # pyright:ignore + print(config.user) + anilist_config = QueryDict() + anilist_config.data = anime_list[1] + anilist_interfaces.select_anime(config, anilist_config) diff --git a/fastanime/cli/commands/anilist/repeating.py b/fastanime/cli/commands/anilist/repeating.py new file mode 100644 index 0000000..b8194ae --- /dev/null +++ b/fastanime/cli/commands/anilist/repeating.py @@ -0,0 +1,30 @@ +import click + +from fastanime.cli.config import Config +from fastanime.cli.interfaces import anilist_interfaces +from fastanime.cli.utils.tools import QueryDict, exit_app + +from ....anilist import AniList + + +@click.command(help="View anime you are rewatching") +@click.pass_obj +def repeating(config: Config): + if not config.user: + print("Not authenticated") + print("Please run: fastanime anilist loggin") + exit_app() + anime_list = AniList.get_anime_list("REPEATING") + if not anime_list: + return + if not anime_list[0]: + return + media = [ + mediaListItem["media"] + for mediaListItem in anime_list[1]["data"]["Page"]["mediaList"] + ] # pyright:ignore + anime_list[1]["data"]["Page"]["media"] = media # pyright:ignore + print(config.user) + anilist_config = QueryDict() + anilist_config.data = anime_list[1] + anilist_interfaces.select_anime(config, anilist_config) diff --git a/fastanime/cli/commands/anilist/watchlist.py b/fastanime/cli/commands/anilist/watchlist.py new file mode 100644 index 0000000..cd483bd --- /dev/null +++ b/fastanime/cli/commands/anilist/watchlist.py @@ -0,0 +1,30 @@ +import click + +from fastanime.cli.config import Config +from fastanime.cli.interfaces import anilist_interfaces +from fastanime.cli.utils.tools import QueryDict, exit_app + +from ....anilist import AniList + + +@click.command(help="View anime you are watching") +@click.pass_obj +def watch_list(config: Config): + if not config.user: + print("Not authenticated") + print("Please run: fastanime anilist loggin") + exit_app() + anime_list = AniList.get_anime_list("CURRENT") + if not anime_list: + return + if not anime_list[0]: + return + media = [ + mediaListItem["media"] + for mediaListItem in anime_list[1]["data"]["Page"]["mediaList"] + ] # pyright:ignore + anime_list[1]["data"]["Page"]["media"] = media # pyright:ignore + print(config.user) + anilist_config = QueryDict() + anilist_config.data = anime_list[1] + anilist_interfaces.select_anime(config, anilist_config) diff --git a/fastanime/cli/interfaces/anilist_interfaces.py b/fastanime/cli/interfaces/anilist_interfaces.py index 5baa824..a07cc12 100644 --- a/fastanime/cli/interfaces/anilist_interfaces.py +++ b/fastanime/cli/interfaces/anilist_interfaces.py @@ -55,7 +55,7 @@ def player_controls(config: Config, anilist_config: QueryDict): if next_episode >= len(episodes): next_episode = len(episodes) - 1 - # update internal config + # updateinternal config anilist_config.episode_number = episodes[next_episode] # update user config @@ -501,6 +501,35 @@ def select_anime(config: Config, anilist_config: QueryDict): anilist_options(config, anilist_config) +def handle_animelist(list_type: str): + match list_type: + case "Watching": + status = "CURRENT" + case "Planned": + status = "PLANNING" + case "Completed": + status = "COMPLETED" + case "Dropped": + status = "DROPPED" + case "Paused": + status = "PAUSED" + case "Repeating": + status = "REPEATING" + case _: + return + anime_list = AniList.get_anime_list(status) + if not anime_list: + return + if not anime_list[0]: + return + media = [ + mediaListItem["media"] + for mediaListItem in anime_list[1]["data"]["Page"]["mediaList"] + ] # pyright:ignore + anime_list[1]["data"]["Page"]["media"] = media # pyright:ignore + return anime_list + + def anilist(config: Config, anilist_config: QueryDict): def _anilist_search(): search_term = Prompt.ask("[cyan]Search for[/]") @@ -531,6 +560,12 @@ def anilist(config: Config, anilist_config: QueryDict): options = { "Trending": AniList.get_trending, + "Watching": lambda x="Watching": handle_animelist(x), + "Paused": lambda x="Paused": handle_animelist(x), + "Dropped": lambda x="Dropped": handle_animelist(x), + "Planned": lambda x="Planned": handle_animelist(x), + "Completed": lambda x="Completed": handle_animelist(x), + "Repeating": lambda x="Repeating": handle_animelist(x), "Recently Updated Anime": AniList.get_most_recently_updated, "Search": _anilist_search, "Watch History": _watch_history, diff --git a/fastanime/libs/anilist/anilist_data_schema.py b/fastanime/libs/anilist/anilist_data_schema.py index 152c5fc..d568961 100644 --- a/fastanime/libs/anilist/anilist_data_schema.py +++ b/fastanime/libs/anilist/anilist_data_schema.py @@ -22,6 +22,7 @@ class AnilistUser(TypedDict): name: str bannerImage: str | None avatar: AnilistImage + token: str class AnilistMediaTrailer(TypedDict): diff --git a/fastanime/libs/anilist/api.py b/fastanime/libs/anilist/api.py index 179aa61..004cd68 100644 --- a/fastanime/libs/anilist/api.py +++ b/fastanime/libs/anilist/api.py @@ -61,7 +61,7 @@ class AniListApi: "CURRENT", "PLANNING", "COMPLETED", "DROPPED", "PAUSED", "REPEATING" ], ): - variables = {"status": status, "id": self.user_id} + variables = {"status": status, "userId": self.user_id} return self._make_authenticated_request(media_list_query, variables) def _make_authenticated_request(self, query: str, variables: dict = {}): @@ -103,6 +103,10 @@ class AniListApi: except Exception as e: return (False, {"Error": f"{e}"}) # type: ignore + def get_watchlist(self): + variables = {"status": "CURRENT", "userId": self.user_id} + return self._make_authenticated_request(media_list_query, variables) + def get_data( self, query: str, variables: dict = {} ) -> tuple[bool, AnilistDataSchema]: