import asyncio from typing import Any, Dict, List, Optional import httpx from rate_limiter import JIKAN_RATE_LIMITER BASE_URL = "https://api.jikan.moe/v4" CLIENT = httpx.AsyncClient(timeout=15.0) async def _get(path: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: """ Обёртка над GET с ретраями и rate-limit'ом. """ url = f"{BASE_URL}{path}" last_exc: Exception | None = None for i in range(5): await JIKAN_RATE_LIMITER.acquire() try: r = await CLIENT.get(url, params=params) r.raise_for_status() return r.json() except Exception as exc: last_exc = exc await asyncio.sleep(1 * 2**i) raise RuntimeError(f"Jikan unreachable: {last_exc!r}") async def search_producer(name: str, limit: int = 1) -> List[Dict[str, Any]]: """ Поиск студии/продюсера по имени. Возвращает список элементов из data[]: [{ "mal_id": int, "name": str, ... }, ...] """ if not name: return [] data = await _get("/producers", {"q": name, "limit": limit}) return data.get("data") or [] async def fetch_producer_full(mal_id: int) -> Optional[Dict[str, Any]]: """ Полная инфа по producer'у (есть поле about). """ if not isinstance(mal_id, int): return None data = await _get(f"/producers/{mal_id}/full") return data.get("data") or None