Skip to content

Latest commit

 

History

History
277 lines (206 loc) · 10.5 KB

docs.md

File metadata and controls

277 lines (206 loc) · 10.5 KB

Docs

Структуры объектов

Приведены поля, которые гарантированно возвращаются в API интерфейсе библиотеки. В некоторых источниках могут присутствовать дополнительные поля или атрибуты для использования во внутренних методах.

  • Например, в anilibria и animevost дополнительные поля из API хранятся в data. В animego.Anime есть сырой несериализованный raw_json для извлечения дополнительных метаданных.

  • В некоторых источниках на полях могут присутствовать "заглушки" для поддержания консистентности API интерфейса. Например, в модуле anicli_api.source.jutsu.Episode уже можно получить прямые ссылки на видео (Video объект), но для поддержания полиморфизма, необходимо возвращать объект Source и только потом Video

Search

  • url: str - URL на тайтл
  • title: str - имя найденного тайтла
  • thumbnail: str - изображение

Ongoing

  • url: str - URL на тайтл
  • title: str - имя найденного тайтла
  • thumbnail: str - изображение

Anime

  • title: str - имя тайтла (на русском)
  • thumbnail: str - изображение
  • description: Optional[str] - описание тайтла. может вернуть пустую строку или None

Episode

  • title: str - имя эпизода (Если источник его не хранит, то будет Серия или Serie)
  • ordinal: int - номер эпизода

Source

  • url: str - ссылка на источник
  • title: str - даббер или имя источника

Video

Объект Video, полученный из Source.get_video/Source.a_get_video имеет следующую структуру:

  • type - тип видео (m3u8, mp4, mpd, audio)
  • quality - разрешение видео (0, 144, 240, 360, 480, 720, 1080)
  • url - прямая ссылка на видео
  • headers - заголовки требуемые для получения потока. Если возвращает пустой словарь - заголовки не нужны

logging

Настройка логгера идет через ключ anicli-api

import logging
logger = logging.getLogger('anicli-api')

Tools

Наборы вспомогательных модулей

cookies.py

Опциональная зависимость для извлечения cookie данных из браузера для последующего использования в httpx. Реализована при помощи библиотеки rookiepy

pip install anicli-api[browser-cookies]
import httpx
from anicli_api.tools.cookies import get_raw_cookies_from_browser, raw_cookies_to_httpx_cookiejar

# по умолчанию извлекает все cookies
raw_cookies = get_raw_cookies_from_browser("firefox")
cookies = raw_cookies_to_httpx_cookiejar(raw_cookies)
# опциональный фильтр по host:
# raw_cookies = get_raw_cookies_from_browser("firefox", ["example.com"])
httpx.get("https://example.com", cookies=cookies)

# update cookies in extractors:
from anicli_api.source.yummy_anime_org import Extractor
ex = Extractor()
ex.http.cookies.update(cookies)
ex.http_async.cookies.update(cookies)

dummy_cli.py

Простой cli-клиент для ручных тестов и имитации клиента

from anicli_api.tools.dummy_cli import cli
from anicli_api.source.yummy_anime_org import Extractor

cli(Extractor())

helpers.py

Наборы вспомогательных функций для взаимодействия с экстракторами

from anicli_api.source.yummy_anime_org import Extractor
from anicli_api.tools.helpers import get_video_by_quality, video_picker_iterator, async_video_picker_iterator

ex = Extractor()
result = ex.search('lain')[0]
anime = result.get_anime()
episodes = anime.get_episodes()
sources = episodes[0].get_sources()
videos = sources[0].get_videos()

# извлечь ближайшее доступное по качеству видео
# 1080 or linear quality: 720 -> 480 -> 360 -> 240...
video = get_video_by_quality(videos, 1080)

# итератор видео и заголовка
# извлекает выбранное видео по разрешению и озвучке
for video_and_title in video_picker_iterator(
        start_source=sources[0],
        start_video=videos[0],
        anime=anime,
        episodes=episodes[3:]):  # limit episodes to 3
    v, title = video_and_title
    print(title, v)

# async реализация итератора
async def main():
    async for vid_and_title in async_video_picker_iterator(
      start_source=sources[0],
        start_video=videos[0],
        anime=anime,
        episodes=episodes[3:]  # limit episodes to 3
    ):
        v, title = vid_and_title
        print(title, v)

import asyncio
asyncio.run(main())

m3u.py

Реализация создания m3u плейлиста из объектов экстрактора

from anicli_api.source.yummy_anime_org import Extractor

from anicli_api.tools.m3u import generate_playlist, generate_asyncio_playlist
from anicli_api.tools.helpers import video_picker_iterator, async_video_picker_iterator

ex = Extractor()
result = ex.search('lain')[0]
anime = result.get_anime()
episodes = anime.get_episodes()
# get first source for first 3 episodes
sources =  [e.get_sources()[0] for e in episodes[:3]]
videos = sources[0].get_videos()

# generate playlist from sources
playlist_sources = generate_playlist(sources)

# generate playlist from video_picker
video_objs, titles_objs = [],[]
for video_and_title in video_picker_iterator(
        start_source=sources[0],
        start_video=videos[0],
        anime=anime,
        episodes=episodes[3:]):  # limit episodes to 3
    v, title = video_and_title
    video_objs.append(v)
    titles_objs.append(title)
playlist = generate_playlist(video_objs, titles_objs)


# asyncio
# if target not Source object - you can use sync variant
import asyncio
playlist_async = asyncio.run(generate_asyncio_playlist(sources))

http client config

source

Каждый Extractor() без аргументов создаёт собственную пару настроенных BaseHTTPSync / BaseHTTPAsync. Эта пара передаётся всем дочерним объектам и player-экстрактору. Разные root extractors не разделяют cookies, headers и connection pool неявно.

Можно передать обычные httpx.Client / httpx.AsyncClient. Они сохраняются без замены и мутации:

from anicli_api.source.animego import Extractor
import httpx

my_client = httpx.Client(headers={"user-agent": "007"}, proxy="http://127.0.0.1:8080")
my_async_client = httpx.AsyncClient(headers={"user-agent": "007"}, proxy="http://127.0.0.1:8080")

ex = Extractor(http_client=my_client, http_async_client=my_async_client)
# Те же instances дойдут до Search -> Anime -> Episode -> Source -> player.

Переданные clients считаются borrowed: библиотека их не закрывает. Lifecycle остаётся ответственностью вызывающего кода. Для clients, созданных самим root Extractor, close() / with закрывают sync client, а aclose() / async with закрывают оба owned clients.

Для общей сессии нескольких extractors создайте clients один раз и передайте одни и те же instances:

from anicli_api._http import BaseHTTPAsync, BaseHTTPSync
from anicli_api.source.animego import Extractor as AnimeGo
from anicli_api.source.sameband import Extractor as SameBand

sync_client = BaseHTTPSync(headers={"Authorization": "Bearer ..."}, proxy="http://127.0.0.1:8080")
async_client = BaseHTTPAsync(headers={"Authorization": "Bearer ..."}, proxy="http://127.0.0.1:8080")

animego = AnimeGo(http_client=sync_client, http_async_client=async_client)
sameband = SameBand(http_client=sync_client, http_async_client=async_client)

BaseHTTP* добавляют retry/reconnect и Anubis transport. Обычные custom httpx.Client используют только собственный transport. Для opt-in middleware передайте HTTPRetryConnectSyncTransport / HTTPRetryConnectAsyncTransport при создании custom client.

player

Per-call headers / cookies / timeout применяются к каждому HTTP-запросу внутри экстрактора для этого вызова и НЕ мутируют сам httpx.Client. Это безопасно для конкурентных asyncio вызовов на одном клиенте/экстракторе.

Для per-tenant изоляции (разные прокси / IP-регионы) создавай отдельный httpx.AsyncClient per tenant и присваивай через source.http_async.

from anicli_api.source.animego import Extractor


sources = (
    Extractor()
    .search("lain")[0]
    .get_anime()
    .get_episodes()[0]
    .get_sources()
)

# новый API: per-call kwargs (без мутации клиента)
videos = sources[0].get_videos(
    headers={"User-Agent": "custom-ua"},
    cookies={"session": "..."},
    timeout=30.0,
)

# Migration: ранее можно было передать http=/a_http= в get_videos для override
# клиента целиком. Теперь нужно присваивать на source:
# source.http = my_proxy_client
# source.get_videos()

Для per-tenant изоляции между конкурентными задачами:

import httpx
from anicli_api.source.animego import Extractor

async def run_for_tenant(proxy_url: str):
    # свой клиент на tenant - никаких гонок
    async with httpx.AsyncClient(proxy=proxy_url) as client:
        ex = Extractor(http_async_client=client)
        ...