diff --git a/lib/features/connections/widget/stremio/stremio_season_selector.dart b/lib/features/connections/widget/stremio/stremio_season_selector.dart index 957e130..49a0e57 100644 --- a/lib/features/connections/widget/stremio/stremio_season_selector.dart +++ b/lib/features/connections/widget/stremio/stremio_season_selector.dart @@ -41,6 +41,7 @@ class _StremioItemSeasonSelectorState extends State late Meta meta = widget.meta; final Map _progress = {}; + Map> watchedEpisodesBySeason = {}; @override void initState() { @@ -64,6 +65,7 @@ class _StremioItemSeasonSelectorState extends State }); getWatchHistory(); + getWatchedHistory(); } int getSelectedSeason() { @@ -74,6 +76,52 @@ class _StremioItemSeasonSelectorState extends State widget.season ?? 0; } + getWatchedHistory() async { + final traktService = TraktService.instance; + try { + + final result = await traktService!.getWatchedShowsWithEpisodes(widget.meta); + watchedEpisodesBySeason.clear(); + print("Trakt Result: $result"); // Print the raw Trakt result + + for (final show in result) { + print("Show Title: ${show.title}"); // Print the show title + if (show.episodes != null) { + print("Episodes for ${show.title}:"); + for (final episode in show.episodes!) { + print(" - Season: ${episode.season}, Episode: ${episode.episode}, Watched At: ${episode.watchedAt}"); + if (!watchedEpisodesBySeason.containsKey(episode.season)) { + watchedEpisodesBySeason[episode.season] = {}; + } + watchedEpisodesBySeason[episode.season]!.add(episode.episode); + } + } else { + print("No episodes found for ${show.title}"); + } + } + + print("Watched Episodes By Season: $watchedEpisodesBySeason"); // Print the final map + setState(() {}); + return; + + } catch (e, stack) { + print("Error fetching Trakt data: $e"); + print("Stack Trace: $stack"); + } + } + bool isEpisodeWatched(int season, int episode) { + return watchedEpisodesBySeason.containsKey(season) && + watchedEpisodesBySeason[season]!.contains(episode); + } + bool isSeasonWatched(int season) { + if (!watchedEpisodesBySeason.containsKey(season)) { + return false; // No episodes watched in this season + } + if (seasonMap.containsKey(season)) { + return watchedEpisodesBySeason[season]!.length == seasonMap[season]!.length; + } + return false; + } getWatchHistory() async { final traktService = TraktService.instance; @@ -245,9 +293,14 @@ class _StremioItemSeasonSelectorState extends State splashBorderRadius: BorderRadius.circular(8), padding: const EdgeInsets.all(4), tabs: seasons.map((season) { + final isWatched = isSeasonWatched(season); return Tab( - text: season == 0 ? "Specials" : 'Season $season', - height: 40, + child: Text( + season == 0 ? "Specials" : 'Season $season', + style: TextStyle( + color: isWatched? Colors.green : Colors.white, + ), + ), ); }).toList(), ), @@ -354,7 +407,7 @@ class _StremioItemSeasonSelectorState extends State ], ), ), - if (progress > .9) + if (isEpisodeWatched(currentSeason, episode.episode!)) Positioned( bottom: 0, right: 0, diff --git a/lib/features/trakt/service/trakt.service.dart b/lib/features/trakt/service/trakt.service.dart index 65049d5..b3db008 100644 --- a/lib/features/trakt/service/trakt.service.dart +++ b/lib/features/trakt/service/trakt.service.dart @@ -15,6 +15,7 @@ import '../../../engine/engine.dart'; import '../../connections/service/base_connection_service.dart'; import '../../connections/types/stremio/stremio_base.types.dart'; import '../../settings/types/connection.dart'; +import '../types/common.dart'; class TraktService { static final Logger _logger = Logger('TraktService'); @@ -1033,4 +1034,81 @@ class TraktService { return meta; } + Future> getWatchedShowsWithEpisodes(Meta meta) async { + if (!isEnabled()) { + _logger.info('Trakt integration is not enabled'); + return []; + } + if (meta.type == "series" ) { + final watchedShows = await getWatchedShows(); + for (final show in watchedShows) { + if(show.ids.imdb==meta.imdbId) { + // await Future.delayed(const Duration(seconds: 5)); + show.episodes = await _getWatchedEpisodes(show.ids.trakt); + } + } + return watchedShows; + } + return []; + } + Future> getWatchedShows() async { + if (!isEnabled()) { + _logger.info('Trakt integration is not enabled'); + return []; + } + try { + final body = await _makeRequest( + "$_baseUrl/sync/watched/shows/", + bypassCache: true, + ); + final List result = []; + for (final item in body) { + try { + result.add( + TraktShowWatched( + title: item["show"]["title"], + seasons: item["seasons"], + ids: TraktIds.fromJson(item["show"]["ids"]), + lastWatchedAt: item["last_watched_at"] != null ? DateTime.parse(item["last_watched_at"]) : null, + plays: item["plays"], + ), + ); + + } catch (e, stack) { + _logger.warning('Error parsing watched show: $e\n$stack item: $item'); + } + } + return result; + } catch (e, stack) { + _logger.severe('Error fetching watched shows: $e\n$stack'); + return []; + } + } + Future> _getWatchedEpisodes(int? traktId) async { + if (traktId == null) return []; + int page = 1; + const int limit = 1000; + try { + final body = await _makeRequest( + "$_baseUrl/sync/history/shows/$traktId?page=$page&limit=$limit", + bypassCache: true, + ); + final List episodes = []; + for (final item in body) { + if (item['episode'] != null) { + episodes.add( + TraktEpisodeWatched( + season: item['episode']['season'], + episode: item['episode']['number'], + watchedAt: DateTime.parse(item['watched_at']), + ), + ); + } + } + return episodes; + } catch (e, stack) { + _logger.severe('Error fetching watched episodes: $e\n$stack'); + return []; + } + } } diff --git a/lib/features/trakt/types/common.dart b/lib/features/trakt/types/common.dart index 492fffd..06d30e7 100644 --- a/lib/features/trakt/types/common.dart +++ b/lib/features/trakt/types/common.dart @@ -13,3 +13,54 @@ class TraktProgress { this.traktId, }); } + +class TraktShowWatched { + final String title; + final List seasons; + final TraktIds ids; + final DateTime? lastWatchedAt; + final int plays; + List? episodes; // Add episodes list + + TraktShowWatched({ + required this.title, + required this.seasons, + required this.ids, + this.lastWatchedAt, + required this.plays, + this.episodes, + }); +} + +class TraktIds { + final int? trakt; + final String? slug; + final String? imdb; + final int? tmdb; + + TraktIds({ + this.trakt, + this.slug, + this.imdb, + this.tmdb, + }); + + factory TraktIds.fromJson(Map json) => TraktIds( + trakt: json['trakt'], + slug: json['slug'], + imdb: json['imdb'], + tmdb: json['tmdb'], + ); +} + +class TraktEpisodeWatched { + final int season; + final int episode; + final DateTime watchedAt; + + TraktEpisodeWatched({ + required this.season, + required this.episode, + required this.watchedAt, + }); +} \ No newline at end of file