YoitsuWrap
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.
Sommaire
- 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
Présentation
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).
- La détection et le contournement des liens vidéo morts grâce à un contrôle de santé (
check_vid_health) intégré avecyt-dlp.
Fonctionnalités clés
- 🌐 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. - ⚡ Vérification automatique des flux (Health Check) : Chaque lien vidéo est testé via
yt-dlpavant le téléchargement. En cas de lien invalide ou expiré sur la source principale, le wrapper récupère automatiquement un lien fonctionnel sur la source alternative. - 🚀 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.
Prérequis
- 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).
Installation
Via pip
pip install YoitsuWrap
En mode développement
git clone https://github.com/TMCooper/YoitsuWrap.git
cd YoitsuWrap
pip install -e .
Configuration Multi-Sources
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é.
Structure des dossiers téléchargés
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/
└── ...
Guide d'utilisation
1. Recherche & téléchargement d'un anime complet
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)
2. Travailler avec les saisons
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)
3. Travailler avec les épisodes
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()
4. Travailler avec les scans
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)
5. Travailler avec les chapitres
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)
Architecture du projet
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
Référence de l'API
Config
| 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") |
Anime
| 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 |
Season
| 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 |
Episode
| 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 |
Scan
| 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 |
Chapter
| 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 |
Licence
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
Metadata
Release files for YoitsuWrap 0.1.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| yoitsuwrap-0.1.6.tar.gz | 31.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| yoitsuwrap-0.1.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 62.4 kB
Release files / yoitsuwrap-0.1.6.tar.gz
| Download URL | yoitsuwrap-0.1.6.tar.gz |
|---|---|
| Size | 31.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6a2f230c4d4b05d86dda614293014b2c18cae7158816c853796cd74e8435e885
|
|
BLAKE2b-256 checksum How to use checksums |
ad5d69a69edb9cc2141f13c9682222e504821ecf3a51ea2c2bddef5e37244781
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / yoitsuwrap-0.1.6-py3-none-any.whl
| Download URL | yoitsuwrap-0.1.6-py3-none-any.whl |
|---|---|
| Size | 30.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
19b4f6a88f46914639f162b131bb68a28a0125f1ba3b4dce43221903c43ca747
|
|
BLAKE2b-256 checksum How to use checksums |
0b07ec42f507b29c67863c9f162c27e9c4b0b4b1c93c44f964a35fcc88713c9a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Security for YoitsuWrap 0.1.6
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.