Anilist extractor added
This commit is contained in:
parent
df188cb531
commit
e11c5aec00
2 changed files with 81 additions and 0 deletions
46
modules/anime_etl/sources/anilist_async_client.py
Normal file
46
modules/anime_etl/sources/anilist_async_client.py
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import httpx
|
||||||
|
import asyncio
|
||||||
|
from rate_limiter import ANILIST_RATE_LIMITER
|
||||||
|
|
||||||
|
URL = "https://graphql.anilist.co"
|
||||||
|
|
||||||
|
QUERY = """
|
||||||
|
query ($search: String, $season: MediaSeason, $seasonYear: Int, $format: MediaFormat, $page: Int, $perPage: Int) {
|
||||||
|
Page(page: $page, perPage: $perPage) {
|
||||||
|
media(search: $search, type: ANIME, season: $season, seasonYear: $seasonYear, format: $format) {
|
||||||
|
id
|
||||||
|
title { romaji english native }
|
||||||
|
status
|
||||||
|
season
|
||||||
|
seasonYear
|
||||||
|
# seasonNumber
|
||||||
|
episodes
|
||||||
|
duration
|
||||||
|
popularity
|
||||||
|
averageScore
|
||||||
|
coverImage { extraLarge large }
|
||||||
|
genres
|
||||||
|
studios(isMain: true) { nodes { id name } }
|
||||||
|
nextAiringEpisode { episode }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
CLIENT = httpx.AsyncClient(timeout=15.0)
|
||||||
|
|
||||||
|
async def _post(payload: dict) -> dict:
|
||||||
|
for i in range(5):
|
||||||
|
await ANILIST_RATE_LIMITER.acquire()
|
||||||
|
try:
|
||||||
|
r = await CLIENT.post(URL, json=payload)
|
||||||
|
r.raise_for_status()
|
||||||
|
return r.json()
|
||||||
|
except Exception:
|
||||||
|
await asyncio.sleep(1 * 2**i)
|
||||||
|
raise RuntimeError("AniList unreachable")
|
||||||
|
|
||||||
|
async def search_raw(filters: dict) -> list[dict]:
|
||||||
|
payload = {"query": QUERY, "variables": filters}
|
||||||
|
data = await _post(payload)
|
||||||
|
return data.get("data", {}).get("Page", {}).get("media") or []
|
||||||
35
modules/anime_etl/sources/anilist_source.py
Normal file
35
modules/anime_etl/sources/anilist_source.py
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
from mappers.anilist_filters import to_anilist_filters
|
||||||
|
from sources.anilist_async_client import search_raw
|
||||||
|
from normalizers.anilist_normalizer import normalize_media
|
||||||
|
import asyncio
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
|
||||||
|
class AniListSource:
|
||||||
|
async def search(self, local_filters: dict) -> list:
|
||||||
|
ani_filters = to_anilist_filters(local_filters)
|
||||||
|
raw_list = await search_raw(ani_filters)
|
||||||
|
return [normalize_media(r) for r in raw_list]
|
||||||
|
|
||||||
|
|
||||||
|
async def _demo() -> None:
|
||||||
|
src = AniListSource()
|
||||||
|
filters = {
|
||||||
|
"query": "monogatari",
|
||||||
|
# "year": 2017,
|
||||||
|
# "season": "winter",
|
||||||
|
# "type": "tv",
|
||||||
|
# "limit": 5,
|
||||||
|
}
|
||||||
|
print("Запускаю поиск с фильтрами:", filters)
|
||||||
|
titles = await src.search(filters)
|
||||||
|
print("Найдено тайтлов:", len(titles))
|
||||||
|
|
||||||
|
for t in titles:
|
||||||
|
# t.title_names — dict[str, list[str]]
|
||||||
|
# en = (t.title_names.get("en") or [""])[0]
|
||||||
|
# print("-", en, "|", t.release_year, t.release_season)
|
||||||
|
pprint.pprint(t)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(_demo())
|
||||||
Loading…
Add table
Add a link
Reference in a new issue