- 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>
🎬 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
# 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 IDmkv2avi. - 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
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 enhttps. En cas de souci, forcez-la avecOIDC_REDIRECT_URI. ActivezSESSION_HTTPS_ONLY=truepour des cookiesSecure.
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 :
# 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 Dockerkeycloak.local+ la ligne/etc/hostsgarantissent 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
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
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) :
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
mkv2avidoit résoudreauth.mkv2avi.maisongrondin.fr(il valide les tokens via cette URL). Si ton réseau ne fait pas de hairpin NAT, décommente le blocextra_hostsdu 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êtesX-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)
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