Skip to main content

Anime extractors api implementation

Project description

anicli-api

Программный интерфейс набора парсеров аниме с различных источников.

Присутствует поддержка sync и async методов с помощью httpx библиотеки.

Парсеры работают на REST-API (если у источника есть доступ) или если такой интерфейс отсутствует, то с помощью parsel, chompjs, jmespath, regex библиотек.

install

pip install anicli-api

Overview

Структура проекта

  • source - наборы модулей для извлечения информации об аниме тайтлов из источников
  • player - наборы модулей для извлечения прямой ссылки на видео

Подробнее про source и player смотрите ниже.

anicli_api
├── base.py - базовый класс модуля-парсера
├── _http.py - предварительно сконфигурированные классы httpx.Client и httpx.AsyncClient
├── _logger.py - логгер
├── player - модули получения ссылок на видео
│     ├── __template__.py - шаблон модуля PlayerExtractor
│     ├── ...  ready-made модули
│     ...
├── source - модули парсеров с источников
│     ├── parsers/... автоматически сгенерированные парсеры html страниц
│     ├── __template__.py - шаблон для экстрактора
│     ├─ ... ready-made парсеры
│     ...
└── tools - прочие модули

Схематичный принцип работы модуля из директории source

префикс a_ обозначает асинхронный метод, возвращаемые объекты идентичны

flowchart TD
    E[Extractor] -->|"search('QUERY') | a_search('QUERY')"| S("List[Search]")
    E -->|"ongoing() | a_ongoing()"| O("List[Ongoing]")
    
    O -->|"get_anime() | a_get_anime()"| A[Anime]
    S -->|"get_anime() | a_get_anime()"| A
    
    A -->|"get_episodes() | a_get_episodes()"|Ep["List[Episode]"]
    Ep -->|"get_sources() | a_get_sources()"|So["List[Source]"]
    So -->|"get_videos() | a_get_videos()"|V["List[Video]"]

quickstart

from anicli_api.source.animego import Extractor
from anicli_api.tools import cli

if __name__ == '__main__':
    cli(Extractor())

Этот модуль реализован для простого ручного тестирования парсеров и "имитирует" потенциальное настоящее приложение

Пример своей реализации

from anicli_api.source.animego import Extractor  # can usage any source


def _print_to_rows(items):
    print(*[f"{i}) {r}" for i, r in enumerate(items)], sep="\n")


if __name__ == "__main__":
    ex = Extractor()
    print("PRESS CTRL + C for exit app")
    while True:
        results = ex.search(input("search query > "))
        if not results:
            print("Not founded, try again")
        continue
    _print_to_rows(results)

    anime = results[int(input("anime > "))].get_anime()
    print(anime)

    episodes = anime.get_episodes()
    _print_to_rows(episodes)
    episode = episodes[int(input("episode > "))]

    sources = episode.get_sources()
    _print_to_rows(sources)
    source = sources[int(input("source > "))]

    videos = source.get_videos()
    _print_to_rows(videos)
    video = videos[int(input("video > "))]
    print(video.type, video.quality, video.url, video.headers)

С asyncio аналогично, но все методы получения объектов имеют префикс a_:

import asyncio
from anicli_api.source.animego import Extractor # или любой другой источник

async def main():
    ex = Extractor()
    prompt = input("search query > ")
    # a_ - async prefix.
    # simular in Ongoing, Anime, Episode, Source, Video objects
    results = await ex.a_search(prompt) 
    print(*[f"{i}) {r}" for i, r in enumerate(results)], sep="\n")
    
if __name__ == '__main__':
    asyncio.run(main())

Player

Эти модули можно использовать как экстрактор прямых ссылок на видео

Эти модули минимально реализуют получение ссылок на видео с минимальными метаданными и заголовками для скачивания и не стремятся стать заменой yt-dlp

import asyncio

from anicli_api.player.sibnet import SibNet

async def main():
    videos = await SibNet().a_parse(URL)
    print(*videos)
    
    
if __name__ == '__main__':
    URL = 'https://video.sibnet.ru/shell.php?videoid=432356'
    print(*SibNet().parse(URL))
    # asyncio support!
    asyncio.run(main())

source description

  • name - имя модуля
  • type - тип источника получения данных.
    • NO - неофициальный (парсинг html документов и запросы недокументированным API методам)
    • YES - официальный (rest-api)
  • note - примечания
  • dubbers - тип озвучек.
    • many - от различных авторов.
    • subtitles - только субтитры.
    • once - один вид (случайный)
    • author - своя
name url type dubbers note
animego https://animego.org NO many источники kodik, animego, не работает на IP отличных от СНГ и стран прибалтики. Часто попадает под РКН блокировки
sovetromantica https://sovetromantica.com NO subtitles, author не на все тайтлы есть видео, у себя хостят
anilibria https://anilibria.tv YES author
animevost https://animevost.org YES author
jutsu https://jut.su NO once Запуск видео в сторонних плеерах зависим от используемого user-agent заголовка в API интерфейсе. Некоторые тайтлы заблокированы на территории РФ
sameband https://sameband.studio NO author
yummy_anime_org https://yummy-anime.org NO many
yummy_anime_ru https://yummy-anime.ru YES many
anilib.me https://anilib.me YES many

players description

Требует дополнения и дополнительные тесты

  • name - имя плеера
  • max quality - максимальное разрешение выдаваемое источником. Это может быть 0 (аудио, без видео), 144, 240, 360, 480, 720, 1080
  • note - примечания
name max quality note
kodik 720 (на старых тайтлах (ранние One Peace, Evangelion) - 480) работает только на IP СНГ и стран прибалтики
aniboom 1080 работает только на IP СНГ и стран прибалтики. Иногда не возвращает mpd ссылку на видео
askor 1080
sibnet 480
csst 1080
sovetromantica 1080 не на все тайтлы присутствуют видео
anilibria 1080
jutsu 1080
sameband 1080
anilib 2060 (4k) требуется авторизация, добавить заголовок Authorization: Bearer ...

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 path

source

Если по какой-то либо причине вас не устраивают настройки по умолчанию - то вы можете задать конфигурацию http клиентов для экстракторов. Или если необходимо подключить proxy

from anicli_api.source.animego import Extractor
import httpx
# не обязательно настраивать все клиенты, зависит от режима использования
# например, если вы будете использовать только asyncio - настраивайте только http_async_client 
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")

# настройки клиентов будут передаваться всем объектам кроме методов Source.get_videos() 
# и Source.a_get_videos()

ex = Extractor(http_client=my_client, http_async_client=my_async_client)

# изменение http клиента для объекта
results = ex.search("lain")
result = results[0]
result.http = my_client
result.http_async = my_async_client
...

player

В player для модификации httpx клиентов (Client, AsyncioClient) необходимо передать kwargs аргументы:

from anicli_api.source.animego import Extractor


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

videos = sources[0].get_videos(transport=None,  # reset to default httpx.HTTPTransport
                               headers={"User-Agent": "i'm crushing :("})

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

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

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

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

  • Если по какой-либо причине объекты не получены (ddos защита, региональные ограничения) - то возвращает пустой список. (#TODO возможно, необходимо выбрасывать исключение?)

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)
  • num: str - номер эпизода

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 - заголовки требуемые для получения потока. Если возвращает пустой словарь - заголовки не нужны

Примечания

  • Парсеры из директории anicli_api/source/parsers автоматически генерируются с помощью ssc_gen, настройки хранятся в libanime_schema

  • Для модификаций парсеров из директории anicli_api/source/parsers используйте наследование, чтобы не потерять изменения при перегенерации библиотекой ssc_gen.

  • Проект разработан преимущественно на личное, некоммерческое использование с client-side стороны. Проекта не несет ответственности за поломки, убытки и решение предоставляется "Как есть" в соответствии с MIT лицензией.

  • Основная цель этого проекта — связать автоматизацию и эффективность извлечения того, что предоставляется пользователю в Интернете. Весь контент, доступный в рамках проекта, размещается на внешних неаффилированных источниках.

  • Этот проект не включает инструменты кеширования и сохранения всех полученных данных, только готовые реализации парсеров и программные интерфейсы

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

anicli_api-0.7.17.tar.gz (59.6 kB view details)

Uploaded Source

Built Distribution

anicli_api-0.7.17-py3-none-any.whl (80.4 kB view details)

Uploaded Python 3

File details

Details for the file anicli_api-0.7.17.tar.gz.

File metadata

  • Download URL: anicli_api-0.7.17.tar.gz
  • Upload date:
  • Size: 59.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.14

File hashes

Hashes for anicli_api-0.7.17.tar.gz
Algorithm Hash digest
SHA256 9ebbf72506984a36530836f005cffbfe862eac9709285c959734df3bdc73d6a8
MD5 b7251e41e30ec54deca81ffae37483ec
BLAKE2b-256 650d65e3ec8a7f8e7dc4f6612ba7d96b5f5fcfe6e771836a6b419d29da4dbde3

See more details on using hashes here.

File details

Details for the file anicli_api-0.7.17-py3-none-any.whl.

File metadata

File hashes

Hashes for anicli_api-0.7.17-py3-none-any.whl
Algorithm Hash digest
SHA256 25b721220398713a54da7ffb5cacc38900bd51bea89d0a09942c5e60c36f4b00
MD5 a98ca0a06a87a81a8cccbd9d02ca1e3d
BLAKE2b-256 355bbef28f865938cd6eff0007cc1ed70336badc1c241fe1232cd688cdefa90f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page