anicli-api


Nameanicli-api JSON
Version 0.5.0 PyPI version JSON
download
home_page
SummaryAnime extractors api implementation
upload_time2023-12-08 07:44:10
maintainer
docs_urlNone
authorvypivshiy
requires_python>=3.8,<4.0
licenseMIT
keywords anime api ru russia asyncio parser httpx dev
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # anicli-api

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

Присутствует поддержка sync и async методов с помощью `httpx` библиотеки
Парсеры работают на REST-API (если у источника есть доступ), parsel и обёртки scrape-schema

# install
`pip install anicli-api`

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


```

Схематичный принцип работы парсеров:

![](high-level-schema.png)

# source description
- name - имя модуля
- type - тип источника получения данных. 
  - **NO** - неофициальный (парсинг html страниц) 
  - **YES** - официальный (rest-api)
- note - примечания
- dubbers - тип озвучек. many - от различных авторов. subtitles - только субтитры. author - своя

| name           | url                        | official api | dubbers           | note                                                                    |
|----------------|----------------------------|--------------|-------------------|-------------------------------------------------------------------------|
| animego        | https://animego.org        | NO           | many              | источники kodik, animego, не работает IP отличных от СНГ                |
| animania       | https://animania.online    | NO           | many              | источник kodik, не работает IP отличных от СНГ                          |
| animejoy       | https://animejoy.ru        | NO           | subtitles         | **имеет cloudflare** (может периодически не работать), много источников |
| sovetromantica | https://sovetromantica.com | NO           | subtitles, author | не на все тайтлы есть видео, у себя хостят                              |
| anilibria      | https://anilibria.tv       | YES          | author            |                                                                         |
| animevost      | https://animevost.org      | YES          | author            |                                                                         |


# players description

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

- name - имя плеера
- max quality - максимальное разрешение выдаваемое источником. Это может быть 0 (аудио, без видео), 144, 240, 360, 480, 720, 1080
- note - примечания

| name           | max quality                               | note                                                           |
|----------------|-------------------------------------------|----------------------------------------------------------------|
| kodik          | 720 (на старых тайтлах - 480)             | **работает только на IP СНГ**                                  |
| aniboom        | 1080                                      | **работает только на IP СНГ**                                  |
| sibnet         | 480                                       |                                                                |
| animejoy       | 1080                                      | только актуальные ongoing, потом видео удаляются с их серверов |
| csst           | 1080                                      |                                                                |
| dzen           | 1080                                      |                                                                |
| mailru         |                                           |                                                                |
| okru           |                                           |                                                                |
| sovetromantica | 1080                                      |                                                                |
| vkcom          | 1080 (какого качества автор зальет видео) | CDN сервера в РФ, в других странах загружается медленнее       |


# Quickstart example

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

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(*[f"{i}) {r}" for i, r in enumerate(results)], sep="\n")
        anime = results[int(input("anime > "))].get_anime()
        episodes = anime.get_episodes()
        print(*[f"{i}) {ep}" for i, ep in enumerate(episodes)], sep="\n")
        episode = episodes[int(input("episode > "))]
        sources = episode.get_sources()
        print(*[f"{i}) {source}" for i, source in enumerate(sources)], sep="\n")
        source = sources[int(input("source > "))]
        videos = source.get_videos()
        print(*[f"{i} {video}" for i, video in enumerate(videos)], sep="\n")
        video = videos[int(input("video > "))]
        print(video.type, video.quality, video.url, video.headers)

```

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

```python
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())
```

## http path

### source

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

```python
from anicli_api.base import HTTPSync

from httpx import HTTPTransport

client = HTTPSync()
print(client._transport)  # anicli_api._http.HTTPRetryConnectSyncTransport
print(client.headers) # {'user-agent': 'Mozilla/5.0 (Linux; Android 6.0...', ...}

client_2 = HTTPSync(transport=HTTPTransport(), # default transport
                    headers={"user-agent": "My Cool useragent"}
                    )  

print(client_2._transport)  # httpx.HTTPTransport
print(client_2.headers)  # {'user-agent': 'My Cool useragent', ...}
assert client_2 == client  # Passed
```
### player

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

```python
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` для извлечения дополнительных данных.

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

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

### Anime
- title: str - имя тайтла (на русском)
- thumbnail: str - изображение
- description: Optional[str] - описание тайтла

### Episode
- title: str - имя эпизода
- 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` - автоматически сгенерированные парсеры с помощью 
[scrape-schema-codegen](https://github.com/vypivshiy/selector_schema_codegen) и файлов-конфигурации [libanime](https://github.com/libanime/libanime_schema). 

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

Пример из модуля [animego](anicli_api/source/animego.py):

```python
from anicli_api.source.parsers.animego_parser import AnimeView as AnimeViewOld

class AnimeView(AnimeViewOld):
    @staticmethod
    def _parse_description(part) -> str:
        # remove whitespaces patch
        val_0 = part.css(".description ::text").getall()
        return " ".join(line.strip() for line in val_0)
```

- Проект разработан преимущественно на личное, некоммерческое использование с client-side 
стороны. 
Автор проекта не несет ответственности за поломки, убытки в высоко нагруженных проектах и решение
предоставляется "Как есть" в соответствии с [MIT](LIENSE) лицензией.

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

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

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "anicli-api",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "anime,api,ru,russia,asyncio,parser,httpx,dev",
    "author": "vypivshiy",
    "author_email": "",
    "download_url": "https://files.pythonhosted.org/packages/a1/6c/f2df2c53aa09069db63f07321deb792c811bd2b3859906c213e1b736560b/anicli_api-0.5.0.tar.gz",
    "platform": null,
    "description": "# anicli-api\n\n\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043d\u0430\u0431\u043e\u0440\u0430 \u043f\u0430\u0440\u0441\u0435\u0440\u043e\u0432 \u0430\u043d\u0438\u043c\u0435 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432.\n\n\u041f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 sync \u0438 async \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e `httpx` \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438\n\u041f\u0430\u0440\u0441\u0435\u0440\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043d\u0430 REST-API (\u0435\u0441\u043b\u0438 \u0443 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0435\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f), parsel \u0438 \u043e\u0431\u0451\u0440\u0442\u043a\u0438 scrape-schema\n\n# install\n`pip install anicli-api`\n\n# Overview\n\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\n```\nanicli_api\n\u251c\u2500\u2500 base.py - \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u043c\u043e\u0434\u0443\u043b\u044f-\u043f\u0430\u0440\u0441\u0435\u0440\u0430\n\u251c\u2500\u2500 _http.py - \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b httpx\n\u251c\u2500\u2500 _logger.py - \u043b\u043e\u0433\u0433\u0435\u0440\n\u251c\u2500\u2500 player - \u043c\u043e\u0434\u0443\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0441\u044b\u043b\u043e\u043a \u043d\u0430 \u0432\u0438\u0434\u0435\u043e\n\u2502     \u251c\u2500\u2500 __template__.py - \u0448\u0430\u0431\u043b\u043e\u043d \u043c\u043e\u0434\u0443\u043b\u044f PlayerExtractor\n\u2502     \u251c\u2500\u2500 ...  ready-made \u043c\u043e\u0434\u0443\u043b\u0438\n\u2502     ...\n\u2514\u2500\u2500 source - \u043c\u043e\u0434\u0443\u043b\u0438 \u043f\u0430\u0440\u0441\u0435\u0440\u043e\u0432 \u0441 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432\n      \u251c\u2500\u2500 parsers/... \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u0430\u0440\u0441\u0435\u0440\u044b html \u0441\u0442\u0440\u0430\u043d\u0438\u0446\n      \u251c\u2500\u2500 __template__.py - \u0448\u0430\u0431\u043b\u043e\u043d \u0434\u043b\u044f \u044d\u043a\u0441\u0442\u0440\u0430\u043a\u0442\u043e\u0440\u0430\n      \u251c\u2500 ... ready-made \u043f\u0430\u0440\u0441\u0435\u0440\u044b\n      ...\n\n\n```\n\n\u0421\u0445\u0435\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0439 \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0430\u0440\u0441\u0435\u0440\u043e\u0432:\n\n![](high-level-schema.png)\n\n# source description\n- name - \u0438\u043c\u044f \u043c\u043e\u0434\u0443\u043b\u044f\n- type - \u0442\u0438\u043f \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445. \n  - **NO** - \u043d\u0435\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 (\u043f\u0430\u0440\u0441\u0438\u043d\u0433 html \u0441\u0442\u0440\u0430\u043d\u0438\u0446) \n  - **YES** - \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 (rest-api)\n- note - \u043f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u044f\n- dubbers - \u0442\u0438\u043f \u043e\u0437\u0432\u0443\u0447\u0435\u043a. many - \u043e\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0430\u0432\u0442\u043e\u0440\u043e\u0432. subtitles - \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b. author - \u0441\u0432\u043e\u044f\n\n| name           | url                        | official api | dubbers           | note                                                                    |\n|----------------|----------------------------|--------------|-------------------|-------------------------------------------------------------------------|\n| animego        | https://animego.org        | NO           | many              | \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 kodik, animego, \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 IP \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0445 \u043e\u0442 \u0421\u041d\u0413                |\n| animania       | https://animania.online    | NO           | many              | \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a kodik, \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 IP \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0445 \u043e\u0442 \u0421\u041d\u0413                          |\n| animejoy       | https://animejoy.ru        | NO           | subtitles         | **\u0438\u043c\u0435\u0435\u0442 cloudflare** (\u043c\u043e\u0436\u0435\u0442 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c), \u043c\u043d\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 |\n| sovetromantica | https://sovetromantica.com | NO           | subtitles, author | \u043d\u0435 \u043d\u0430 \u0432\u0441\u0435 \u0442\u0430\u0439\u0442\u043b\u044b \u0435\u0441\u0442\u044c \u0432\u0438\u0434\u0435\u043e, \u0443 \u0441\u0435\u0431\u044f \u0445\u043e\u0441\u0442\u044f\u0442                              |\n| anilibria      | https://anilibria.tv       | YES          | author            |                                                                         |\n| animevost      | https://animevost.org      | YES          | author            |                                                                         |\n\n\n# players description\n\n\u0422\u0440\u0435\u0431\u0443\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432\n\n- name - \u0438\u043c\u044f \u043f\u043b\u0435\u0435\u0440\u0430\n- max quality - \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432\u044b\u0434\u0430\u0432\u0430\u0435\u043c\u043e\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c 0 (\u0430\u0443\u0434\u0438\u043e, \u0431\u0435\u0437 \u0432\u0438\u0434\u0435\u043e), 144, 240, 360, 480, 720, 1080\n- note - \u043f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u044f\n\n| name           | max quality                               | note                                                           |\n|----------------|-------------------------------------------|----------------------------------------------------------------|\n| kodik          | 720 (\u043d\u0430 \u0441\u0442\u0430\u0440\u044b\u0445 \u0442\u0430\u0439\u0442\u043b\u0430\u0445 - 480)             | **\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 IP \u0421\u041d\u0413**                                  |\n| aniboom        | 1080                                      | **\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 IP \u0421\u041d\u0413**                                  |\n| sibnet         | 480                                       |                                                                |\n| animejoy       | 1080                                      | \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 ongoing, \u043f\u043e\u0442\u043e\u043c \u0432\u0438\u0434\u0435\u043e \u0443\u0434\u0430\u043b\u044f\u044e\u0442\u0441\u044f \u0441 \u0438\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 |\n| csst           | 1080                                      |                                                                |\n| dzen           | 1080                                      |                                                                |\n| mailru         |                                           |                                                                |\n| okru           |                                           |                                                                |\n| sovetromantica | 1080                                      |                                                                |\n| vkcom          | 1080 (\u043a\u0430\u043a\u043e\u0433\u043e \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0430\u0432\u0442\u043e\u0440 \u0437\u0430\u043b\u044c\u0435\u0442 \u0432\u0438\u0434\u0435\u043e) | CDN \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432 \u0420\u0424, \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0442\u0440\u0430\u043d\u0430\u0445 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435       |\n\n\n# Quickstart example\n\n```python\nfrom anicli_api.source.animego import Extractor  # can usage any source\n\nif __name__ == \"__main__\":\n    ex = Extractor()\n    print(\"PRESS CTRL + C for exit app\")\n    while True:\n        results = ex.search(input(\"search query > \"))\n        if not results:\n            print(\"Not founded, try again\")\n            continue\n        \n        print(*[f\"{i}) {r}\" for i, r in enumerate(results)], sep=\"\\n\")\n        anime = results[int(input(\"anime > \"))].get_anime()\n        episodes = anime.get_episodes()\n        print(*[f\"{i}) {ep}\" for i, ep in enumerate(episodes)], sep=\"\\n\")\n        episode = episodes[int(input(\"episode > \"))]\n        sources = episode.get_sources()\n        print(*[f\"{i}) {source}\" for i, source in enumerate(sources)], sep=\"\\n\")\n        source = sources[int(input(\"source > \"))]\n        videos = source.get_videos()\n        print(*[f\"{i} {video}\" for i, video in enumerate(videos)], sep=\"\\n\")\n        video = videos[int(input(\"video > \"))]\n        print(video.type, video.quality, video.url, video.headers)\n\n```\n\n\u0421 asyncio \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e, \u043d\u043e **\u0432\u0441\u0435** \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438\u043c\u0435\u044e\u0442 \u043f\u0440\u0435\u0444\u0438\u043a\u0441 `a_`:\n\n```python\nimport asyncio\nfrom anicli_api.source.animego import Extractor # \u0438\u043b\u0438 \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\n\nasync def main():\n    ex = Extractor()\n    prompt = input(\"search query > \")\n    # a_ - async prefix.\n    # simular in Ongoing, Anime, Episode, Source, Video objects\n    results = await ex.a_search(prompt) \n    print(*[f\"{i}) {r}\" for i, r in enumerate(results)], sep=\"\\n\")\n    \nif __name__ == '__main__':\n    asyncio.run(main())\n```\n\n## http path\n\n### source\n\n\u0415\u0441\u043b\u0438 \u043f\u043e \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043b\u0438\u0431\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u0432\u0430\u0441 \u043d\u0435 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u044e\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e - \u0442\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0434\u0430\u0442\u044c\n\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e http \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u044d\u043a\u0441\u0442\u0440\u0430\u043a\u0442\u043e\u0440\u043e\u0432\n\n```python\nfrom anicli_api.base import HTTPSync\n\nfrom httpx import HTTPTransport\n\nclient = HTTPSync()\nprint(client._transport)  # anicli_api._http.HTTPRetryConnectSyncTransport\nprint(client.headers) # {'user-agent': 'Mozilla/5.0 (Linux; Android 6.0...', ...}\n\nclient_2 = HTTPSync(transport=HTTPTransport(), # default transport\n                    headers={\"user-agent\": \"My Cool useragent\"}\n                    )  \n\nprint(client_2._transport)  # httpx.HTTPTransport\nprint(client_2.headers)  # {'user-agent': 'My Cool useragent', ...}\nassert client_2 == client  # Passed\n```\n### player\n\n\u0412 player \u0434\u043b\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 httpx \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 (Client, AsyncioClient) \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c kwargs \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b:\n\n```python\nfrom anicli_api.source.animego import Extractor\n\n\nsources = (\n    Extractor()\n    .search(\"lain\")[0]\n    .get_anime()\n    .get_episodes()[0]\n    .get_sources()\n)\n\nvideos = sources[0].get_videos(transport=None,  # reset to default httpx.HTTPTransport\n                               headers={\"User-Agent\": \"i'm crushing :(\"})\n```\n\n## \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432\n\n\u041f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u044b \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 **\u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e** \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 API, \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u0445\n\u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0438\u043b\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u0430\u0445 \n\n\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 `anilibria` \u0438 `animevost` \u043f\u043e\u0447\u0442\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b \u043e\u0442\u0432\u0435\u0442\u0430\u043c API. \n\u0412 `animego.Anime` \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0439 `raw_json` \u0434\u043b\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.\n\n### Search\n- url: str - URL \u043d\u0430 \u0442\u0430\u0439\u0442\u043b\n- title: str - \u0438\u043c\u044f \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0430\u0439\u0442\u043b\u0430\n- thumbnail: str - \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\n\n### Ongoing\n- url: str - URL \u043d\u0430 \u0442\u0430\u0439\u0442\u043b\n- title: str - \u0438\u043c\u044f \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0430\u0439\u0442\u043b\u0430\n- thumbnail: str - \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\n\n### Anime\n- title: str - \u0438\u043c\u044f \u0442\u0430\u0439\u0442\u043b\u0430 (\u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c)\n- thumbnail: str - \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\n- description: Optional[str] - \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0430\u0439\u0442\u043b\u0430\n\n### Episode\n- title: str - \u0438\u043c\u044f \u044d\u043f\u0438\u0437\u043e\u0434\u0430\n- num: str - \u043d\u043e\u043c\u0435\u0440 \u044d\u043f\u0438\u0437\u043e\u0434\u0430\n\n### Source\n- url: str - \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\n- title: str - \u0434\u0430\u0431\u0431\u0435\u0440 \u0438\u043b\u0438 \u0438\u043c\u044f \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\n\n### Video\n\n\u041e\u0431\u044a\u0435\u043a\u0442 `Video`, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0438\u0437 `Source.get_video` (\u0438\u043b\u0438 `Source.a_get_video`) \n\u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:\n\n* type - \u0442\u0438\u043f \u0432\u0438\u0434\u0435\u043e (m3u8, mp4, mpd, audio)\n* quality - \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432\u0438\u0434\u0435\u043e (0, 144, 240, 360, 480, 720, 1080)\n* url - \u043f\u0440\u044f\u043c\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0432\u0438\u0434\u0435\u043e\n* headers - \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0435 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0438\u0434\u0435\u043e. \n\u0415\u0441\u043b\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u044c - \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043d\u0435 \u043d\u0443\u0436\u043d\u044b\n\n# \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u044f\n- `anicli_api/source/parsers` - \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u0430\u0440\u0441\u0435\u0440\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \n[scrape-schema-codegen](https://github.com/vypivshiy/selector_schema_codegen) \u0438 \u0444\u0430\u0439\u043b\u043e\u0432-\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 [libanime](https://github.com/libanime/libanime_schema). \n\n- \u0422\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f \u0438 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f, \u0442\u043e \u043f\u0440\u0438 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f\u0445 \u044d\u0442\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \n\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u043e\u0442\u0435\u0440\u044f\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f\u0445.\n\n\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f [animego](anicli_api/source/animego.py):\n\n```python\nfrom anicli_api.source.parsers.animego_parser import AnimeView as AnimeViewOld\n\nclass AnimeView(AnimeViewOld):\n    @staticmethod\n    def _parse_description(part) -> str:\n        # remove whitespaces patch\n        val_0 = part.css(\".description ::text\").getall()\n        return \" \".join(line.strip() for line in val_0)\n```\n\n- \u041f\u0440\u043e\u0435\u043a\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043d\u0430 \u043b\u0438\u0447\u043d\u043e\u0435, \u043d\u0435\u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441 client-side \n\u0441\u0442\u043e\u0440\u043e\u043d\u044b. \n\u0410\u0432\u0442\u043e\u0440 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0435 \u043d\u0435\u0441\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0437\u0430 \u043f\u043e\u043b\u043e\u043c\u043a\u0438, \u0443\u0431\u044b\u0442\u043a\u0438 \u0432 \u0432\u044b\u0441\u043e\u043a\u043e \u043d\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u0435\n\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \"\u041a\u0430\u043a \u0435\u0441\u0442\u044c\" \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 [MIT](LIENSE) \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u0435\u0439.\n\n- \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0446\u0435\u043b\u044c \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u2014 \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044e \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u0433\u043e, \n\u0447\u0442\u043e \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435. \n\u0412\u0435\u0441\u044c \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u043d\u0435\u0430\u0444\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u0445.\n\n- **\u042d\u0442\u043e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \n\u0442\u043e\u043b\u044c\u043a\u043e \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0430\u0440\u0441\u0435\u0440\u043e\u0432 \u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b**\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Anime extractors api implementation",
    "version": "0.5.0",
    "project_urls": {
        "Bug Tracker": "https://github.com/vypivshiy/anicli-api/issues",
        "Cli app": "https://github.com/vypivshiy/ani-cli-ru"
    },
    "split_keywords": [
        "anime",
        "api",
        "ru",
        "russia",
        "asyncio",
        "parser",
        "httpx",
        "dev"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "3a1335c9c052063d646d8e9c1a7db0cbc56fef43591f9f88b2e20ce9e8f70c49",
                "md5": "8e8aad7535df89a82cd30a0a02f73f07",
                "sha256": "ab20454b89a408905c1d62395fa75f81fbc3e30a60102ff2aa9ab39677afaf2a"
            },
            "downloads": -1,
            "filename": "anicli_api-0.5.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8e8aad7535df89a82cd30a0a02f73f07",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 39527,
            "upload_time": "2023-12-08T07:44:08",
            "upload_time_iso_8601": "2023-12-08T07:44:08.246149Z",
            "url": "https://files.pythonhosted.org/packages/3a/13/35c9c052063d646d8e9c1a7db0cbc56fef43591f9f88b2e20ce9e8f70c49/anicli_api-0.5.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a16cf2df2c53aa09069db63f07321deb792c811bd2b3859906c213e1b736560b",
                "md5": "fcba49033675449ab2ae4bc951663fd4",
                "sha256": "66563288e2e66cf56d0fba779498efb0748550932fb1c177a376dc66f8e38325"
            },
            "downloads": -1,
            "filename": "anicli_api-0.5.0.tar.gz",
            "has_sig": false,
            "md5_digest": "fcba49033675449ab2ae4bc951663fd4",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 29428,
            "upload_time": "2023-12-08T07:44:10",
            "upload_time_iso_8601": "2023-12-08T07:44:10.024255Z",
            "url": "https://files.pythonhosted.org/packages/a1/6c/f2df2c53aa09069db63f07321deb792c811bd2b3859906c213e1b736560b/anicli_api-0.5.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-12-08 07:44:10",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "vypivshiy",
    "github_project": "anicli-api",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "anicli-api"
}
        
Elapsed time: 0.15777s