Un match NBA a échoué après 30 refus du fournisseur en 13 min, alors
qu'il restait 3 h 20 de diffusion. Le plafond MAX_FFMPEG_ATTEMPTS
condamnait tout l'enregistrement sur un refus temporaire : on relance
désormais tant que la fenêtre est ouverte, au rythme de
ffmpeg_retry_delay (30 s au plus).
- direct_proxy journalise le code HTTP du panneau : FFmpeg n'affiche
que « 4XX », le code exact (ici 407) n'était visible nulle part.
- direct_proxy libère les connexions de lecture orphelines du compte
avant d'ouvrir le flux, comme turbo.ts et HLS. Un flux encore regardé
n'est jamais coupé.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le serveur ignorait l'IPTV choisie : direct, VOD, guide, enregistrements,
season passes et Auto NBA passaient tous par la playlist la plus récente
(ou celle du premier utilisateur pour la capture FFmpeg), et les
enregistrements s'affichaient sous toutes les playlists.
- get_playlist respecte ?playlist=<id> (prioritaire) puis l'en-tête
X-Playlist-Id, avec contrôle du propriétaire (admin : toutes).
- Sessions FFmpeg HLS/VOD séparées par IPTV (même stream_id possible) ;
le m3u8 propage ?playlist= aux segments, redirections et bascule
.ts → HLS du lecteur web aussi.
- tv_recordings, season_passes, auto_rules : colonne playlist_id
(migrations v4-v6) ; lignes existantes rattachées à la playlist la
plus récente de leur propriétaire ; URL de capture avec ?playlist= ;
listes filtrées par IPTV ; une règle NBA par IPTV.
- Proxy /api/xtream : cache d'allowlist par playlist, paramètre retiré
avant l'appel au panneau ; CORS autorise X-Playlist-Id.
- Client : AuthedHttp envoie X-Playlist-Id ; XtreamService ajoute
?playlist= aux flux, à l'EPG et aux appels xtream-api (cache distinct).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le serveur Dart (bin/) est remplacé par un serveur Rust (server/) :
tokio + axum, reqwest/rustls, SQLite embarqué via rusqlite. Même API,
mêmes routes et mêmes réponses : le front Flutter ne change pas.
La base de production est reprise telle quelle : schéma, migrations et
formats de dates (DateTime.toIso8601String de Dart) sont reproduits à
l'identique, les sessions et hachages existants restent valides.
Comportement conservé : cascade de routage, anti-SSRF, logs masqués,
rate limits, transcodage HLS/turbo.ts avec repli GPU, quotas fournisseur,
enregistrements (reprise, relances, fusion), season passes, EPG, logos de
repli, arrêt gracieux sur SIGTERM. Tests Dart portés (132 tests Rust) ;
la CI exécute fmt, test et clippy -D warnings, l'image Docker compile le
serveur dans un étage rust:1.98.1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>