Fuseaux horaires :
- POST /api/recordings rejette en 400 les dates sans fuseau et normalise
tout en UTC à l'écriture (l'interprétation des dates naïves dans le TZ
du conteneur décalait les enregistrements de 1-2 h)
- Helper frontend unique postRecording() : les 2 points de création
(modal, guide EPG) envoient la même convention UTC
Contrôle d'accès :
- stop/delete/logs d'un enregistrement et delete d'un season pass
vérifient la propriété (userId ou admin), comme playlists_handler
- Suppression des replis 'dev_user_id' et 'admin' (401 sans session)
SQLite :
- PRAGMA foreign_keys/WAL/busy_timeout (les ON DELETE CASCADE déclarés
ne s'appliquaient pas : sessions et playlists orphelines)
- Migrations de schéma versionnées (schema_version) + index user_id,
start_time, season_passes(user_id)
Gestion disque :
- Refus explicite de capture sous MIN_FREE_DISK_MB (défaut 500 Mo)
- Rotation par quota d'octets (RECORDINGS_QUOTA_GB, opt-in) qui ne touche
jamais un enregistrement actif et supprime fichiers + ligne ensemble ;
l'ancienne rotation « 50 fichiers » pouvait effacer une capture en cours
- DELETE /api/recordings/<id> supprime aussi .mkv/.log/parties (SafePath)
Scheduler :
- Arrêt gracieux orchestré par server.dart : clôture des enregistrements
(fusion des parties, statut) avant killAll des sessions de streaming ;
l'ancien handler SIGTERM de FfmpegSessionManager faisait exit(0) direct
- Noms de fichiers uniques par fragment d'id (deux enregistrements du
même programme s'écrasaient mutuellement avec -y)
- Requête filtrée scheduled/recording au lieu de toute la table / 10 s
- Statut cancelled pour un scheduled arrêté (completed sans fichier
cassait la lecture)
Season passes :
- Playlist du propriétaire du pass résolue à chaque scan (l'injection
figée du 1er utilisateur rendait les passes muets après ajout de
playlist, et mélangeait les credentials en multi-utilisateurs)
- Correspondance exacte par défaut (match_mode, migration en 'contains'
pour l'existant), plafond de créations par scan, réalignement des
horaires déplacés dans l'EPG, déduplication tolérante ±2 min
- Redaction des erreurs de scan (ClientException contient l'URL amont)
API de suivi (polling conservé) :
- GET /api/recordings enrichi : progress_pct, file_size_bytes,
retry_count, is_active ; barre de progression + taille dans la liste
Validé : dart analyze (0 issue) et dart test (48/48) sur bin/.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015oEu9QayWsw7hCKhenxgVa
- Nouveau bus de notification (recordingsRefreshBus) : la liste se recharge
immédiatement dès qu'un enregistrement est créé, planifié ou arrêté depuis
n'importe où dans l'app (guide EPG, modal, widget rapide)
- Polling en arrière-plan : 5 s quand un enregistrement est en cours ou
planifié, 20 s sinon, pour suivre les changements de statut sans clic
- Rafraîchissement silencieux (pas de spinner ni de vidage de liste) pour
éviter le clignotement ; les erreurs transitoires ne remplacent pas la liste
- Indicateur « Suivi auto » avec l'heure de dernière actualisation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015oEu9QayWsw7hCKhenxgVa
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>
- Implemented DownloadService for managing download tasks, including start, pause, resume, and cancel functionalities.
- Created SubtitleService for handling subtitle tracks, parsing SRT and WebVTT formats, and downloading subtitles.
- Added ContinueWatchingWidget to display user's watch history with progress indicators.
- Developed QualitySelectorWidget for selecting video quality during playback, including auto quality adjustment.
- Introduced TrendingWidget and RecentlyAddedWidget to showcase trending and recently added content.