mirror of
https://github.com/Benexl/FastAnime.git
synced 2025-12-28 13:43:28 -08:00
137 lines
4.6 KiB
Python
137 lines
4.6 KiB
Python
import logging
|
|
from typing import Optional
|
|
|
|
from httpx import Client
|
|
|
|
from ....core.config import AnilistConfig
|
|
from ....core.utils.graphql import (
|
|
execute_graphql,
|
|
execute_graphql_query_with_get_request,
|
|
)
|
|
from ..base import ApiSearchParams, BaseApiClient, UpdateListEntryParams, UserListParams
|
|
from ..types import MediaSearchResult, UserProfile
|
|
from . import gql, mapper
|
|
|
|
logger = logging.getLogger(__name__)
|
|
ANILIST_ENDPOINT = "https://graphql.anilist.co"
|
|
|
|
|
|
class AniListApi(BaseApiClient):
|
|
"""AniList API implementation of the BaseApiClient contract."""
|
|
|
|
def __init__(self, config: AnilistConfig, client: Client):
|
|
super().__init__(config, client)
|
|
self.token: Optional[str] = None
|
|
self.user_profile: Optional[UserProfile] = None
|
|
|
|
def authenticate(self, token: str) -> Optional[UserProfile]:
|
|
self.token = token
|
|
self.http_client.headers["Authorization"] = f"Bearer {token}"
|
|
self.user_profile = self.get_viewer_profile()
|
|
if not self.user_profile:
|
|
self.token = None
|
|
self.http_client.headers.pop("Authorization", None)
|
|
return self.user_profile
|
|
|
|
def get_viewer_profile(self) -> Optional[UserProfile]:
|
|
if not self.token:
|
|
return None
|
|
response = execute_graphql(
|
|
ANILIST_ENDPOINT, self.http_client, gql.GET_LOGGED_IN_USER, {}
|
|
)
|
|
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
|
|
response = execute_graphql(
|
|
ANILIST_ENDPOINT, self.http_client, gql.SEARCH_MEDIA, variables
|
|
)
|
|
return mapper.to_generic_search_result(response.json())
|
|
|
|
def fetch_user_list(self, params: UserListParams) -> Optional[MediaSearchResult]:
|
|
if not self.user_profile:
|
|
logger.error("Cannot fetch user list: user is not authenticated.")
|
|
return None
|
|
variables = {
|
|
"userId": self.user_profile.id,
|
|
"status": params.status,
|
|
"page": params.page,
|
|
"perPage": params.per_page,
|
|
}
|
|
response = execute_graphql(
|
|
ANILIST_ENDPOINT, self.http_client, gql.GET_USER_MEDIA_LIST, variables
|
|
)
|
|
return mapper.to_generic_user_list_result(response.json()) if response else None
|
|
|
|
def update_list_entry(self, params: UpdateListEntryParams) -> bool:
|
|
if not self.token:
|
|
return False
|
|
score_raw = int(params.score * 10) if params.score is not None else None
|
|
variables = {
|
|
"mediaId": params.media_id,
|
|
"status": params.status,
|
|
"progress": params.progress,
|
|
"scoreRaw": score_raw,
|
|
}
|
|
variables = {k: v for k, v in variables.items() if v is not None}
|
|
response = execute_graphql(
|
|
ANILIST_ENDPOINT, self.http_client, gql.SAVE_MEDIA_LIST_ENTRY, variables
|
|
)
|
|
return response.json() is not None and "errors" not in response.json()
|
|
|
|
def delete_list_entry(self, media_id: int) -> bool:
|
|
if not self.token:
|
|
return False
|
|
response = execute_graphql(
|
|
ANILIST_ENDPOINT,
|
|
self.http_client,
|
|
gql.GET_MEDIA_LIST_ITEM,
|
|
{"mediaId": media_id},
|
|
)
|
|
entry_data = response.json()
|
|
|
|
list_id = (
|
|
entry_data.get("data", {}).get("MediaList", {}).get("id")
|
|
if entry_data
|
|
else None
|
|
)
|
|
if not list_id:
|
|
return False
|
|
response = execute_graphql(
|
|
ANILIST_ENDPOINT,
|
|
self.http_client,
|
|
gql.DELETE_MEDIA_LIST_ENTRY,
|
|
{"id": list_id},
|
|
)
|
|
return (
|
|
response.json()
|
|
.get("data", {})
|
|
.get("DeleteMediaListEntry", {})
|
|
.get("deleted", False)
|
|
if response
|
|
else False
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
from httpx import Client
|
|
|
|
from ....core.config import AnilistConfig
|
|
from ....core.constants import APP_ASCII_ART
|
|
from ..params import ApiSearchParams
|
|
|
|
anilist = AniListApi(AnilistConfig(), Client())
|
|
print(APP_ASCII_ART)
|
|
|
|
# search
|
|
query = input("What anime would you like to search for: ")
|
|
search_results = anilist.search_media(ApiSearchParams(query=query))
|
|
if not search_results:
|
|
print("Nothing was finding matching: ", query)
|
|
exit()
|
|
for result in search_results.media:
|
|
print(
|
|
f"Title: {result.title.english or result.title.romaji} Episodes: {result.episodes}"
|
|
)
|