anime-parsers-ru 1.13.3
Python package for parsing russian anime players
Requires Python: >=3.10
Keywords: anime, parser, kodik, parsing, aniboom, animego, jutsu, shikimori, kodikapi, kodik api, аниме, парсинг, кодик, парсер, анибум, анимего, джутсу, шикимори, кодик апи

# AnimeParsers
[![PyPI - Downloads](https://img.shields.io/pypi/dm/anime-parsers-ru?label=PyPI%20downloads)
]() [![PyPI - Version](https://img.shields.io/pypi/v/anime-parsers-ru)
]()
## Описание
Данный проект нацелен на создание наиболее широкого спектра парсеров на python для различных аниме-плееров в русскоязычном/снг сегменте

Актуальная стабильная версия доступна на [pypi](https://pypi.org/project/anime-parsers-ru/) или в [релизах](https://github.com/YaNesyTortiK/AnimeParsers/releases) на гитхабе 

## Что есть на данный момент
- [x] Парсер Kodik (__требуется api ключ__)
- [x] Асинхронный парсер Kodik
- [x] Парсер AniBoom (на основе animego, не требует api ключей)
- [x] Асинхронный парсер Aniboom
- [ ] Парсер JutSu (без функции поиска, не требует api ключей) (Сервис заблокирован ркн)
- [x] Парсер Shikimori (с возможностью использовать псевдо-api, не требует api ключей)
- [x] Асинхронный парсер Shikimori

## Установка
- Стандартная установка:
    ```commandline
    pip install anime-parsers-ru
    ```
- Установка с lxml:
    ```commandline
    pip install anime-parsers-ru[lxml]
    ```
    Для использования lxml при инициализации парсера установите параметр `use_lxml = True`
- Установка с асинхронными библиотеками (без lxml):
    ```commandline
    pip install anime-parsers-ru[async]
    ```

Установка lxml вручную:
```commandline
pip install lxml
```

# Инструкция к парсерам

## Оглавление
- [Kodik инструкция](#kodik-инструкция)
- [AniBoom инструкция](#aniboom-инструкция)
- [JutSu инструкция](#jutsu-инструкция)
- [Shikimori инструкция](#shikimori-инструкция)
- [Типы Исключений](#типы-исключений)

## Kodik инструкция

> [!IMPORTANT]
> Если вы хотите использовать функции библиотеки для апи кодика, то вся документация расположена в файле [KODIK_API.md](KODIK_API.md) 

> [!WARNING]
> Токен получаемый с помощью функции `get_token` НЕ работает для функций base_search, base_search_by_id, get_list и search
> По умолчанию данная функция не используется и класс требует от пользователя указать корректный токен.
> Если вы хотите использовать ограниченный функционал библиотеки, то можете при инициализации указать параметры 
> `token=KodikParser.get_token(), validate_token=False` (Для асинхронного параметр `token=KodikParserAsync.get_token_sync()`)

> [!TIP]
> В большинстве случаев в комментариях к функциям описаны шаблоны и возможные значения возвращаемых данных

0. Установите и импортируйте библиотеку
    
    Стандартно:
    ```commandline
    pip install anime-parsers-ru
    ```
    С lxml:
    ```commandline
    pip install anime-parsers-ru[lxml]
    ```
    ```python
    from anime_parsers_ru import KodikParser

    parser = KodikParser(<ваш api ключ>)
    ```

    __Для асинхронного кода__:
    ```commandline
    pip install anime-parsers-ru[async]
    ```
    (Установка без lxml)
    ```python
    from anime_parsers_ru import KodikParserAsync

    parser = KodikParserAsync(<ваш api ключ>)
    ```

1. Поиск аниме по названию
    ```python
    parser.search(title="Наруто", limit=None, include_material_data=True, anime_status=None, strict=False, only_anime=False) # список словарей
    # title - Название аниме/фильма/сериала
    # limit - количество результатов выдачи (int) (результатов будет сильно меньше чем указанное число, так как в выдаче результаты повторяются)
    # include_material_data - Добавлять дополнительные данные об элементе
    # anime_status - Статус выхода аниме (доступно: released, ongoing, None - если ищется не аниме или любой статус)
    # strict - Исключение названий далеких от оригинального
    # only_anime - возвращать только элементы где type in ['anime', 'anime-serial']
    ```
    Возвращает:
    ```json
    [
    {
        "title": "Название",
        "type": "тип мультимедиа (anime, film, ...)",
        "year": "Год выпуска фильма",
        "screenshots": [
            "ссылки на скриншоты"
        ],
        "shikimori_id": "Id шикимори, если нет - None",
        "kinopoisk_id": "Id кинопоиска, если нет - None",
        "imdb_id": "Id imdb, если нет - None",
        "worldart_link": "ссылка на worldart, если нет - None",
        "additional_data": {
            "Здесь будут находится все остальные данные выданные кодиком, не связанные с отдельным переводом"
        },
        "material_data": { 
            "Здесь будут все данные о сериале имеющиеся у кодика. (None если указан параметр include_material_data=False)
            В том числе оценки на шикимори, статус выхода, даты анонсов, выхода, все возможные названия, жанры, студии и многое другое."
        },
        "link": "ссылка на kodik.info (Пример: //kodik.info/video/20609/e8fd5bc1190b7eb1ee1a3e1c3aec5f62/720p)"
    },
    ]
    ```

2. Поиск аниме по id
    ```python
    parser.search_by_id(id="20", id_type="shikimori", limit=None)
    # id - id аниме на одном из сайтов
    # id_type - с какого сайта id (Поддерживается: shikimori, kinopoisk, imdb)
    # limit - количество результатов выдачи (int) (результатов будет сильно меньше чем указанное число, так как в выдаче результаты повторяются)
    ```
    Возвращает:
    ```json
    [
    {
        "title": "Название",
        "type": "тип мультимедиа (anime, film, ...)",
        "year": "Год выпуска фильма",
        "screenshots": [
            "ссылки на скриншоты"
        ],
        "shikimori_id": "Id шикимори, если нет - None",
        "kinopoisk_id": "Id кинопоиска, если нет - None",
        "imdb_id": "Id imdb, если нет - None",
        "worldart_link": "ссылка на worldart, если нет - None",
        "additional_data": {
            "Здесь будут находится все остальные данные выданные кодиком, не связанные с отдельным переводом"
        },
        "material_data": { 
            "Здесь будут все данные о сериале имеющиеся у кодика. (None если указан параметр include_material_data=False)
            В том числе оценки на шикимори, статус выхода, даты анонсов, выхода, все возможные названия, жанры, студии и многое другое."
        },
        "link": "ссылка на kodik.info (Пример: //kodik.info/video/20609/e8fd5bc1190b7eb1ee1a3e1c3aec5f62/720p)"
    },
    ]
    ```

3. Получить список аниме
    ```python
    data = parser.get_list(limit_per_page=50, pages_to_parse=1, include_material_data=True, anime_status=None, only_anime=False, start_from=None)
    # limit_per_page - количество результатов на одной странице (итоговых результатов будет сильно меньше чем указан параметр)
    # pages_to_parse - количество страниц для обработки (каждая страница - отдельный запрос)
    # include_material_data - включить в результат дополнительные данные
    # anime_status - Статус выхода аниме (доступно: released, ongoing, None - если ищется не аниме или любой статус)
    # only_anime - возвращать только элементы где type in ['anime', 'anime-serial']
    # start_from - начать поиск со страницы под id (id возвращается вторым элементом результата функции)
    ```
    Возвращает:
    ```json
    (
        [
        {
            "title": "Название",
            "type": "тип мультимедиа (anime, film, ...)",
            "year": "Год выпуска фильма",
            "screenshots": [
                "ссылки на скриншоты"
            ],
            "shikimori_id": "Id шикимори, если нет - None",
            "kinopoisk_id": "Id кинопоиска, если нет - None",
            "imdb_id": "Id imdb, если нет - None",
            "worldart_link": "ссылка на worldart, если нет - None",
            "additional_data": {
                "Здесь будут находится все остальные данные выданные кодиком, не связанные с отдельным переводом"
            },
            "material_data": { 
                "Здесь будут все данные о сериале имеющиеся у кодика. (None если указан параметр include_material_data=False)
                В том числе оценки на шикимори, статус выхода, даты анонсов, выхода, все возможные названия, жанры, студии и многое другое."
            },
            "link": "ссылка на kodik.info (Пример: //kodik.info/video/20609/e8fd5bc1190b7eb1ee1a3e1c3aec5f62/720p)"
        },
        ],
        "next_page_id": "id следующей страницы (для последовательного парсинга нескольких страниц) (может быть None, если след. страниц нет)"
    )
    ```

4. Получить информацию об аниме
    ```python
    parser.get_info(id="z20", id_type="shikimori")
    # id - id аниме на одном из сайтов
    # id_type - с какого сайта id (Поддерживается: shikimori, kinopoisk, imdb)
    ```
    Возвращает:
    ```json
    {
        "series_count": 220, 
        "translations": [
            {"id": "735", "type": "Озвучка", "name": "2x2 (220 эп.)"}, 
            {"id": "609", "type": "Озвучка", "name": "AniDUB (220 эп.)"}, 
            {"id": "869", "type": "Субтитры", "name": "Субтитры (220 эп.)"}, 
            {"id": "958", "type": "Озвучка", "name": "AniRise (135 эп.)"}, 
            {"id": "2550", "type": "Озвучка", "name": "ANI.OMNIA (8 эп.)"}
        ]
    }
    ```

    - Получить отдельно кол-во серий:
        ```python
        parser.series_count("z20", "shikimori") # число
        ```
    - Получить отдельно переводы:
        ```python
        parser.translations("z20", "shikimori") # список словарей
        ```
5. Прямая ссылка на видеофайл
    ```python
    parser.get_link(
        id="z20", 
        id_type="shikimori", 
        seria_num=1, 
        translation_id="609") # Кортеж
    # id - id медиа
    # id_type - тип id (возможные: shikimori, kinopoisk, imdb)
    # seria_num - номер серии (если фильм или одно видео - 0)
    # translation_id - id перевода (прим: Anilibria = 610, если неизвестно - 0)
    ```
    Возвращает кортеж: `("//cloud.kodik-storage.com/useruploads/67b6e546-e51d-43d2-bb11-4d8bfbedc2d7/d6f4716bc90bd30694cf09b0062d07a2:2024062705/", 720)`
    
    1. Ссылка
    Пример: `//cloud.kodik-storage.com/useruploads/67b6e546-e51d-43d2-bb11-4d8bfbedc2d7/d6f4716bc90bd30694cf09b0062d07a2:2024062705/`
    К данной ссылке в начале нужно добавить `http:` или `https:`, а в конце качество.mp4 (`720.mp4`) (Обычно доступны следующие варианты качества: `360`, `480`, `720`)
    2. Максимально возможное качество
    Прим: `720` (1280x720)

6. Ссылка на m3u8 плейлист
    ```python
    parser.get_m3u8_playlist_link(
        id="z20", 
        id_type="shikimori", 
        seria_num=1, 
        translation_id="609",
        quality=480) # Для "Наруто" нет 720p, хотя сервер и возвращает 720 в списке источников
    # id - id медиа
    # id_type - тип id (возможные: shikimori, kinopoisk, imdb)
    # seria_num - номер серии (если фильм или одно видео - 0)
    # translation_id - id перевода (прим: Anilibria = 610, если неизвестно - 0)
    # quality - Желаемое качество (360, 480, 720). Если указанное качество будет больше, чем максимально доступное, вернется ссылка с максимально доступным качеством. По умолчанию: 720
    ```
    Возвращает строку вида:
    `https://cloud.kodik-storage.com/.../.../720.mp4:hls:manifest.m3u8`

7. Текстовое содержание m3u8 плейлиста
    ```python
    parser.get_m3u8_playlist(
        id="z20", 
        id_type="shikimori", 
        seria_num=1, 
        translation_id="609",
        quality=480) # Для "Наруто" нет 720p, хотя сервер и возвращает 720 в списке источников
    # id - id медиа
    # id_type - тип id (возможные: shikimori, kinopoisk, imdb)
    # seria_num - номер серии (если фильм или одно видео - 0)
    # translation_id - id перевода (прим: Anilibria = 610, если неизвестно - 0)
    # quality - Желаемое качество (360, 480, 720). Если указанное качество будет больше, чем максимально доступное, вернется ссылка с максимально доступным качеством. По умолчанию: 720
    ```
    Возвращает строку вида:
    ```
    #EXTM3U
    #EXT-X-TARGETDURATION:6
    #EXT-X-ALLOW-CACHE:YES
    #EXT-X-PLAYLIST-TYPE:VOD
    #EXT-X-VERSION:3
    #EXT-X-MEDIA-SEQUENCE:1
    #EXTINF:6.000,
    https://.../480.mp4:hls:seg-1-v1-a1.ts
    #EXTINF:6.000,
    https://.../480.mp4:hls:seg-2-v1-a1.ts
    #EXTINF:6.000,
    https://.../480.mp4:hls:seg-3-v1-a1.ts
    ```

    Ключевое отличие от плейлиста который скачивается просто по ссылке (полученной в п.6) в том, что данная функция добавляет полную ссылку до сегментов. В изначальном файле ссылки содержатся в виде `./480.mp4...` что будет работать если ссылка открыта, например, в браузере, но не будет работать если файл открыт локально. С добавлением полной ссылки можно сохранить файл локально и запускать любым плеером который поддерживает m3u8 плейлисты (например VLC).


> [!IMPORTANT]
> В случае, если аниме является фильмом или содержит только одну серию, в параметр `seria_num` указывается значение `0`. В случае если перевод/субтитры неизвестны или нет выбора, в параметр `translation_id` указывается значение `"0"`

6. Прямое обращение к апи кодика
    Рекомендуется использовать модули KodikSearch и KodikList для обращения к апи.
    ```python
    parser.api_request (
        endpoint="list",
        filters={
            "limit": 5
        },
        parameters={
            "with_episodes_data": True
        }
    )
    # endpoint - ссылка куда направляется запрос (доступно: "search", "list", "translations")
    # filters - фильтры запроса
    # parameters - дополнительные параметры (для удобства можно их записывать в один словарь с фильтрами)
    ```
    Возвращает необработанный ответ от сервера кодика.
    Для подробного списка фильтров, параметров и примеров смотрите [инструкцию](KODIK_API.md).




7. Получить токен
    ```python
    parser.get_token() # строка
    # Или
    KodikParser.get_token()
    ```
    Использует один из скриптов кодика в котором указан api ключ, поэтому может не работать из-за внесенных изменений

## AniBoom инструкция
0. Установите и импортируйте библиотеку
    ```commandline
    pip install anime-parsers-ru
    ```
    ```python
    from anime_parsers_ru import AniboomParser

    parser = AniboomParser()
    # Если вы знаете что есть актуальное зеркало сайта, можете указать его домен в параметре `mirror` при инициализации класса
    ```
    __Для асинхронного кода__:
    ```commandline
    pip install anime-parsers-ru[async]
    ```
    ```python
    from anime_parsers_ru import AniboomParserAsync

    parser = AniboomParserAsync()
    # Далее перед всеми функциями дополнительно нужно прописывать await
    # Если вы знаете что есть актуальное зеркало сайта, можете указать его домен в параметре `mirror` при инициализации класса
    ```

1. Поиск по названию
    1. Быстрый поиск
    ```python
    parser.fast_search("Название аниме")
    ```
    Возвращает список из словарей в виде:
    ```json
    [
            {
                "title": "Название аниме",
                "year": "Год выпуска",
                "other_title": "Другое название(оригинальное название)",
                "type": "Тип аниме (ТВ сериал, фильм, ...)",
                "link": "Ссылка на страницу с информацией",
                "animego_id": "id на анимего (по сути в ссылке на страницу с информацией последняя цифра и есть id)"
            },
        ]
    ```
    2. Поиск с дополнительной информацией / Расширенный поиск
    ```python
    parser.search("Название аниме")
    ```
    Возвращает список из словарей:
    ```json
    [
        {
            "title": "Название",
            "other_titles": ["Альтернативное название 1", "..."],
            "status": "Статус аниме (онгоинг, анонс, вышел, ...)",
            "type": "Тип аниме (ТВ сериал, фильм, ...)",
            "genres": ["Жанр1", "Жанр2", "..."],
            "description": "описание",
            "episodes": "если аниме вышло, то количество серий, если еще идет, то 'вышло / всего'",
            "episodes_info": [
                {
                    "num": "Номер эпизода",
                    "title": "Название эпизода",
                    "date": "Даты выхода (предполагаемые если анонс)",
                    "status": "'вышло' или 'анонс' (Имеется в виду вышло в оригинале, не переведено)",
                },
            ],
            "translations": [
                {
                    "name": "Название студии",
                    "translation_id": "id перевода в плеере aniboom"
                },
            ],
            "poster_url": "Ссылка на постер аниме",
            "trailer": "Ссылка на ютуб embed трейлер",
            "screenshots": [
                "Список ссылок на скриншоты"
            ],
            "other_info": {
                // Данная информация может меняться в зависимости от типа или состояния тайтла
                "Возрастные ограничения": "(прим: 16+)",
                "Выпуск": "(прим: с 2 апреля 2024)",
                "Главные герои": ["Список главных героев"],
                "Длительность": "(прим: 23 мин. ~ серия)",
                "Первоисточник": "(прим: Легкая новела)",
                "Рейтинг MPAA": "(прим: PG-13)",
                "Сезон": "(прим. Весна 2024)",
                "Снят по ранобэ": "название ранобэ (Или так же может быть 'Снят по манге')",
                "Студия": "название студии"
            },
            "link": "Ссылка на страницу с информацией",
            "animego_id": "id на анимего (по сути в ссылке на страницу с информацией последняя цифра и есть id)"
        },
    ]
    ```
2. Данные по эпизодам. Если в аниме 1 эпизод или это фильм, то данных по эпизодам может не быть.
    ```python
    parser.episodes_info('ссылка на страницу аниме на animego.org') # Ссылка доступна из поиска по ключу 'link'
    ```
    Возвращает отсортированный по номеру серии список:
    ```json
    [   
        {
            "num": "Номер эпизода",
            "title": "Название эпизода",
            "date": "Даты выхода (предполагаемые если анонс)",
            "status": "'вышло' или 'анонс' (Имеется в виду вышло в оригинале, не переведено)"
        },
    ]
    ```
3. Данные по аниме (как в полном/расширенном поиске)
    ```python
    parser.anime_info('ссылка на страницу аниме на animego.org') # Ссылка доступна из поиска по ключу 'link'
    ```
    Возвращает словарь:
    ```json
    {
        "title": "Название",
        "other_titles": ["Альтернативное название 1", "..."],
        "status": "Статус аниме (онгоинг, анонс, вышел, ...)",
        "type": "Тип аниме (ТВ сериал, фильм, ...)",
        "genres": ["Жанр1", "Жанр2", "..."],
        "description": "описание",
        "episodes": "если аниме вышло, то количество серий, если еще идет, то 'вышло / всего'",
        "episodes_info": [
            {
                "num": "Номер эпизода",
                "title": "Название эпизода",
                "date": "Даты выхода (предполагаемые если анонс)",
                "status": "'вышло' или 'анонс' (Имеется в виду вышло в оригинале, не переведено)",
            },
        ],
        "translations": [
            {
                "name": "Название студии",
                "translation_id": "id перевода в плеере aniboom"
            },
        ],
        "poster_url": "Ссылка на постер аниме",
        "trailer": "Ссылка на ютуб embed трейлер",
        "screenshots": [
            "Список ссылок на скриншоты"
        ],
        "other_info": {
            // Данная информация может меняться в зависимости от типа или состояния тайтла
            "Возрастные ограничения": "(прим: 16+)",
            "Выпуск": "(прим: с 2 апреля 2024)",
            "Главные герои": ["Список главных героев"],
            "Длительность": "(прим: 23 мин. ~ серия)",
            "Первоисточник": "(прим: Легкая новела)",
            "Рейтинг MPAA": "(прим: PG-13)",
            "Сезон": "(прим. Весна 2024)",
            "Снят по ранобэ": "название ранобэ (Или так же может быть 'Снят по манге')",
            "Студия": "название студии"
        },
        "link": "Ссылка на страницу с информацией",
        "animego_id": "id на анимего (по сути в ссылке на страницу с информацией последняя цифра и есть id)"
    },
    ```

4. Данные по переводам (которые есть в плеере aniboom)
    ```python
    parser.get_translation_info('animego_id') # Ссылка доступна из поиска по ключу 'animego_id'
    ```
    Возвращает список словарей:
    ```json
    [
        {
            "name": "Название студии озвучки",
            "translation_id": "id перевода в плеере aniboom"
        }
    ]
    ```

5. Получить контент файла mpd (mp4 файл разбитый на чанки) в виде строки. При сохранении данной строки в .mpd файл и при открытии его плеером, который поддерживает такой формат (прим: VLC PLayer), можно смотреть серию без рекламы. Обратите внимание, что в данном файле находятся именно ссылки на чанки, а не само видео, поэтому потребуется доступ в интернет. (Вы можете использовать ffmpeg для конвертации этого файла в mp4 формат)
    ```python
    parser.get_mpd_playlist('animego_id', 'episode_num', 'translation_id')
    # animego_id можно найти в результате поиска по ключу 'animego_id' (либо взять последние цифры в ссылке на страницу аниме на animego.org)
    # episode_num - номер вышедшего эпизода (нужно чтобы эпизод вышел именно с выбранной озвучкой)
    # translation_id - id перевода в базе aniboom (Можно найти либо в результате поиска, либо через anime_info, либо через get_translation_info)
    ```
    Возвращает строку - контент mpd файла
    
> [!IMPORTANT]
> В случае, если аниме является фильмом или содержит только одну серию, в параметр `episode_num` указывается значение `0`.

6. Сохранить mpd файл (Дополняет предыдущую функцию get_mpd_playlist)
    ```python
    parser.get_as_file('animego_id', 'episode_num', 'translation_id', 'filename')
    # animego_id можно найти в результате поиска по ключу 'animego_id' (либо взять последние цифры в ссылке на страницу аниме на animego.org)
    # episode_num - номер вышедшего эпизода (нужно чтобы эпизод вышел именно с выбранной озвучкой)
    # translation_id - id перевода в базе aniboom (Можно найти либо в результате поиска, либо через anime_info, либо через get_translation_info)
    # filename - имя файла или путь
    ```
    Сохраняет файл по указанному имени/пути

> [!IMPORTANT]
> В случае, если аниме является фильмом или содержит только одну серию, в параметр `episode_num` указывается значение `0`.

## JutSu инструкция
0. Установите и импортируйте библиотеку
    ```commandline
    pip install anime-parsers-ru
    ```
    ```python
    from anime_parsers_ru import JutsuParser

    parser = JutsuParser()
    # Если вы знаете что есть актуальное зеркало сайта, можете указать его домен в параметре `mirror` при инициализации класса
    ```

1. Данные по аниме (по ссылке на страницу)
    ```python
    parser.get_anime_info("Ссылка на страницу")
    # Пример ссылки: https://jut.su/tondemo-skill/
    # Для аниме: Кулинарные скитания в параллельном мире
    ```
    Возвращает словарь:
    ```json
    {
        "title": "Название аниме",
        "origin_title": "Оригинальное название (транслит японского названия на английском)",
        "age_rating": "Возрастное ограничение",
        "description": "Описание",
        "years": ["Год выхода 1 сезона", "Год выхода 2 сезона"],
        "genres": ["Жанр 1", "Жанр 2"],
        "poster": "Ссылка на картинку (плохое качество)",
        "seasons": [
            [ // 1 сезон будет обязательно, даже если у аниме нет других сезонов
                "ссылка на 1 серию 1 сезона (страница с плеером)",
                "ссылка на 2 серию 1 сезона (страница с плеером)"
            ],
            [ // 2 сезон если есть
                "ссылка на 1 серию 2 сезона (страница с плеером)",
                "ссылка на 2 серию 2 сезона (страница с плеером)"
            ],
        ],
        "seasons_names": [ // Если у аниме только 1 сезон, этот список будет пустым
            "Название 1 сезона", 
            "Название 2 сезона"
        ],
        "films": [ // Если фильмов нет - список пустой
            "Ссылка на фильм 1 (страница с плеером)",
            "Ссылка на фильм 2 (страница с плеером)",
        ]
    }
    ```

2. Получить ссылку на mp4 файл
    ```python
    parser.get_mp4_link('ссылка на страницу с плеером')
    # Пример ссылки: https://jut.su/tondemo-skill/episode-1.html
    # Еще пример ссылки: https://jut.su/ookami-to-koshinryou/season-1/episode-1.html
    ```
    Возвращает словарь:
    ```json
    {
        "360": "ссылка на mp4 файл с качеством 360p",
    }
    ```

> [!IMPORTANT]
> Для разных аниме разное количество доступных качеств плеера. (Например для "Наруто" доступно только 360 и 480, для большинства новых аниме доступно качество до 1080)
> Также jutsu не позволяет выбрать озвучку для аниме.

> [!NOTE]
> Для jutsu нет функции поиска, потому что он использует поиск яндекса по сайту и из-за того что он "умный" он может работать абсолютно непредсказуемо.
> В качестве "поиска" вы можете использовать оригинальное название аниме. Так как ссылка формируется по следующей схеме:
> Название аниме: Волчица и пряности
> Оригинальное название: Ookami to Koushinryou
> Ссылка на страницу: https://jut.su/ookami-to-koshinryou/

## Shikimori инструкция
0. Установите и импортируйте библиотеку
    ```commandline
    pip install anime-parsers-ru
    ```
    ```python
    from anime_parsers_ru import ShikimoriParser

    parser = ShikimoriParser()
    # Если вы знаете что есть актуальное зеркало сайта, можете указать его домен в параметре `mirror` при инициализации класса
    ```
    __Для асинхронного кода__:
    ```commandline
    pip install anime-parsers-ru[async]
    ```
    ```python
    from anime_parsers_ru import ShikimoriParserAsync

    parser = ShikimoriParserAsync()
    # Далее перед всеми функциями дополнительно нужно прописывать await
    # Если вы знаете что есть актуальное зеркало сайта, можете указать его домен в параметре `mirror` при инициализации класса
    ```

> [!NOTE]
> Шикимори ограничивает частоту запросов на сервер.
> Если шикимори возвращает код ответа 520, парсер вернет exception TooManyRequests.
> Для избежания этой ошибки делайте задержку 1-3 секунды между запросами.

1. Поиск аниме по названию
    ```python
    parser.search('Название аниме')
    ```
    Возвращает список словарей:
    ```json
    [
        {
            "genres": ["Жанр1", "Жанр2"],
            "link": "Ссылка на страницу аниме",
            "original_title": "Оригинальное название (транслит японского названия на английском)",
            "poster": "Ссылка на постер к аниме (плохое качество) (если есть, иначе None)",
            "shikimori_id": "id шикимори",
            "status": "статус (вышло, онгоинг, анонс) (если есть, иначе None)",
            "studio": "студия анимации (если есть, иначе None)",
            "title": "Название",
            "type": "тип аниме (TV сериал, OVA, ONA, ...) (если есть, иначе None)",
            "year": "год выхода (если есть, иначе None)"
        }
    ]
    ```

2. Информация об аниме
    ```python
    parser.anime_info('shikimori_link')
    # Ссылку на шикимори можно получить с помощью функции
    # parser.link_by_id
    ```
    Возвращает словарь:
    ```json
    {
        "dates": "Даты выхода",
        "description": "Описание",
        "episode_duration": "Средняя продолжительность серии",
        "episodes": "Количество эпизодов если статус 'вышло' или 'вышедших эпизодов / анонсировано эпизодов' или None (если фильм)",
        "genres": ["Жанр1", "Жанр2"],
        "licensed": "Кто лицензировал в РФ или None",
        "licensed_in_ru": "Название аниме как лицензировано в РФ или None",
        "next_episode": "Дата выхода следующего эпизода или None",
        "original_title": "Оригинальное название",
        "picture": "Ссылка на jpeg постер",
        "premiere_in_ru": "Дата премьеры в РФ или None",
        "rating": "возрастной рейтинг",
        "score": "оценка на шикимори",
        "status": "статус выхода",
        "studio": "студия анимации",
        "themes": ["Тема1", "Тема2"],
        "title": "Название на русском",
        "type": "тип аниме (TV Сериал, Фильм, т.п.)"
    }
    ```

3. Дополнительная информация об а