mark watched from Trakt

This commit is contained in:
Abinanthankv 2025-01-14 17:36:14 +05:30
parent f129eb7360
commit 6f044446f9
3 changed files with 185 additions and 3 deletions

View file

@ -41,6 +41,7 @@ class _StremioItemSeasonSelectorState extends State<StremioItemSeasonSelector>
late Meta meta = widget.meta;
final Map<String, double> _progress = {};
Map<int, Set<int>> watchedEpisodesBySeason = {};
@override
void initState() {
@ -64,6 +65,7 @@ class _StremioItemSeasonSelectorState extends State<StremioItemSeasonSelector>
});
getWatchHistory();
getWatchedHistory();
}
int getSelectedSeason() {
@ -74,6 +76,52 @@ class _StremioItemSeasonSelectorState extends State<StremioItemSeasonSelector>
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<StremioItemSeasonSelector>
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<StremioItemSeasonSelector>
],
),
),
if (progress > .9)
if (isEpisodeWatched(currentSeason, episode.episode!))
Positioned(
bottom: 0,
right: 0,

View file

@ -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<List<TraktShowWatched>> 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<List<TraktShowWatched>> 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<TraktShowWatched> 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<List<TraktEpisodeWatched>> _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<TraktEpisodeWatched> 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 [];
}
}
}

View file

@ -13,3 +13,54 @@ class TraktProgress {
this.traktId,
});
}
class TraktShowWatched {
final String title;
final List<dynamic> seasons;
final TraktIds ids;
final DateTime? lastWatchedAt;
final int plays;
List<TraktEpisodeWatched>? 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<String, dynamic> 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,
});
}