roman 853b4e0866 Compatibilité Sonarr : flux RSS Torznab, catégories qBittorrent, save_path, TLS auto-signé
- torznab : tvsearch sans q sert les nouveautés (RSS sync + test Sonarr)
  au lieu d'une erreur 400 — ajoute TorznabService.latest_releases()
- qbit : POST /torrents/createCategory + GET /torrents/categories stateful
  (Sonarr crée sa catégorie tv-sonarr puis la revérifie)
- qbit : /app/preferences expose save_path=/downloads (health Sonarr)
- sonarr : verify=False sur httpx — reverse proxy swizzin en certificat
  auto-signé (usage LAN)
2026-09-22 18:25:03 +00:00

⛩ 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 privé du Gitea — rien n'est publié publiquement.

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

Bibliothèque Plex / Sonarr existante

Ohm peut déposer ses épisodes directement dans ton serveur de média :

  1. 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 fait scripts/install.sh.
  2. 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.
  3. 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) — 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).
  • Proxy vidéo intégré (/api/proxy) : contourne les protections (tokens liés à l'IP, Referer/UA obligatoires), réécrit les playlists HLS.
  • Streaming HLS via hls.js ; téléchargement HLS via ffmpeg (remux mp4, progression temps réel).
  • Métadonnées enrichies via Kitsu (synopsis, genres, note, images) avec cache 72 h.
  • 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) : 🆕 nouveautés fusionnées de toutes les sources, triées par date de sortie réelle (enrichissement Kitsu, badge « en cours de diffusion »), 🔥 incontournables (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).

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
├── 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        # 86 tests
uv run ruff check .  # lint
S
Description
No description provided
Readme
7.4 MiB
Languages
Python 76.4%
HTML 14.5%
CSS 5.8%
Shell 2.1%
JavaScript 0.6%
Other 0.6%