⛩ 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.
Déploiement (Docker) — recommandé
Le déploiement officiel passe par Docker Compose : l'image (ffmpeg inclus) est hébergée sur le registre du Gitea — un compte y est requis, même en lecture.
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 --skip-login.
À la main
# 1. Récupérer le projet puis se connecter au registre privé (compte Gitea avec accès lecture)
git clone https://git.lanro.eu/Roman/ohm_streaming.git && cd ohm_streaming
docker login git.lanro.eu
# 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 puis se connecter au registre (compte Gitea requis)
git clone https://git.lanro.eu/Roman/ohm_streaming.git && cd ohm_streaming
podman login git.lanro.eu
# 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