From 506ca4f95c2efbaf8f4a6c6cd452ccef43b36876 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sun, 4 Jan 2026 03:49:06 +0530 Subject: [PATCH 1/4] rework the trakt sync logic --- src/services/traktService.ts | 82 ++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/src/services/traktService.ts b/src/services/traktService.ts index eb94f8f..73f951f 100644 --- a/src/services/traktService.ts +++ b/src/services/traktService.ts @@ -1102,48 +1102,74 @@ export class TraktService { public async isMovieWatchedAccurate(imdbId: string): Promise { try { - const history = await this.client.get( - `/sync/history/movies/${imdbId}?limit=1` + const watched = await this.client.get( + '/sync/watched/movies' ); - - const history = response.data; - return Array.isArray(history) && history.length > 0; - } catch { + + const movies = watched.data; + + return movies.some( + (m: any) => m.movie?.ids?.imdb === imdbId + ); + } catch (err) { + logger.warn('[TraktService] Movie watched check failed', err); return false; } } public async isEpisodeWatchedAccurate( - showId: string, + showImdbId: string, season: number, episode: number ): Promise { try { - const history = await this.client.get( - `/sync/history/episodes/${showId}`, - { params: { limit: 20 } } + if (season === 0) return false; + const watchedShows = await this.apiRequest('/sync/watched/shows'); + + const show = watchedShows.find( + s => s.show?.ids?.imdb === showImdbId ); - - const history = response.data; - if (!Array.isArray(history)) return false; + if (!show) return false; - for (const entry of history) { - if ( - entry.episode?.season === season && - entry.episode?.number === episode - ) { - - if (entry.reset_at) { - const watchedAt = new Date(entry.watched_at).getTime(); - const resetAt = new Date(entry.reset_at).getTime(); - if (watchedAt < resetAt) return false; - } - return true; - } - } + const seasonData = show.seasons?.find( + (s: any) => s.number === season + ); + if (!seasonData) return false; + return seasonData.episodes?.some( + (e: any) => e.number === episode + ) ?? false; + } catch (err) { + logger.warn('[TraktService] Episode watched check failed', err); return false; - } catch { + } + } + + public async isSeasonCompletedAccurate( + showImdbId: string, + seasonNumber: number, + totalAiredEpisodes: number + ): Promise { + try { + if (seasonNumber === 0) return false; + if (!totalAiredEpisodes || totalAiredEpisodes <= 0) return false; + const watchedShows = await this.apiRequest('/sync/watched/shows'); + + const show = watchedShows.find( + s => s.show?.ids?.imdb === showImdbId + ); + if (!show) return false; + + const season = show.seasons?.find( + (s: any) => s.number === seasonNumber + ); + if (!season) return false; + + const watchedCount = season.episodes?.length ?? 0; + + return watchedCount >= totalAiredEpisodes; + } catch (err) { + logger.warn('[TraktService] Season completion check failed', err); return false; } } From d2556b6c36e21dd39260b4216ec9a80cbecd7621 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sun, 4 Jan 2026 04:46:13 +0530 Subject: [PATCH 2/4] rework --- src/services/traktService.ts | 116 +++++++++++++++++++++++++++-------- 1 file changed, 92 insertions(+), 24 deletions(-) diff --git a/src/services/traktService.ts b/src/services/traktService.ts index 73f951f..e267dba 100644 --- a/src/services/traktService.ts +++ b/src/services/traktService.ts @@ -1102,14 +1102,15 @@ export class TraktService { public async isMovieWatchedAccurate(imdbId: string): Promise { try { - const watched = await this.client.get( - '/sync/watched/movies' - ); + const imdb = imdbId.startsWith('tt') + ? imdbId + : `tt${imdbId}`; - const movies = watched.data; + const response = await this.client.get('/sync/watched/movies'); + const movies = Array.isArray(response.data) ? response.data : []; return movies.some( - (m: any) => m.movie?.ids?.imdb === imdbId + (m: any) => m.movie?.ids?.imdb === imdb ); } catch (err) { logger.warn('[TraktService] Movie watched check failed', err); @@ -1124,21 +1125,56 @@ export class TraktService { ): Promise { try { if (season === 0) return false; - const watchedShows = await this.apiRequest('/sync/watched/shows'); + + const imdb = showImdbId.startsWith('tt') + ? showImdbId + : `tt${showImdbId}`; + + const watchedShows = await this.apiRequest( + '/sync/watched/shows' + ); const show = watchedShows.find( - s => s.show?.ids?.imdb === showImdbId + s => s.show?.ids?.imdb === imdb ); - if (!show) return false; - const seasonData = show.seasons?.find( - (s: any) => s.number === season - ); - if (!seasonData) return false; + if (show) { + const seasonData = show.seasons?.find( + (s: any) => s.number === season + ); - return seasonData.episodes?.some( - (e: any) => e.number === episode - ) ?? false; + if ( + seasonData?.episodes?.some( + (e: any) => e.number === episode + ) + ) { + return true; + } + } + + let page = 1; + + while (true) { + const history = await this.apiRequest( + `/sync/history/shows/${imdb}?page=${page}&limit=100` + ); + + if (!history.length) break; + + if ( + history.some( + (h: any) => + h.episode?.season === season && + h.episode?.number === episode + ) + ) { + return true; + } + + page++; + } + + return false; } catch (err) { logger.warn('[TraktService] Episode watched check failed', err); return false; @@ -1153,21 +1189,53 @@ export class TraktService { try { if (seasonNumber === 0) return false; if (!totalAiredEpisodes || totalAiredEpisodes <= 0) return false; - const watchedShows = await this.apiRequest('/sync/watched/shows'); + + const imdb = showImdbId.startsWith('tt') + ? showImdbId + : `tt${showImdbId}`; + + const watchedEpisodes = new Set(); + + const watchedShows = await this.apiRequest( + '/sync/watched/shows' + ); const show = watchedShows.find( - s => s.show?.ids?.imdb === showImdbId + s => s.show?.ids?.imdb === imdb ); - if (!show) return false; - const season = show.seasons?.find( - (s: any) => s.number === seasonNumber - ); - if (!season) return false; + if (show) { + const season = show.seasons?.find( + (s: any) => s.number === seasonNumber + ); - const watchedCount = season.episodes?.length ?? 0; + season?.episodes?.forEach( + (e: any) => watchedEpisodes.add(e.number) + ); + } - return watchedCount >= totalAiredEpisodes; + let page = 1; + + while (true) { + const history = await this.apiRequest( + `/sync/history/shows/${imdb}?page=${page}&limit=10` + ); + + if (!history.length) break; + + history.forEach((h: any) => { + if ( + h.episode?.season === seasonNumber && + typeof h.episode?.number === 'number' + ) { + watchedEpisodes.add(h.episode.number); + } + }); + + page++; + } + + return watchedEpisodes.size >= totalAiredEpisodes; } catch (err) { logger.warn('[TraktService] Season completion check failed', err); return false; From 8a0bed7238593490cd6f9c2ca2b5d91600033ac5 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sun, 4 Jan 2026 05:17:40 +0530 Subject: [PATCH 3/4] ironed out a ui flaw + fix --- src/components/home/ContinueWatchingSection.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/home/ContinueWatchingSection.tsx b/src/components/home/ContinueWatchingSection.tsx index 05bca2a..ee866f7 100644 --- a/src/components/home/ContinueWatchingSection.tsx +++ b/src/components/home/ContinueWatchingSection.tsx @@ -469,7 +469,10 @@ const ContinueWatchingSection = React.forwardRef((props, re // Skip movies that are already watched on Trakt if (group.type === 'movie') { const watchedSet = await traktMoviesSetPromise; - if (watchedSet.has(group.id)) { + const imdbId = group.id.startsWith('tt') + ? group.id + : `tt${group.id}`; + if (watchedSet.has(imdbId)) { // Optional: sync local store to watched to prevent reappearance try { await storageService.setWatchProgress(group.id, 'movie', { @@ -1198,7 +1201,6 @@ const ContinueWatchingSection = React.forwardRef((props, re padding: isTV ? 16 : isLargeTablet ? 14 : isTablet ? 12 : 12 } ]}> - {(() => { const isUpNext = item.type === 'series' && item.progress === 0; return ( From be3e111e638632b03af23afe8680d6ab06dfcd94 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sun, 4 Jan 2026 05:44:56 +0530 Subject: [PATCH 4/4] small fix --- src/components/home/ContinueWatchingSection.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/home/ContinueWatchingSection.tsx b/src/components/home/ContinueWatchingSection.tsx index ee866f7..ac006e9 100644 --- a/src/components/home/ContinueWatchingSection.tsx +++ b/src/components/home/ContinueWatchingSection.tsx @@ -376,7 +376,10 @@ const ContinueWatchingSection = React.forwardRef((props, re const [type, id, ...episodeIdParts] = keyParts; const episodeId = episodeIdParts.length > 0 ? episodeIdParts.join(':') : undefined; const progress = allProgress[key]; - const progressPercent = (progress.currentTime / progress.duration) * 100; + const progressPercent = + progress.duration > 0 + ? (progress.currentTime / progress.duration) * 100 + : 0; // Skip fully watched movies if (type === 'movie' && progressPercent >= 85) continue; // Skip movies with no actual progress (ensure > 0%)