Files
mkv2avi/README.md
T
Alexandre fd2e0689bf Initial commit: MKV → AVI web app (Docker + Keycloak OIDC)
- App FastAPI : recherche dans un dossier média, download original ou
  conversion en AVI Xvid (tone-mapping HDR→SDR, audio FR auto, MP3 stéréo)
- Auth Keycloak OIDC (Authlib) optionnelle
- 3 composes : app seule, stack local (keycloak.local), production (NPM)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 00:28:51 +02:00

175 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🎬 MKV → AVI
Petite application web (Docker) pour parcourir un dossier média, **télécharger** un
fichier d'origine ou le **convertir en AVI Xvid** lisible par les vieux lecteurs DivX/DVD.
La conversion reprend le pipeline qui a fait ses preuves :
- vidéo **Xvid** (`mpeg4 -vtag xvid`, qualité `qscale 4`) ;
- audio **MP3 stéréo** (downmix 5.1 → 2.0) ;
- sélection auto de la **piste française** en évitant l'audiodescription ;
- **tone-mapping HDR → SDR** propre via `zscale` (les sources 4K HDR10/DV/HLG
sont détectées automatiquement) ;
- redimensionnement au choix (720 px « max compatibilité », 1280 px, ou original).
> ️ Le décodage est **logiciel** : dans un conteneur, l'accélération matérielle
> (VideoToolbox sur Mac, QSV/NVENC) n'est pas disponible. Comptez plusieurs minutes
> à quelques dizaines de minutes par film selon le CPU.
## Démarrage rapide
```bash
# Dossier contenant vos films (monté en lecture seule)
export MEDIA_DIR=/chemin/vers/mes/films
# Où écrire les AVI convertis (optionnel, défaut ./output)
export OUTPUT_DIR=$PWD/output
docker compose up -d --build
```
Puis ouvrir **http://localhost:8080**.
- Rechercher un fichier dans le champ de recherche.
- **⬇ Télécharger** : récupère le fichier d'origine.
- **🎬 Convertir en AVI** : choisir définition + piste audio → suivre la progression →
**⬇ Télécharger l'AVI** une fois terminé.
Les fichiers convertis restent aussi dans le dossier `OUTPUT_DIR`.
## Authentification Keycloak (OIDC)
L'app peut exiger une connexion Keycloak (flow **Authorization Code**, session par
cookie). Elle est **désactivée tant que `OIDC_ISSUER` est vide** — pratique en dev local.
Une fois configurée, **tout utilisateur authentifié** du realm a accès ; login/logout
et nom de l'utilisateur sont gérés dans l'app.
### 1. Créer le client dans Keycloak
- **Clients → Create client** : type `OpenID Connect`, Client ID `mkv2avi`.
- **Client authentication : On** (client confidentiel) → un *secret* est généré
(onglet **Credentials**).
- **Valid redirect URIs** : `https://mkv2avi.mondomaine.fr/auth/callback`
- **Valid post logout redirect URIs** : `https://mkv2avi.mondomaine.fr/`
- **Web origins** : `+` (ou l'URL exacte).
### 2. Renseigner les variables
```bash
cp .env.example .env
# puis éditer .env :
# OIDC_ISSUER=https://keycloak.mondomaine.fr/realms/mon-realm
# OIDC_CLIENT_ID=mkv2avi
# OIDC_CLIENT_SECRET=...(onglet Credentials)
# SESSION_SECRET=$(openssl rand -hex 32)
# SESSION_HTTPS_ONLY=true # si servi en HTTPS via Nginx Proxy Manager
docker compose up -d --build
```
> Derrière **Nginx Proxy Manager** (TLS) : uvicorn tourne avec `--proxy-headers`, donc
> l'URL de callback est déduite en `https`. En cas de souci, forcez-la avec
> `OIDC_REDIRECT_URI`. Activez `SESSION_HTTPS_ONLY=true` pour des cookies `Secure`.
### Stack tout-en-un (Keycloak inclus)
Pour tester/déployer **Keycloak + PostgreSQL + l'app** d'un coup, un compose dédié
avec un realm pré-importé (client `mkv2avi` + utilisateur de test) est fourni :
```bash
# 1. Rendre Keycloak résolvable sous le même nom côté navigateur ET côté conteneur
echo "127.0.0.1 keycloak.local" | sudo tee -a /etc/hosts
# 2. (optionnel) dossier de films à convertir
export MEDIA_DIR=/Volumes/data/films
# 3. Démarrer le stack
docker compose -f docker-compose.keycloak.yml up -d --build
```
| Service | URL | Identifiants |
|---------|-----|--------------|
| App MKV → AVI | http://localhost:8090 | `alex` / `alex` |
| Console Keycloak | http://localhost:8080 | `admin` / `admin` |
Le realm `mkv2avi` (`keycloak/realm-mkv2avi.json`) contient déjà le client confidentiel
(`secret : mkv2avi-secret-change-me`) et un utilisateur. **Change les secrets/mots de
passe avant tout usage réel** (variables `OIDC_CLIENT_SECRET`, `SESSION_SECRET`,
`KC_ADMIN_PASSWORD`, `KC_DB_PASSWORD`, et le `secret` dans le realm JSON).
> **Pourquoi `keycloak.local` ?** L'URL de Keycloak (l'*issuer*) doit être **identique**
> depuis le navigateur et depuis le conteneur de l'app. L'alias réseau Docker
> `keycloak.local` + la ligne `/etc/hosts` garantissent cette cohérence. En production
> derrière Nginx Proxy Manager, on remplace tout ça par le vrai domaine
> (`KC_HOSTNAME` + `OIDC_ISSUER` = `https://auth.mondomaine.fr/realms/mkv2avi`).
## Production derrière Nginx Proxy Manager
Fichier `docker-compose.prod.yml` : Keycloak en **mode production** (`start`), TLS
terminé par NPM. Domaines : app = `https://mkv2avi.maisongrondin.fr`,
Keycloak = `https://auth.mkv2avi.maisongrondin.fr`.
### 1. Secrets
```bash
cp .env.prod.example .env.prod
# générer : openssl rand -hex 32 (pour OIDC_CLIENT_SECRET et SESSION_SECRET)
# OIDC_CLIENT_SECRET doit être identique au "secret" du client dans
# keycloak/realm-mkv2avi.json (ou régénéré ensuite dans la console Keycloak).
```
### 2. Démarrage
```bash
docker compose --env-file .env.prod -f docker-compose.prod.yml up -d --build
```
Les services publient sur l'hôte : Keycloak `:8080`, app `:8090`.
### 3. Deux Proxy Hosts dans NPM
| Domaine | Forward vers | Options |
|---------|--------------|---------|
| `auth.mkv2avi.maisongrondin.fr` | `http` `<IP_HOTE>` `8080` | SSL (Let's Encrypt) · Force SSL · Websockets |
| `mkv2avi.maisongrondin.fr` | `http` `<IP_HOTE>` `8090` | SSL · Force SSL · Websockets |
Pour l'app, ajoute cette **Advanced / Custom Nginx Configuration** (téléchargements de
gros fichiers sans coupure — même logique que ton fix Nextcloud) :
```nginx
proxy_buffering off;
proxy_request_buffering off;
client_max_body_size 0;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
```
### 4. Points de vigilance
- **DNS interne** : le conteneur `mkv2avi` doit résoudre `auth.mkv2avi.maisongrondin.fr`
(il valide les tokens via cette URL). Si ton réseau ne fait pas de *hairpin NAT*,
décommente le bloc `extra_hosts` du compose en pointant vers l'IP de NPM/hôte.
- **Keycloak** sert en HTTP interne (`KC_HTTP_ENABLED=true`) et fait confiance aux
en-têtes `X-Forwarded-*` de NPM (`KC_PROXY_HEADERS=xforwarded`) ; l'issuer reste
figé sur l'URL publique (`KC_HOSTNAME`).
- Change **tous** les mots de passe/secrets par défaut avant exposition.
## Déploiement sur TrueNAS SCALE
Utilisable comme *Custom App* (Docker) : montez le dataset des films sur `/media`
(en lecture seule) et un dataset de sortie sur `/output`, exposez le port `8000`.
## Variables d'environnement
| Variable | Défaut | Rôle |
|---------------|-----------|----------------------------------------------|
| `MEDIA_DIR` | `/media` | Dossier parcouru (monté en lecture seule) |
| `OUTPUT_DIR` | `/output` | Dossier des AVI convertis |
| `MAX_WORKERS` | `1` | Conversions simultanées (1 = en série) |
| `MAX_RESULTS` | `400` | Nb max de fichiers listés par recherche |
| `OIDC_ISSUER` | *(vide)* | URL du realm Keycloak (vide = auth off) |
| `OIDC_CLIENT_ID` | *(vide)* | Client ID Keycloak |
| `OIDC_CLIENT_SECRET` | *(vide)* | Secret du client confidentiel |
| `OIDC_REDIRECT_URI` | *(auto)* | Force l'URL de callback si besoin |
| `SESSION_SECRET` | *(à changer)* | Clé de signature des cookies de session |
| `SESSION_HTTPS_ONLY` | `false` | Cookies `Secure` (mettre `true` en HTTPS) |
## Développement local (sans Docker)
```bash
pip install -r requirements.txt
# ffmpeg avec le filtre zscale requis pour le HDR (sinon HDR non géré)
MEDIA_DIR=/chemin/films OUTPUT_DIR=./output \
uvicorn main:app --app-dir app --reload --port 8000
```