# ⛩ 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) ```bash 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 ```bash # 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) : ```bash docker compose pull && docker compose up -d ``` ### Publier une version (mainteneur) ```bash ./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) ```bash 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** : la suite *arr le voit comme un indexeur de plus, et chaque grab Sonarr déclenche l'extraction + le téléchargement dans la file interne (les épisodes arrivent dans la bibliothèque OhmStreaming). ### 1. OhmStreaming comme indexeur Dans **Admin → Intégrations Sonarr / Prowlarr**, copier : | Champ | Valeur | |---|---| | URL | `http://: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). - **Client de téléchargement** : « Torrent Blackhole » — Sonarr enregistre le `.torrent` de service tandis qu'OhmStreaming télécharge réellement l'épisode (extraction embed → HLS/HTTP → mp4 dans `downloads/`). Endpoints : `t=caps`, `t=tvsearch` (q, season, ep), `t=search` — auth par `?apikey=` ou en-tête `X-Api-Key`. ### 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 ```bash uv run pytest # 83 tests uv run ruff check . # lint ```