From 29e5dee0014ecc8e740422c396182244e12356b2 Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Fri, 20 Feb 2026 21:51:36 +0530 Subject: [PATCH] improve episode progress removal logic and normalize episode IDs --- .../home/ContinueWatchingSection.tsx | 10 ++-- src/services/storageService.ts | 51 +++++++++++++++++-- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/src/components/home/ContinueWatchingSection.tsx b/src/components/home/ContinueWatchingSection.tsx index 62bdd020..586d66e1 100644 --- a/src/components/home/ContinueWatchingSection.tsx +++ b/src/components/home/ContinueWatchingSection.tsx @@ -1817,15 +1817,15 @@ const ContinueWatchingSection = React.forwardRef((props, re try { Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); - // For series episodes, only remove the specific episode's local progress - // Don't add a base tombstone which would block all episodes of the series + // For series episodes, remove only that episode's progress. + // Do not wipe all series entries. const isEpisode = selectedItem.type === 'series' && selectedItem.season && selectedItem.episode; if (isEpisode) { - // Only remove local progress for this specific episode (no base tombstone) - await storageService.removeAllWatchProgressForContent( + const episodeId = `${selectedItem.id}:${selectedItem.season}:${selectedItem.episode}`; + await storageService.removeWatchProgress( selectedItem.id, selectedItem.type, - { addBaseTombstone: false } + episodeId ); } else { // For movies or whole series, add the base tombstone diff --git a/src/services/storageService.ts b/src/services/storageService.ts index bd3b1484..74402527 100644 --- a/src/services/storageService.ts +++ b/src/services/storageService.ts @@ -80,6 +80,29 @@ class StorageService { return `${type}:${id}${episodeId ? `:${episodeId}` : ''}`; } + private normalizeContinueWatchingEpisodeRemoveId(id: string, episodeId?: string): string | undefined { + if (!episodeId) return undefined; + const normalizedId = id?.trim(); + const normalizedEpisodeId = episodeId.trim(); + if (!normalizedId || !normalizedEpisodeId) return undefined; + + const colonMatch = normalizedEpisodeId.match(/(?:^|:)(\d+):(\d+)$/); + if (colonMatch) { + return `${normalizedId}:${colonMatch[1]}:${colonMatch[2]}`; + } + + const sxeMatch = normalizedEpisodeId.match(/s(\d+)e(\d+)/i); + if (sxeMatch) { + return `${normalizedId}:${sxeMatch[1]}:${sxeMatch[2]}`; + } + + if (normalizedEpisodeId.startsWith(`${normalizedId}:`)) { + return normalizedEpisodeId; + } + + return `${normalizedId}:${normalizedEpisodeId}`; + } + public async addWatchProgressTombstone( id: string, type: string, @@ -274,12 +297,30 @@ class StorageService { try { const removedMap = await this.getContinueWatchingRemoved(); - const removedKey = this.buildWpKeyString(id, type); - const removedAt = removedMap[removedKey]; + const removeCandidates: Array<{ removeId: string; key: string }> = []; - if (removedAt != null && timestamp > removedAt) { - logger.log(`♻️ [StorageService] restoring content to continue watching due to new progress: ${type}:${id}`); - await this.removeContinueWatchingRemoved(id, type); + const baseRemoveId = (id || '').trim(); + if (baseRemoveId) { + removeCandidates.push({ + removeId: baseRemoveId, + key: this.buildWpKeyString(baseRemoveId, type), + }); + } + + const episodeRemoveId = this.normalizeContinueWatchingEpisodeRemoveId(id, episodeId); + if (episodeRemoveId && episodeRemoveId !== baseRemoveId) { + removeCandidates.push({ + removeId: episodeRemoveId, + key: this.buildWpKeyString(episodeRemoveId, type), + }); + } + + for (const candidate of removeCandidates) { + const removedAt = removedMap[candidate.key]; + if (removedAt != null && timestamp > removedAt) { + logger.log(`♻️ [StorageService] restoring content to continue watching due to new progress: ${candidate.key}`); + await this.removeContinueWatchingRemoved(candidate.removeId, type); + } } } catch (e) { // Ignore error checks for restoration to prevent blocking save