From e32390608384fc4c76fa30360046f6a82162dfb0 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sat, 3 Jan 2026 18:11:27 +0530 Subject: [PATCH 1/8] fix up next --- .../home/ContinueWatchingSection.tsx | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/components/home/ContinueWatchingSection.tsx b/src/components/home/ContinueWatchingSection.tsx index 4d19e3c..745f5fd 100644 --- a/src/components/home/ContinueWatchingSection.tsx +++ b/src/components/home/ContinueWatchingSection.tsx @@ -769,24 +769,36 @@ const ContinueWatchingSection = React.forwardRef((props, re if (!cachedData?.basicContent) continue; const { metadata, basicContent } = cachedData; - if (metadata?.videos) { - const nextEpisodeVideo = findNextEpisode(info.season, info.episode, metadata.videos); - if (nextEpisodeVideo) { - logger.log(`➕ [TraktSync] Adding next episode for ${showId}: S${nextEpisodeVideo.season}E${nextEpisodeVideo.episode}`); - traktBatch.push({ - ...basicContent, - id: showId, - type: 'series', - progress: 0, // Next episode, not started - lastUpdated: info.watchedAt, - season: nextEpisodeVideo.season, - episode: nextEpisodeVideo.episode, - episodeTitle: `Episode ${nextEpisodeVideo.episode}`, - addonId: undefined, - } as ContinueWatchingItem); - } + const traktService = TraktService.getInstance(); + let showProgress: any = null; + + try { + showProgress = await (traktService as any).getShowWatchedProgress?.(showId); + } catch { + showProgress = null; } + if (!showProgress || showProgress.completed || !showProgress.next_episode) { + logger.log(`🚫 [TraktSync] Skipping completed show: ${showId}`); + continue; + } + + const nextEp = showProgress.next_episode; + + logger.log(`➕ [TraktSync] Adding next episode for ${showId}: S${nextEp.season}E${nextEp.number}`); + + traktBatch.push({ + ...basicContent, + id: showId, + type: 'series', + progress: 0, + lastUpdated: info.watchedAt, + season: nextEp.season, + episode: nextEp.number, + episodeTitle: nextEp.title || `Episode ${nextEp.number}`, + addonId: undefined, + } as ContinueWatchingItem); + // Persist "watched" progress for the episode that Trakt reported if (!recentlyRemovedRef.current.has(showKey)) { const watchedEpisodeId = `${showId}:${info.season}:${info.episode}`; From 4603d1dc2aee5b6b61613d1805a50493a94c3395 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sat, 3 Jan 2026 18:33:06 +0530 Subject: [PATCH 2/8] redo how trakt marks stuff as watched to local --- src/services/watchedService.ts | 80 +++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/src/services/watchedService.ts b/src/services/watchedService.ts index 3436496..4bfca17 100644 --- a/src/services/watchedService.ts +++ b/src/services/watchedService.ts @@ -301,52 +301,60 @@ class WatchedService { * Check if a movie is marked as watched (locally) */ public async isMovieWatched(imdbId: string): Promise { - try { - // First check local watched flag - const localWatched = await mmkvStorage.getItem(`watched:movie:${imdbId}`); - if (localWatched === 'true') { - return true; - } + try { + const isAuthed = await this.traktService.isAuthenticated(); - // Check local progress - const progress = await storageService.getWatchProgress(imdbId, 'movie'); - if (progress) { - const progressPercent = (progress.currentTime / progress.duration) * 100; - if (progressPercent >= 85) { - return true; - } - } - - return false; - } catch (error) { - logger.error('[WatchedService] Error checking movie watched status:', error); - return false; + if (isAuthed) { + const traktWatched = + await this.traktService.isMovieWatchedAccurate(imdbId); + if (traktWatched) return true; } + + const local = await mmkvStorage.getItem(`watched:movie:${imdbId}`); + return local === 'true'; + } catch { + return false; + } } + /** * Check if an episode is marked as watched (locally) */ - public async isEpisodeWatched(showId: string, season: number, episode: number): Promise { - try { - const episodeId = `${showId}:${season}:${episode}`; + public async isEpisodeWatched( + showId: string, + season: number, + episode: number + ): Promise { + try { + const isAuthed = await this.traktService.isAuthenticated(); - // Check local progress - const progress = await storageService.getWatchProgress(showId, 'series', episodeId); - if (progress) { - const progressPercent = (progress.currentTime / progress.duration) * 100; - if (progressPercent >= 85) { - return true; - } - } - - return false; - } catch (error) { - logger.error('[WatchedService] Error checking episode watched status:', error); - return false; + if (isAuthed) { + const traktWatched = + await this.traktService.isEpisodeWatchedAccurate( + showId, + season, + episode + ); + if (traktWatched) return true; } - } + const episodeId = `${showId}:${season}:${episode}`; + const progress = await storageService.getWatchProgress( + showId, + 'series', + episodeId + ); + + if (!progress) return false; + + const pct = (progress.currentTime / progress.duration) * 100; + return pct >= 99; + } catch { + return false; + } + } + /** * Set local watched status by creating a "completed" progress entry */ From af138944b538ff6cd53b7b2637ac70b73c8069de Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sat, 3 Jan 2026 18:45:43 +0530 Subject: [PATCH 3/8] fix trakt sync to local for upnext --- src/services/traktService.ts | 49 +++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/services/traktService.ts b/src/services/traktService.ts index f3874a4..d46f95f 100644 --- a/src/services/traktService.ts +++ b/src/services/traktService.ts @@ -1099,6 +1099,53 @@ export class TraktService { return this.apiRequest('/sync/watched/shows'); } + + public async isMovieWatchedAccurate(imdbId: string): Promise { + try { + const history = await this.client.get( + `/sync/history/movies/${imdbId}?limit=1` + ); + + return Array.isArray(history) && history.length > 0; + } catch { + return false; + } + } + + public async isEpisodeWatchedAccurate( + showId: string, + season: number, + episode: number + ): Promise { + try { + const history = await this.client.get( + `/sync/history/episodes/${showId}`, + { params: { limit: 20 } } + ); + + if (!Array.isArray(history)) 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; + } + } + + return false; + } catch { + return false; + } + } + /** * Get the user's watchlist movies */ @@ -2923,4 +2970,4 @@ export class TraktService { } // Export a singleton instance -export const traktService = TraktService.getInstance(); \ No newline at end of file +export const traktService = TraktService.getInstance(); From ebbe715581687634ee7334a6d9a6bb2aeb4583b9 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sat, 3 Jan 2026 18:52:53 +0530 Subject: [PATCH 4/8] small fix --- src/services/traktService.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/services/traktService.ts b/src/services/traktService.ts index d46f95f..eb94f8f 100644 --- a/src/services/traktService.ts +++ b/src/services/traktService.ts @@ -1105,7 +1105,8 @@ export class TraktService { const history = await this.client.get( `/sync/history/movies/${imdbId}?limit=1` ); - + + const history = response.data; return Array.isArray(history) && history.length > 0; } catch { return false; @@ -1122,7 +1123,8 @@ export class TraktService { `/sync/history/episodes/${showId}`, { params: { limit: 20 } } ); - + + const history = response.data; if (!Array.isArray(history)) return false; for (const entry of history) { From 28d27128d171d53f71e02f8880f6a0a4c1684720 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sat, 3 Jan 2026 19:11:35 +0530 Subject: [PATCH 5/8] fix local data overriding trakt progress --- .../home/ContinueWatchingSection.tsx | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/components/home/ContinueWatchingSection.tsx b/src/components/home/ContinueWatchingSection.tsx index 745f5fd..0b4a290 100644 --- a/src/components/home/ContinueWatchingSection.tsx +++ b/src/components/home/ContinueWatchingSection.tsx @@ -500,23 +500,46 @@ const ContinueWatchingSection = React.forwardRef((props, re } } - if (currentSeason !== undefined && currentEpisode !== undefined && metadata?.videos) { - const nextEpisodeVideo = findNextEpisode(currentSeason, currentEpisode, metadata.videos); + if (currentSeason !== undefined && currentEpisode !== undefined) { + const traktService = TraktService.getInstance(); + let nextEpisode: any = null; - if (nextEpisodeVideo) { + try { + const isAuthed = await traktService.isAuthenticated(); + if (isAuthed && typeof (traktService as any).getShowWatchedProgress === 'function') { + const showProgress = await (traktService as any).getShowWatchedProgress(group.id); + + if (showProgress && !showProgress.completed && showProgress.next_episode) { + nextEpisode = showProgress.next_episode; + } + } + } catch { + + } + + if (!nextEpisode && metadata?.videos) { + nextEpisode = findNextEpisode( + currentSeason, + currentEpisode, + metadata.videos + ); + } + + if (nextEpisode) { batch.push({ ...basicContent, id: group.id, type: group.type, progress: 0, lastUpdated: progress.lastUpdated, - season: nextEpisodeVideo.season, - episode: nextEpisodeVideo.episode, - episodeTitle: `Episode ${nextEpisodeVideo.episode}`, + season: nextEpisode.season, + episode: nextEpisode.number ?? nextEpisode.episode, + episodeTitle: nextEpisode.title || `Episode ${nextEpisode.number ?? nextEpisode.episode}`, addonId: progress.addonId, } as ContinueWatchingItem); } } + } continue; } From e0ad949141a164099c7083839df66d404b3a43a8 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sat, 3 Jan 2026 19:47:53 +0530 Subject: [PATCH 6/8] small fix --- .../home/ContinueWatchingSection.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/components/home/ContinueWatchingSection.tsx b/src/components/home/ContinueWatchingSection.tsx index 0b4a290..9ba6046 100644 --- a/src/components/home/ContinueWatchingSection.tsx +++ b/src/components/home/ContinueWatchingSection.tsx @@ -227,18 +227,26 @@ const ContinueWatchingSection = React.forwardRef((props, re try { const shouldFetchMeta = await stremioService.isValidContentId(type, id); - const [metadata, basicContent, addonContent] = await Promise.all([ + const [metadata, basicContent, addonSpecificMeta, metadataAddonMeta] = await Promise.all([ shouldFetchMeta ? stremioService.getMetaDetails(type, id) : Promise.resolve(null), catalogService.getBasicContentDetails(type, id), - addonId ? stremioService.getMetaDetails(type, id, addonId).catch(() => null) : Promise.resolve(null) + + addonId + ? stremioService.getMetaDetails(type, id, addonId).catch(() => null) + : Promise.resolve(null), + + stremioService.getMetaDetails(type, id).catch(() => null) ]); + const preferredAddonMeta = addonSpecificMeta || metadataAddonMeta; + const finalContent = basicContent ? { ...basicContent, - ...(addonContent?.name && { name: addonContent.name }), - ...(addonContent?.poster && { poster: addonContent.poster }), - ...(addonContent?.description && { description: addonContent.description }), + ...(preferredAddonMeta?.name && { name: preferredAddonMeta.name }), + ...(preferredAddonMeta?.poster && { poster: preferredAddonMeta.poster }), + ...(preferredAddonMeta?.description && { description: preferredAddonMeta.description }), } : null; + if (finalContent) { const result = { metadata, basicContent: finalContent, addonContent, timestamp: now }; From e7b3458f3497d7c2a7e8fb43ca20a9c554a83752 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sat, 3 Jan 2026 19:54:46 +0530 Subject: [PATCH 7/8] small fix --- src/components/home/ContinueWatchingSection.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/home/ContinueWatchingSection.tsx b/src/components/home/ContinueWatchingSection.tsx index 9ba6046..d3ae49d 100644 --- a/src/components/home/ContinueWatchingSection.tsx +++ b/src/components/home/ContinueWatchingSection.tsx @@ -249,7 +249,13 @@ const ContinueWatchingSection = React.forwardRef((props, re if (finalContent) { - const result = { metadata, basicContent: finalContent, addonContent, timestamp: now }; + const result = { + metadata, + basicContent: finalContent, + addonContent: preferredAddonMeta, + timestamp: now + }; + metadataCache.current[cacheKey] = result; return result; } From 2c6c110265086b6f63f4de8bdce522ad9b562816 Mon Sep 17 00:00:00 2001 From: chrisk325 Date: Sat, 3 Jan 2026 20:03:03 +0530 Subject: [PATCH 8/8] fix --- src/components/home/ContinueWatchingSection.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/home/ContinueWatchingSection.tsx b/src/components/home/ContinueWatchingSection.tsx index d3ae49d..05bca2a 100644 --- a/src/components/home/ContinueWatchingSection.tsx +++ b/src/components/home/ContinueWatchingSection.tsx @@ -227,18 +227,17 @@ const ContinueWatchingSection = React.forwardRef((props, re try { const shouldFetchMeta = await stremioService.isValidContentId(type, id); - const [metadata, basicContent, addonSpecificMeta, metadataAddonMeta] = await Promise.all([ + const [metadata, basicContent, addonSpecificMeta] = await Promise.all([ shouldFetchMeta ? stremioService.getMetaDetails(type, id) : Promise.resolve(null), catalogService.getBasicContentDetails(type, id), addonId ? stremioService.getMetaDetails(type, id, addonId).catch(() => null) - : Promise.resolve(null), - - stremioService.getMetaDetails(type, id).catch(() => null) + : Promise.resolve(null) ]); - const preferredAddonMeta = addonSpecificMeta || metadataAddonMeta; + const preferredAddonMeta = addonSpecificMeta || metadata; + const finalContent = basicContent ? { ...basicContent,