Le serveur réclamait toujours <id>.mkv au panneau. Un film stocké en .mp4
était refusé (HTTP 551 constaté en prod). Le client transmet désormais
container_extension (?ext=), validé côté serveur ; mkv reste le défaut
pour un client qui ne l'envoie pas. Même approche que xtremobile, qui lit
ces films sans souci.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Son manquant sur certaines chaînes :
- Nouvelle route GET /api/live/<id>/turbo.ts pour le player web : vidéo
copiée (-c:v copy), audio TOUJOURS réencodé en AAC. mpegts.js ne démuxe
que l'AAC/MP3 : les chaînes en AC-3/E-AC-3/MP2 passaient par le proxy
brut → image sans son, et le fallback HLS côté client ne couvrait pas
les codecs démuxés mais non décodables par le navigateur (MP2)
- getLiveStreamUrlTs pointe sur la route turbo ; le proxy brut
/api/live/<id>.ts reste inchangé pour le scheduler d'enregistrement
- FFmpeg turbo tué dès que le client zappe (onCancel) ; stderr redacté
- Le fallback client (_hlsEquivalent) reconnaît le nouveau format d'URL
et reste en filet de sécurité
Temps de chargement :
- Players vendorisés mis à jour : hls.js 1.6.7 → 1.7.1,
mpegts.js 1.7.3 → 1.8.2
- Live HLS et turbo : -fflags nobuffer + probesize/analyzeduration 1 Mo
(sans borne, FFmpeg pouvait sonder plusieurs secondes avant le premier
segment)
- VOD : probesize 10 Mo → 5 Mo, analyzeduration 5 s → 2 s
- Live 'high' : preset medium → veryfast (zerolatency déjà actif) ;
lecture d'enregistrement : medium/crf18 → veryfast/crf20 (medium ne
tenait pas le temps réel en 1080p sur CPU modeste)
- waitForPlaylist : polling 500 ms → 100 ms
- Suppression du cache-buster &v=timestamp qui re-téléchargeait
player.html à chaque zap ; les .html sont servis en no-cache côté
serveur pour garder la fraîcheur après déploiement
- mpegts.js : liveBufferLatencyChasing activé en profil « fast » — les
micro-coupures ne font plus dériver la lecture derrière le direct
Validé : dart analyze (0 issue) + dart test (48/48) sur bin/, syntaxe JS
vérifiée.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015oEu9QayWsw7hCKhenxgVa
Les journaux du serveur montrent la grille Live TV se faire couper en 429 :
"Rate limit exceeded", une trentaine de requêtes refusées d'affilée après
quelques écrans de défilement.
Deux causes cumulées. D'une part le passage du guide de Dio vers AuthedHttp a
fait perdre le cache de réponses qui existait auparavant : chaque
reconstruction de tuile repartait en requête. Un cache mémoire de dix minutes
le rétablit — le backend garde déjà ces réponses trente minutes, il n'y a
aucune raison d'aller les rechercher.
D'autre part le plafond de deux cents requêtes par minute et par adresse était
trop bas pour l'usage réel : une grille demande un logo et un guide par tuile,
et tous les clients partagent l'adresse du reverse proxy. Il passe à six
cents.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le guide du fournisseur est figé sur beaucoup de revendeurs : sur le compte de
test, get_simple_data_table répond correctement mais le dernier programme
français date de deux jours, et le xmltv.php du panneau ne couvre aucune chaîne
française. Aucun correctif côté appel Xtream ne pouvait donc remplir la grille.
Nouveau service XmltvEpgService : téléchargement de dumps XMLTV publics,
décompression gzip détectée sur le nombre magique, parsing en flux via
XmlEventReader — un dump national fait 46 Mo décompressés, en charger l'arbre
DOM coûterait plusieurs centaines de mégaoctets dans le conteneur. Mesuré à
environ 1 s pour 973 chaînes. Index rafraîchi toutes les 6 h, programmes
terminés depuis plus de 6 h écartés à l'indexation.
L'appel sortant reste un dernier recours. L'ordre est inchangé —
get_simple_data_table, puis get_short_epg — et le dump n'est consulté que si
le panneau ne rend aucun programme couvrant l'instant présent : compter les
entrées ne suffisait pas, un guide périmé en renvoie des centaines. La source
se configure par EPG_XMLTV_URLS ; vider la variable supprime tout appel
sortant. La réponse porte un en-tête X-Epg-Source pour savoir qui a répondu.
Les identifiants sont rapprochés après normalisation : le dump écrit
France.2.fr là où le panneau annonce France2.fr. Repli sur le nom affiché de
la chaîne, et table stream_id vers identifiant EPG mise en cache 6 h.
Le client passe désormais par /api/epg au lieu d'appeler player_api.php en
direct. Il dupliquait le choix de l'action, la conversion des fuseaux et le
décodage base64 ; le backend le fait une fois, met en cache pour tous les
utilisateurs, et sait basculer sur le repli — bascule impossible depuis le
navigateur.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
EPG — les trois chemins (backend /api/epg, XtreamService.getShortEpg et
getShortEPG) n'utilisaient que get_epg et get_short_epg. Beaucoup de
panneaux Xtream ne connaissent pas get_epg : ils répondent 200 avec le
bloc d'authentification, sans epg_listings, ce qui produisait un guide
vide indiscernable d'une chaîne sans programme. get_short_epg y renvoie
epg_listings vide en permanence.
- backend : get_simple_data_table en premier, get_short_epg en repli
- client : bascule automatique et mémorisée vers le tableau complet dès
qu'un panneau est muet sur l'action légère, pour ne pas doubler les
requêtes sur chaque tuile de grille
- dates dérivées des *_timestamp epoch et émises en ISO-8601 UTC : les
champs texte sont dans le fuseau du panneau, sans indicateur de zone,
et étaient relus comme de l'heure locale — le guide était décalé et
les enregistrements planifiés depuis le guide l'étaient aussi
- cache backend : la clé incluait seulement le channelId, deux playlists
partageant un stream_id se servaient mutuellement leur guide
UI — les deux halos d'ambiance du dashboard étaient restés de l'ancien
thème : primary (#FFB68C) à 40 % posé sur le coin haut-gauche, donc pile
derrière la sidebar, et info (#A3B8C4, bleu-gris) à 35 % dans une palette
entièrement chaude. Ramenés à des braises ember à 8 % / 6 %.
- fond via AppColors.backgroundGradient
- onglet actif rempli en primaryContainer (surface) et non primary
(teinte claire réservée au texte/icônes)
- sidebar en niveau flottant : en niveau 1 son fond #181310 se confondait
avec le haut du dégradé #1A1310
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
getShortEpg ended in `catch (e) { return []; }`, so a 401, a timeout, a
rate-limited panel and a genuinely empty guide all rendered the same
"No Info" label. That made the current problem undiagnosable from the
UI. Failures are now logged with the HTTP status, the Dio error type and
the response shape.
Two concrete causes are handled while we are here:
- Some Xtream panels answer player_api.php with a textual Content-Type.
Dio then hands back a raw String, and `response.data['epg_listings']`
threw, landing in the silent catch. The body is now parsed explicitly
when it arrives as a String.
- The channel grid mounts one EPG provider per visible tile, firing
~32 concurrent requests at player_api.php. Many panels rate-limit well
below that and fail the whole batch. A 3-slot semaphore serialises
them in small groups.
This does not by itself prove why the guide is empty in production; it
makes the reason visible in the browser console.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Security:
- Replace unsalted SHA-256 password hashing with bcrypt (lazy rehash on login)
- Add authenticated /api/xtream-api gateway: Xtream credentials are injected
server-side and never sent to the frontend; /api/playlists no longer
returns passwords
- Redact credentials from all logs (login body, proxy/FFmpeg/scheduler URLs)
- Add auth to recordings, EPG, season-passes and streaming routes
(HttpOnly session cookie for hls.js; loopback bypass for local FFmpeg)
- Lock player postMessage to same-origin in both directions
- Vendor and pin hls.js 1.6.7 / mpegts.js 1.7.3 (drop CDN @latest)
- Fix rate limiter (client IP was never resolved), add login rate limit,
restrict CORS, add CSP Report-Only, block private-IP SSRF targets,
fix path traversal in recording log retrieval, chmod 777 -> 770
- Remove dead HiveService (seeded admin/admin into IndexedDB with SHA-256)
- Fix authMiddleware not populating 'user' context (getPlaylist ignored the
logged-in user; admin purge always returned 403)
Streaming:
- New FfmpegSessionManager: process registry, idle reaper (4 min live /
15 min VOD), orphan cleanup at startup, clean SIGTERM shutdown,
fast-fail with stderr instead of 30 s timeout
- Quality selection (source/high/medium/low) for live and VOD; source mode
streams with -c:v copy (zero transcoding); selector wired into the player
- Concurrent recordings (MAX_CONCURRENT_RECORDINGS, default 2); conflicts
retry on the next tick instead of silently failing
- Lower live latency (HLS window 20 -> 10 segments, liveSync 10 -> 3)
- Fix recording log lookup (.mp4 vs .mkv mismatch)
Design:
- Replace hardcoded colors with AppColors tokens (12 files)
- web/theme.css syncs HTML players with the Flutter palette
- DPAD/keyboard navigation (arrow-key focus, player shortcuts)
- Tooltips on player icon buttons, Semantics on content cards
- Remove 7 dead widgets broken since the Stitch merge
Quality:
- bin/test/: 21 unit tests (bcrypt, redaction, traversal, SSRF, recording
conflicts) plus a quality-selector widget test
- GitHub Actions CI (analyze + test + build web)
- Archive stale status docs into docs/archive/
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Implement parallel fetching for categories and streams in Live, VOD, and Series
- Add persistent local storage caching for instant UI population
- Optimize JSON parsing logic for large datasets
- Implement failover to local cache when network is unavailable
- Add playback lock to XtreamService to delay EPG during stream init
- Increase MPEG-TS stash buffer to 512KB for better stability
- Enable liveBufferLatencyChasing to prevent stream drift
- Tune HLS parameters for balanced speed and reliability
- Increased FFmpeg video quality to 8Mbps and audio to 192kbps.
- Added audio resync filters and better presets.
- Optimized HLS buffer settings for mobile players to reduce interruptions.
- Reduced API cache duration to 15m and added refresh support for faster content updates.