⛩ Ohm Stream Downloader
Application web auto-hébergée (homelab) : centre de contrôle unique pour découvrir, regarder et télécharger des animes et séries VOSTFR/VF.
⚖️ Avertissement légal
Ohm Stream Downloader est un outil technique d'automatisation : il ne fournit, n'héberge ni ne distribue aucun contenu. Il automatise uniquement l'accès à des flux déjà publiquement accessibles sur des sites tiers, dont l'auteur n'est pas responsable et qu'il n'exploite pas.
L'utilisation de ce logiciel relève de la seule responsabilité de l'utilisateur, tenu de respecter la législation de son pays — notamment le droit d'auteur (en France : art. L.122-4 du Code de la propriété intellectuelle). Le téléchargement ou la diffusion d'œuvres protégées sans autorisation est interdit par la loi.
Projet publié à des fins éducatives et de recherche. L'auteur décline toute responsabilité en cas d'usage illégal et n'encourage en aucune façon le piratage.
Disclaimer (EN): this project is a technical automation tool. It does not provide, host or distribute any content — it merely automates access to streams already publicly available on third-party websites that the author neither controls nor operates. Users are solely responsible for complying with their local laws, including copyright. The author assumes no liability for illegal use and does not endorse piracy.
Déploiement (Docker) — recommandé
Le déploiement officiel passe par Docker Compose : l'image (ffmpeg inclus) est
hébergée publiquement sur GHCR (ghcr.io/aulyriusohm/ohm-streaming) — aucun compte requis.
Installation guidée (recommandée)
git clone https://git.lanro.eu/Roman/ohm_streaming.git && cd ohm_streaming
./scripts/install.sh
Le script vérifie Docker, demande la destination des épisodes (dossier dédié
recommandé — voir « Bibliothèque Plex/Sonarr » ci-dessous), le port, génère les
secrets, branche le montage et démarre. Non interactif aussi :
./scripts/install.sh --dir /srv/animes --port 8777.
À la main
# 1. Récupérer le projet
git clone https://git.lanro.eu/Roman/ohm_streaming.git && cd ohm_streaming
# 2. Configuration locale
cp .env.example .env
# → OHM_SECRET_KEY (openssl rand -hex 32) et WATCHTOWER_TOKEN (openssl rand -hex 24) obligatoires
# 3. Démarrage
docker compose up -d
Puis ouvrir http://localhost:8777 — le premier compte créé est administrateur.
Les données (data/, downloads/) sont montées en volumes : elles survivent aux mises à jour.
Variante Podman
Même déploiement via docker-compose.podman.yml (socket Podman pour Watchtower,
au lieu du socket Docker) :
# 0. Socket Podman (une seule fois) — rootless :
systemctl --user enable --now podman.socket
sudo loginctl enable-linger $USER # persister après déconnexion
export PODMAN_SOCKET=/run/user/$(id -u)/podman/podman.sock
# rootful : sudo systemctl enable --now podman.socket (aucun export nécessaire)
# 1. Récupérer le projet
git clone https://git.lanro.eu/Roman/ohm_streaming.git && cd ohm_streaming
# 2. Configuration locale (identique à Docker)
cp .env.example .env # → OHM_SECRET_KEY et WATCHTOWER_TOKEN obligatoires
# 3. Démarrage
podman compose -f docker-compose.podman.yml up -d
# (« podman compose » délègue à docker-compose ; sinon : podman-compose)
La mise à jour depuis la page Admin (bouton Watchtower) fonctionne à l'identique ;
à la main : podman compose -f docker-compose.podman.yml pull && podman compose -f docker-compose.podman.yml up -d.
Bibliothèque Plex / Sonarr existante
Ohm peut déposer ses épisodes directement dans ton serveur de média :
- Crée un dossier dédié (recommandé : hors de la racine Sonarr, ex.
/plex_videos/ohm) et monte-le à la place de./downloads:- /plex_videos/ohm:/downloads— c'est ce que faitscripts/install.sh. - Ajoute ce dossier à Plex comme dossier d'une bibliothèque (ou comme
dossier supplémentaire de ta bibliothèque animes). Les épisodes arrivent
rangés par animé :
One Piece/One Piece - E1010 (VOSTFR).mp4— le nom du dossier sert de série, le fichier d'épisode. - Sonarr n'est pas touché : l'entrypoint du conteneur ne prend possession
(
chown) que d'un dossier de téléchargements vide ; une bibliothèque existante et ses droits restent intacts. Pour piloter Ohm depuis Sonarr ou Prowlarr, voir l'API Torznab plus bas.
Si tu pointes /downloads sur un dossier non vide, Ohm adopte les fichiers
présents (ils apparaissent dans sa bibliothèque interne) et conserve les droits
existants — assure-toi juste que l'uid 1000 du conteneur peut y écrire.
Mettre à jour
Depuis l'interface (déploiement Docker) : page Admin → Mise à jour — configurer une fois le dépôt Gitea + un jeton d'accès (droit lecture), puis « Vérifier » et « ⬆ Mettre à jour maintenant ». Watchtower tire la nouvelle image et recrée le conteneur : quelques secondes d'indisponibilité, les pages ouvertes se reconnectent et rechargent automatiquement.
En ligne de commande (toujours possible) :
docker compose pull && docker compose up -d
Publier une version (mainteneur)
./scripts/release.sh 0.2.0
Bump de version, commit + tag git, build de l'image et push vers
git.lanro.eu/roman/ohm_streaming (tags 0.2.0 et latest).
Démarrage rapide (développement)
uv sync
# ffmpeg requis pour les flux HLS (binaire statique dans ~/.local/bin, ou apt install ffmpeg)
uv run uvicorn app.main:app --host 0.0.0.0 --port 8777
Serveur persistant en dev : préférer Docker (voir plus haut) ; sinon
tmux new-session -d -s ohm 'uv run uvicorn app.main:app --host 0.0.0.0 --port 8777'.
Puis ouvrir http://localhost:8777 — le premier compte créé est administrateur.
Configuration
Variables d'environnement (préfixe OHM_, voir .env.example) :
| Variable | Défaut | Rôle |
|---|---|---|
OHM_SECRET_KEY |
change-me-in-production |
À changer — signature des tokens |
OHM_DOWNLOAD_DIR |
./downloads |
Dossier des fichiers téléchargés |
OHM_DATABASE_PATH |
./data/ohm.db |
Base SQLite |
OHM_MAX_PARALLEL_DOWNLOADS |
3 |
Téléchargements simultanés |
OHM_WATCHTOWER_URL |
(vide) | URL Watchtower pour la mise à jour (réglé par docker-compose) |
OHM_WATCHTOWER_TOKEN |
(vide) | Jeton partagé Watchtower (réglé par docker-compose) |
OHM_VERSION |
(pyproject) | Version affichée — cuite dans l'image Docker au build |
Fonctionnalités
- Recherche unifiée sur plusieurs sources (Vostfree, French-Manga, VoirAnime pour les animes ; French-Stream pour les séries et films VF/VOSTFR) — chaque source est un module interchangeable activable/désactivable à chaud (page Admin), dont l'URL est modifiable à la volée (utile si un site change de domaine).
- Extraction en 2 niveaux : page d'épisode → lecteurs embarqués → URL directe (Sibnet, SendVid, VidMoly, Uqload, Vidzy, Luluvdo ; VoirAnime résout via son endpoint « prepare » : MP4 direct ou HLS relayé par le proxy du site).
- Préférence de contenus par compte : sélecteur topbar ⛨ Animés / 📺 Séries / ✨ Les deux — la recherche et les nouveautés filtrent par type de média, et les sources hors périmètre ne sont même pas interrogées.
- Proxy vidéo intégré (
/api/proxy) : contourne les protections (tokens liés à l'IP, Referer/UA obligatoires), réécrit les playlists HLS. - Téléchargements : file parallèle, pause/reprise (HTTP Range), retry, anti-doublons, progression en temps réel (SSE), persistance au redémarrage.
- Bibliothèque locale : streaming avec range requests, reprise de lecture, navigation épisode suivant/précédent.
- Comptes : JWT court + refresh token (rotation), rôles admin/utilisateur, administration des comptes.
- Découverte (
/discover) : 🎭 exploration par genre (animés via Kitsu, séries/films via French-Stream — état dans l'URL, partageable), 🆕 nouveautés en rails séparés (animés triés par date de sortie via Kitsu ; séries & films de French-Stream), 🔥 incontournables animés (top popularité Kitsu) et ✨ recommandations par genres déduites des téléchargements et favoris, titres déjà possédés exclus (cache mémoire). Sans Sonarr, les genres des séries/films téléchargés sont lus sur leur fiche source ; sans aucun historique, une carte d'amorçage invite à télécharger un premier titre.
Intégration Sonarr / Prowlarr (*arr)
OhmStreaming expose une API Torznab (indexeur) et une API compatible qBittorrent (client de téléchargement) : Sonarr peut lui déléguer toute la chaîne — recherche, téléchargement, puis import et renommage automatiques dans la bibliothèque Sonarr.
1. OhmStreaming comme indexeur
Dans Admin → Intégrations Sonarr / Prowlarr, copier :
| Champ | Valeur |
|---|---|
| URL | http://<hote-ohm>:8777/torznab/api |
| Clé API | générée automatiquement (bouton Régénérer pour la changer) |
- Prowlarr : Indexers → Add Indexer → Generic Torznab → coller URL + clé, puis synchroniser vers Sonarr.
- Sonarr (direct) : Settings → Indexers → Add → Torznab → coller URL + clé. Catégories : TV (5000) / Anime (5070).
Endpoints : t=caps, t=tvsearch (q, season, ep), t=search — auth par
?apikey= ou en-tête X-Api-Key.
2. OhmStreaming comme client de téléchargement (recommandé)
Dans Sonarr : Settings → Download Clients → Add → qBittorrent :
| Champ | Valeur |
|---|---|
| Host | http://<hote-ohm>:8777 |
| Username | ohm |
| Password | la clé API Torznab (Admin → Intégrations) |
Le flux complet devient : Sonarr grab → Ohm télécharge (progression visible dans la file Sonarr) → Sonarr importe, renomme et range l'épisode dans sa bibliothèque selon ses propres règles → le « torrent » est retiré de la file Ohm (fichier inclu si « Remove Completed » est coché).
Chemin d'accès : Ohm annonce les fichiers sous /downloads/<Animé>/…
(chemin conteneur). Si Sonarr tourne dans Docker sans ce montage, ajouter un
Remote Path Mapping : hôte = <hote-ohm>, distant = /downloads, local =
le dossier hôte monté (ex. /plex_videos/ohm).
Variante minimale sans import : client « Torrent Blackhole » — Sonarr pose le
.torrent de service et l'épisode reste dans la bibliothèque OhmStreaming
seulement (pas d'import/renommage Sonarr).
2. « Pour toi » personnalisé par Sonarr
Toujours dans Admin → Intégrations, renseigner l'URL Sonarr
(http://sonarr:8989) et sa clé API (Settings → General → API Key), puis
« Enregistrer » et « Tester ». Les genres des séries téléchargées/grabées sur
Sonarr alimentent la section ✨ Pour toi (et ce qui y est possédé n'est pas
re-recommandé). Sonarr absent ou KO → dégradation gracieuse, rien ne casse.
Architecture
app/
├── main.py # FastAPI + lifespan (DB, download manager)
├── config.py # pydantic-settings (OHM_*)
├── db.py # SQLite (aiosqlite) — source de vérité unique
├── routers/ # auth, search, discover, downloads, library, admin, torznab, pages
├── scrapers/
│ ├── base.py # contrats SourceScraper/HosterExtractor + registres
│ ├── configs/ # sélecteurs YAML externalisés (réparer sans coder)
│ ├── sources/ # vostfree, french_manga, voiranime, french_stream
├── services/ # downloads, kitsu, discover, sonarr, torznab, settings
└── templates/ + static/ # UI htmx + Alpine.js, thème sombre
Ajouter une source : créer app/scrapers/sources/ma_source.py qui implémente
SourceScraper, la décorer @register_source — c'est tout (registre auto-découvert).
Tests
uv run pytest # 132 tests
uv run ruff check . # lint