Files
ohm_streaming/README.md
T
Roman 9148b5fb6a Mise à jour automatique (Gitea + Watchtower) et conteneurisation Docker
- Détection de version via l'API Gitea, application via Watchtower
- Router système, UI admin (intégrations), bandeau de mise à jour
- Dockerfile multi-étapes, docker-compose, scripts/release.sh
- Version centralisée dans app/version.py (pyproject ou OHM_VERSION au build)
2026-09-22 11:58:03 +00:00

158 lines
6.8 KiB
Markdown

# ⛩ 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.
# 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. Port hôte modifiable via `OHM_PORT` dans `.env`.
### 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://<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).
- **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 # 61 tests
uv run ruff check . # lint
```