Wrapper Python moderne et multi-sources pour AnimeSamaApi & VoirAnime_API — recherchez et téléchargez des épisodes d'anime et des chapitres de scans manga en quelques lignes de code avec gestion du multithreading et vérification de la santé des flux vidéo.
- Présentation
- Fonctionnalités clés
- Prérequis
- Installation
- Configuration Multi-Sources
- Guide d'utilisation
- Architecture du projet
- Référence de l'API
- Licence
YoitsuWrap est une bibliothèque Python orientée objet conçue pour interagir simplement avec les APIs d'agrégation d'animes et de mangas (comme AnimeSamaApi et VoirAnime_API).
Elle prend en charge :
- La recherche unifiée d'œuvres (animes & scans).
- Le support multi-sources avec bascule automatique.
- Le téléchargement haute performance grâce au multithreading (épisodes vidéo, chapitres et pages de scans).
- Multi-APIs & Redondance : Configurez simultanément plusieurs sources (ex :
ANIMESAMA,VOIRANIME). Si un contenu ou un lien est indisponible sur une API, YoitsuWrap bascule automatiquement sur les sources suivantes. - Téléchargement parallèle configurable : Contrôlez précisément le nombre de threads simultanés pour les saisons, les épisodes, les chapitres de scans et les images individuelles.
- Organisation automatique : Classement arborescent standardisé de vos médias par titre, saison, version linguistique (VOSTFR, VF) et chapitres.
- Python 3.8+
- Au moins une instance d'API compatible en cours d'exécution (par exemple
AnimeSamaApisur le port5000et/ouVoirAnime_APIsur le port8000). - Les dépendances Python listées dans
pyproject.toml(requests,yt-dlp).
pip install YoitsuWrapgit clone https://github.com/TMCooper/YoitsuWrap.git
cd YoitsuWrap
pip install -e .Avant de requêter les animes, initialisez votre configuration via la méthode statique Config.create_config(). Cette méthode teste la disponibilité des APIs via leur endpoint /status et retourne un dictionnaire de configurations valides :
from YoitsuWrap.Config import Config
# Configuration mono ou multi-sources
config = Config.create_config(
urls=["http://127.0.0.1"], # URL(s) de base des APIs
ports=[5000, 8000], # Ports respectifs des APIs
path=r"C:\Users\vous\Téléchargements", # Dossier racine de destination
sources=["ANIMESAMA", "VOIRANIME"] # Identifiants des sources
)Remarque : Si une source est injoignable lors de l'initialisation, une erreur réseau est signalée et le processus s'arrête par sécurité.
Les fichiers sont automatiquement rangés selon l'arborescence suivante :
<PATH>/
└── Anime/
└── <Titre de l'oeuvre>/
├── <Saison>/ # Ex: 1, 2, remake2024, film, oav...
│ └── <Version>/ # Ex: vostfr, vf
│ ├── 1.mp4
│ ├── 2.mp4
│ └── ...
└── Scans/
├── Chapitre 1/
│ ├── page_1.jpg
│ ├── page_2.jpg
│ └── ...
└── Chapitre 2/
└── ...
La classe Anime est le point d'entrée principal pour manipuler une œuvre (épisodes et scans éventuels) :
from YoitsuWrap.Config import Config
from YoitsuWrap.Anime import Anime
config = Config.create_config(
urls=["http://127.0.0.1"],
ports=[5000, 8000],
path=r"C:\Téléchargements",
sources=["ANIMESAMA", "VOIRANIME"]
)
# 1. Recherche par titre (version 'vostfr' par défaut, ou 'vf')
frieren = Anime.search_by_name(title="Frieren", config=config, version="vostfr")
# Informations générales
print("Titre :", frieren.get_title())
print("Cover :", frieren.get_cover())
print("Lien source :", frieren.get_link())
print("Nombre total d'épisodes :", frieren.get_episodes_num())
# 2. Téléchargement global (épisodes de toutes les saisons + scans si existants)
frieren.download_all(max_seasons_workers=1, max_workers=2, chapter_workers=2)
# 3. Télécharger uniquement les épisodes vidéo
frieren.download_anime(max_seasons_workers=1, max_workers=4)
# 4. Télécharger une saison précise (ex: saison "1", "oav", "film")
frieren.download_anime(season="1", max_workers=2)
# 5. Télécharger les scans associés
frieren.download_scan(images_workers=4, max_workers=2)
# 6. Télécharger un chapitre spécifique de scan
frieren.download_scan(chapter=33, images_workers=4)Vous pouvez inspecter et télécharger directement un objet Season :
from YoitsuWrap.Season import Season
# Instanciation ciblée d'une saison
saison = Season.search_by_name(
title="Spice And Wolf",
saison="remake2024",
version="vostfr",
config=config
)
print(f"{saison.get_title()} - {saison.get_saison()} ({saison.get_version()})")
print("Nombre d'épisodes :", saison.get_episodes_numbers())
# Téléchargement multithreadé de la saison (2 épisodes en parallèle)
saison.download_season(max_workers=2)La classe Episode permet de manipuler les épisodes individuellement, d'extraire leurs URLs de streaming ou de tester leur disponibilité :
from YoitsuWrap.Episode import Episode
# Récupérer la liste des épisodes d'une saison
episodes = Episode.search_by_name(
title="Spice And Wolf",
saison="remake2024",
version="vostfr",
config=config
)
premier_ep = episodes[0]
print("Épisode numéro :", premier_ep.get_episode_number())
print("Lien direct :", premier_ep.get_link())
print("Saison :", premier_ep.get_season())
print("Version :", premier_ep.get_version())
print("Source :", premier_ep.get_source())
# Télécharger l'épisode individuel
premier_ep.download_episode()La classe Scan gère l'ensemble des chapitres d'un manga associé à un titre :
from YoitsuWrap.Scan import Scan
# Recherche des scans d'une œuvre
scan = Scan.search_by_name(manga_name="Frieren", config=config)
if scan:
print("Manga :", scan.get_title())
print("Nombre de chapitres :", scan.get_number_of_chapters())
print("Nombre total de pages :", scan.get_number_of_pages())
# Télécharger tous les chapitres
# (max_workers = chapitres en simultané, images_workers = pages par chapitre)
scan.download_scan(images_workers=4, max_workers=2)
# Télécharger un chapitre précis
scan.download_scan(chapter=1, images_workers=4)La classe Chapter permet d'accéder au découpage page par page :
from YoitsuWrap.Chapter import Chapter
# Récupérer tous les chapitres sous forme de dictionnaire {numéro_int: Chapter}
chapitres = Chapter.search_by_name(manga_title="Frieren", config=config)
chapitre_1 = chapitres[1]
print("Nom du chapitre :", chapitre_1.get_chapter_name()) # "Chapitre 1"
print("Nombre de pages :", chapitre_1.get_number_of_pages())
print("URLs des pages :", chapitre_1.get_page_link()[:3]) # Les premières URLs
# Télécharger les pages du chapitre (ex: 4 images en simultané)
chapitre_1.download_chapter(max_workers=4)YoitsuWrap/
├── src/
│ └── YoitsuWrap/
│ ├── __init__.py
│ ├── Config.py # Gestion des sources API, validation & configuration
│ ├── Anime.py # Classe centrale regroupant saisons, épisodes et scans
│ ├── Season.py # Modèle et gestion des saisons d'anime
│ ├── Episode.py # Gestion d'un épisode, yt-dlp & health check vidéo
│ ├── Scan.py # Gestion globale des scans d'un manga
│ └── Chapter.py # Gestion et téléchargement multithreadé des pages
├── pyproject.toml # Métadonnées, dépendances et configuration du build
├── LICENSE # Licence GPL-3.0-or-later
└── README.md
| Méthode / Attribut | Type / Retour | Description |
|---|---|---|
Config.create_config(urls, ports, path, sources) |
dict[str, Config] |
Teste l'accessibilité de chaque API via /status et renvoie la table des configurations |
BASE_URL |
str |
URL de base de l'API (ex: "http://127.0.0.1") |
PORT |
int |
Port associé à l'API (ex: 5000) |
PATH |
str |
Chemin du dossier racine pour les téléchargements |
API_LINK |
str |
URL complète de l'API déduite (ex: "http://127.0.0.1:5000/api") |
SOURCE |
str |
Nom de la source associée (ex: "ANIMESAMA") |
| Méthode | Paramètres | Retour | Description |
|---|---|---|---|
search_by_name |
title: str, config: dict, version: str = "vostfr" |
Anime | str |
Recherche l'anime sur les APIs et construit l'objet complet |
download_all |
max_seasons_workers=1, max_workers=2, chapter_workers=1 |
int |
Télécharge l'ensemble des saisons et des scans |
download_anime |
max_seasons_workers=1, max_workers=2, season=None |
int |
Télécharge tous les épisodes ou ceux d'une saison ciblée |
download_scan |
chapter=None, images_workers=1, max_workers=2 |
int |
Télécharge les scans disponibles |
get_title() |
- | str |
Titre de l'œuvre |
get_cover() |
- | str |
URL de la jaquette |
get_link() |
- | str |
Lien direct vers la page catalogue source |
get_episodes_num() |
- | int |
Nombre total d'épisodes recensés |
get_seasons() |
- | dict[str, Season] |
Dictionnaire de toutes les saisons disponibles |
get_season(season="1") |
season: str |
Season |
Retourne l'objet Season spécifié |
get_scan() |
- | Scan |
Retourne l'objet Scan associé (ou [] si aucun) |
get_path() |
- | str |
Dossier de destination configuré |
get_api_links() |
- | list[str] |
Liste des liens d'APIs ayant répondu pour cet anime |
| Méthode | Paramètres | Retour | Description |
|---|---|---|---|
search_by_name |
title: str, saison: str, version: str, config: dict |
Season | str |
Construit l'objet d'une saison spécifique |
download_season |
max_workers=1 |
int |
Télécharge tous les épisodes de la saison en parallèle |
get_title() |
- | str |
Titre de l'œuvre |
get_saison() |
- | str |
Nom de la saison (ex: "1", "remake2024") |
get_version() |
- | str |
Version linguistique (ex: "vostfr", "vf") |
get_episodes() |
- | list[Episode] |
Liste des objets Episode |
get_episodes_numbers() |
- | int |
Nombre d'épisodes de la saison |
get_path() |
- | str |
Dossier de destination |
get_api_link() |
- | str |
URL de l'API source ayant servi pour la saison |
| Méthode | Paramètres | Retour | Description |
|---|---|---|---|
search_by_name |
title: str, saison: str, version: str, config: dict |
list[Episode] | str |
Récupère la liste des épisodes avec bascule de source automatique si nécessaire |
download_episode |
- | int |
Télécharge l'épisode via yt-dlp au format MP4 |
check_vid_health(link) |
link: str (statique) |
bool |
Vérifie sans télécharger si le lien vidéo est valide et accessible |
get_title() |
- | str |
Titre de l'œuvre |
get_episode_number() |
- | int |
Numéro de l'épisode |
get_season() |
- | str |
Saison de l'épisode |
get_version() |
- | str |
Version linguistique |
get_link() |
- | str |
URL du flux vidéo |
get_path() |
- | str |
Dossier de destination |
get_api_link() |
- | str |
Lien de l'API d'origine |
get_source() |
- | str |
API source qui a été utilisée pour la récupération des données |
| Méthode | Paramètres | Retour | Description |
|---|---|---|---|
search_by_name |
manga_name: str, config: dict |
Scan | None |
Construit l'objet Scan pour un manga |
download_scan |
chapter=None, images_workers=1, max_workers=1 |
int |
Télécharge tous les chapitres ou un chapitre précis |
get_title() |
- | str |
Titre du manga |
get_chapters(chapter=None) |
chapter: int = None |
dict[int, Chapter] | Chapter |
Retourne tous les chapitres ou le chapitre demandé |
get_number_of_chapters() |
- | int |
Nombre total de chapitres |
get_number_of_pages() |
- | int |
Nombre total de pages cumulées |
get_path() |
- | str |
Dossier de destination |
get_api_link() |
- | str |
Lien de l'API utilisée |
| Méthode | Paramètres | Retour | Description |
|---|---|---|---|
search_by_name |
manga_title: str, config: dict |
dict[int, Chapter] |
Récupère tous les chapitres indexés par numéro entier |
download_chapter |
max_workers=1 |
int |
Télécharge toutes les pages du chapitre dans des fichiers page_X.jpg |
get_title() |
- | str |
Titre du manga |
get_chapter_name() |
- | str |
Nom du dossier/chapitre (ex: "Chapitre 1") |
get_number_of_pages() |
- | int |
Nombre de pages dans ce chapitre |
get_page_link() |
- | list[str] |
Liste des URLs des images du chapitre |
get_path() |
- | str |
Dossier de destination |
get_api_link() |
- | str |
Lien de l'API d'origine |
Ce projet est distribué sous licence GPL-3.0-or-later. Voir le fichier LICENSE pour plus de détails.
Ce dépôt est créé et maintenu par TMCooper