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