From 52504d4e1a6e3d6d1ee3127e77fb5271e3349f85 Mon Sep 17 00:00:00 2001 From: Michael SCHAL Date: Mon, 19 Oct 2026 14:15:19 +0200 Subject: [PATCH] =?UTF-8?q?Multi-IPTV=20:=20le=20quota=20du=20navigateur?= =?UTF-8?q?=20ne=20doit=20plus=20=C3=A9craser=20le=20choix=20d'IPTV?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Console du navigateur, à deux playlists : QuotaExceededError: Failed to execute 'setItem' on 'Storage': Setting the value of 'xtream_cache__live_channels' exceeded the quota. Les catalogues mis en cache (chaînes, films, séries), plusieurs Mo par IPTV, saturent le stockage. L'erreur était avalée, mais le stockage restait plein : toute écriture suivante échouait, dont celle de localStorage['selected_playlist']. L'entrée gardait l'IPTV précédente, AuthedHttp envoyait un X-Playlist-Id périmé, le serveur résolvait la même playlist pour les deux, et Auto NBA n'avait qu'une règle commune — désactivée d'un côté, désactivée de l'autre. - persistSelectedPlaylist purge les catalogues et réessaye avant de renoncer ; elle ne lève plus jamais, sans quoi le clic de sélection n'aurait plus posé l'état du tout. - _saveToLocalCache purge les catalogues des autres IPTV puis réessaye : un catalogue se recharge depuis le serveur, le choix d'IPTV ne se devine pas. Non vérifié localement : le SDK Flutter de cette machine (3.10.3) est antérieur au ^3.13.0 exigé par le projet. Co-Authored-By: Claude Opus 5 --- .../iptv/providers/xtream_provider.dart | 44 ++++++++++++++++--- .../iptv/services/xtream_service.dart | 25 +++++++++-- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/lib/features/iptv/providers/xtream_provider.dart b/lib/features/iptv/providers/xtream_provider.dart index db73f02..1616345 100644 --- a/lib/features/iptv/providers/xtream_provider.dart +++ b/lib/features/iptv/providers/xtream_provider.dart @@ -57,14 +57,48 @@ final selectedPlaylistProvider = StateProvider((ref) { return null; }); +/// Préfixe des caches de catalogue (chaînes, films, séries) par IPTV. +const xtreamCachePrefix = 'xtream_cache_'; + +/// Vide les caches de catalogue pour rendre de la place. +/// +/// Ces caches pèsent plusieurs mégaoctets par IPTV et saturent le quota du +/// navigateur ; ils se reconstruisent au prochain chargement. +void clearXtreamCaches() { + final keys = html.window.localStorage.keys + .where((k) => k.startsWith(xtreamCachePrefix)) + .toList(); + for (final key in keys) { + html.window.localStorage.remove(key); + } +} + /// Écrit l'IPTV courante là où `AuthedHttp` la relit pour poser l'en-tête /// `X-Playlist-Id`. +/// +/// Quota saturé, `setItem` lève : les caches de catalogue remplissent le +/// stockage et faisaient échouer cette écriture-ci, minuscule mais décisive. +/// L'entrée restait sur l'IPTV précédente, l'en-tête désignait la mauvaise +/// playlist, et les deux IPTV retombaient sur la même. Le catalogue cède donc +/// la place, et un échec résiduel ne doit jamais empêcher le changement +/// d'IPTV. void persistSelectedPlaylist(PlaylistConfig? playlist) { - if (playlist != null) { - html.window.localStorage['selected_playlist'] = - jsonEncode(playlist.toJson()); - } else { - html.window.localStorage.remove('selected_playlist'); + if (playlist == null) { + try { + html.window.localStorage.remove('selected_playlist'); + } catch (_) {} + return; + } + final value = jsonEncode(playlist.toJson()); + try { + html.window.localStorage['selected_playlist'] = value; + } catch (_) { + try { + clearXtreamCaches(); + html.window.localStorage['selected_playlist'] = value; + } catch (e) { + debugPrint('Impossible de persister l\'IPTV choisie: $e'); + } } } diff --git a/lib/features/iptv/services/xtream_service.dart b/lib/features/iptv/services/xtream_service.dart index 174c274..5aa4a9d 100644 --- a/lib/features/iptv/services/xtream_service.dart +++ b/lib/features/iptv/services/xtream_service.dart @@ -333,12 +333,31 @@ class XtreamService { } } + /// Met le catalogue en cache, en cédant la place plutôt qu'en saturant. + /// + /// Un catalogue pèse plusieurs mégaoctets et il y en a un par IPTV : à deux + /// playlists, le quota du navigateur était atteint. L'erreur était avalée + /// ici, mais le stockage restait plein — et toute autre écriture échouait + /// à son tour, à commencer par celle de l'IPTV sélectionnée, bien plus + /// importante que ce cache. On purge donc les catalogues des autres IPTV + /// avant de réessayer, puis on renonce : ils se rechargent depuis le + /// serveur, le choix d'IPTV, lui, ne se devine pas. void _saveToLocalCache(String key, Map data) { if (!kIsWeb) return; + final storageKey = 'xtream_cache_${_currentPlaylist?.id}_$key'; + final jsonStr = jsonEncode(data); try { - final jsonStr = jsonEncode(data); - html.window.localStorage['xtream_cache_${_currentPlaylist?.id}_$key'] = - jsonStr; + html.window.localStorage[storageKey] = jsonStr; + return; + } catch (_) {} + try { + final stale = html.window.localStorage.keys + .where((k) => k.startsWith('xtream_cache_') && k != storageKey) + .toList(); + for (final k in stale) { + html.window.localStorage.remove(k); + } + html.window.localStorage[storageKey] = jsonStr; } catch (e) { debugPrint('Error saving to local cache ($key): $e'); }