From 5ec3169bd0bc5f6479ad03ddad09715d42392445 Mon Sep 17 00:00:00 2001 From: Michael SCHAL Date: Mon, 8 Dec 2025 15:45:46 +0100 Subject: [PATCH] feat: implement web-based IPTV player using HLS.js and mpegts.js with parent frame communication --- lib/features/iptv/widgets/movies_tab.dart | 13 +++++++++++-- lib/features/iptv/widgets/series_tab.dart | 13 +++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/features/iptv/widgets/movies_tab.dart b/lib/features/iptv/widgets/movies_tab.dart index 3eefb66..c9c9664 100644 --- a/lib/features/iptv/widgets/movies_tab.dart +++ b/lib/features/iptv/widgets/movies_tab.dart @@ -157,6 +157,15 @@ class _MoviesTabState extends ConsumerState { ); } + String? _getProxiedIconUrl(String? originalUrl) { + if (originalUrl == null || originalUrl.isEmpty) return null; + // Proxy toutes les URLs externes (http et https) via notre serveur + if (originalUrl.startsWith('http://') || originalUrl.startsWith('https://')) { + return '/api/xtream/$originalUrl'; + } + return originalUrl; + } + @override Widget build(BuildContext context) { final settings = ref.watch(iptvSettingsProvider); @@ -175,7 +184,7 @@ class _MoviesTabState extends ConsumerState { final heroItems = displayMovies.take(5).map((m) => HeroItem( id: m.streamId, title: m.name, - imageUrl: m.streamIcon ?? '', + imageUrl: _getProxiedIconUrl(m.streamIcon) ?? '', subtitle: m.rating != null ? '${_formatRating(m.rating)} ★' : null, onMoreInfo: () { _playMovie(m); @@ -291,7 +300,7 @@ class _MoviesTabState extends ConsumerState { return MediaCard( title: movie.name, - imageUrl: movie.streamIcon, + imageUrl: _getProxiedIconUrl(movie.streamIcon), subtitle: movie.rating != null ? '${_formatRating(movie.rating)} ★' : null, rating: _formatRating(movie.rating), diff --git a/lib/features/iptv/widgets/series_tab.dart b/lib/features/iptv/widgets/series_tab.dart index e91beab..b86b8f2 100644 --- a/lib/features/iptv/widgets/series_tab.dart +++ b/lib/features/iptv/widgets/series_tab.dart @@ -152,6 +152,15 @@ class _SeriesTabState extends ConsumerState { ); } + String? _getProxiedIconUrl(String? originalUrl) { + if (originalUrl == null || originalUrl.isEmpty) return null; + // Proxy toutes les URLs externes (http et https) via notre serveur + if (originalUrl.startsWith('http://') || originalUrl.startsWith('https://')) { + return '/api/xtream/$originalUrl'; + } + return originalUrl; + } + @override Widget build(BuildContext context) { final settings = ref.watch(iptvSettingsProvider); @@ -173,7 +182,7 @@ class _SeriesTabState extends ConsumerState { final heroItems = displaySeries.take(5).map((s) => HeroItem( id: s.seriesId.toString(), // ID logic might differ for Series title: s.name, - imageUrl: s.cover ?? '', + imageUrl: _getProxiedIconUrl(s.cover) ?? '', subtitle: s.rating != null ? '${_formatRating(s.rating)} ★' : null, onMoreInfo: () => _openSeries(s), )).toList(); @@ -281,7 +290,7 @@ class _SeriesTabState extends ConsumerState { final serie = displaySeries[index]; return MediaCard( title: serie.name, - imageUrl: serie.cover, + imageUrl: _getProxiedIconUrl(serie.cover), subtitle: serie.rating != null ? '${_formatRating(serie.rating)} ★' : null, rating: _formatRating(serie.rating),