diff --git a/src/components/home/ContinueWatchingSection.tsx b/src/components/home/ContinueWatchingSection.tsx index 7763914d..2539ed59 100644 --- a/src/components/home/ContinueWatchingSection.tsx +++ b/src/components/home/ContinueWatchingSection.tsx @@ -393,16 +393,16 @@ const ContinueWatchingSection = React.forwardRef((props, re Season {item.season} - - {item.episodeTitle && ( + + {item.episodeTitle && ( - {item.episodeTitle} - - )} - + {item.episodeTitle} + + )} + ); } else { return ( @@ -416,15 +416,15 @@ const ContinueWatchingSection = React.forwardRef((props, re {/* Progress Bar */} - + ]} + /> {Math.round(item.progress)}% watched diff --git a/src/components/metadata/SeriesContent.tsx b/src/components/metadata/SeriesContent.tsx index 37e0cf7a..82086fd5 100644 --- a/src/components/metadata/SeriesContent.tsx +++ b/src/components/metadata/SeriesContent.tsx @@ -40,16 +40,17 @@ export const SeriesContent: React.FC = ({ const { width } = useWindowDimensions(); const isTablet = width > 768; const isDarkMode = useColorScheme() === 'dark'; - const [episodeProgress, setEpisodeProgress] = useState<{ [key: string]: { currentTime: number; duration: number } }>({}); + const [episodeProgress, setEpisodeProgress] = useState<{ [key: string]: { currentTime: number; duration: number; lastUpdated: number } }>({}); - // Add ref for the season selector ScrollView + // Add refs for the scroll views const seasonScrollViewRef = useRef(null); + const episodeScrollViewRef = useRef(null); const loadEpisodesProgress = async () => { if (!metadata?.id) return; const allProgress = await storageService.getAllWatchProgress(); - const progress: { [key: string]: { currentTime: number; duration: number } } = {}; + const progress: { [key: string]: { currentTime: number; duration: number; lastUpdated: number } } = {}; episodes.forEach(episode => { const episodeId = episode.stremioId || `${metadata.id}:${episode.season_number}:${episode.episode_number}`; @@ -57,7 +58,8 @@ export const SeriesContent: React.FC = ({ if (allProgress[key]) { progress[episodeId] = { currentTime: allProgress[key].currentTime, - duration: allProgress[key].duration + duration: allProgress[key].duration, + lastUpdated: allProgress[key].lastUpdated }; } }); @@ -65,6 +67,67 @@ export const SeriesContent: React.FC = ({ setEpisodeProgress(progress); }; + // Function to find and scroll to the most recently watched episode + const scrollToMostRecentEpisode = () => { + if (!metadata?.id || !episodeScrollViewRef.current || settings.episodeLayoutStyle !== 'horizontal') { + console.log('[SeriesContent] Scroll conditions not met:', { + hasMetadataId: !!metadata?.id, + hasScrollRef: !!episodeScrollViewRef.current, + isHorizontal: settings.episodeLayoutStyle === 'horizontal' + }); + return; + } + + const currentSeasonEpisodes = groupedEpisodes[selectedSeason] || []; + if (currentSeasonEpisodes.length === 0) { + console.log('[SeriesContent] No episodes in current season:', selectedSeason); + return; + } + + // Find the most recently watched episode in the current season + let mostRecentEpisodeIndex = -1; + let mostRecentTimestamp = 0; + let mostRecentEpisodeName = ''; + + currentSeasonEpisodes.forEach((episode, index) => { + const episodeId = episode.stremioId || `${metadata.id}:${episode.season_number}:${episode.episode_number}`; + const progress = episodeProgress[episodeId]; + + if (progress && progress.lastUpdated > mostRecentTimestamp && progress.currentTime > 0) { + mostRecentTimestamp = progress.lastUpdated; + mostRecentEpisodeIndex = index; + mostRecentEpisodeName = episode.name; + } + }); + + console.log('[SeriesContent] Episode scroll analysis:', { + totalEpisodes: currentSeasonEpisodes.length, + mostRecentIndex: mostRecentEpisodeIndex, + mostRecentEpisode: mostRecentEpisodeName, + selectedSeason + }); + + // Scroll to the most recently watched episode if found + if (mostRecentEpisodeIndex >= 0) { + const cardWidth = isTablet ? width * 0.4 + 16 : width * 0.85 + 16; + const scrollPosition = mostRecentEpisodeIndex * cardWidth; + + console.log('[SeriesContent] Scrolling to episode:', { + index: mostRecentEpisodeIndex, + cardWidth, + scrollPosition, + episodeName: mostRecentEpisodeName + }); + + setTimeout(() => { + episodeScrollViewRef.current?.scrollTo({ + x: scrollPosition, + animated: true + }); + }, 500); // Delay to ensure the season has loaded + } + }; + // Initial load of watch progress useEffect(() => { loadEpisodesProgress(); @@ -96,6 +159,13 @@ export const SeriesContent: React.FC = ({ } }, [selectedSeason, groupedEpisodes]); + // Add effect to scroll to most recently watched episode when season changes or progress loads + useEffect(() => { + if (Object.keys(episodeProgress).length > 0 && selectedSeason) { + scrollToMostRecentEpisode(); + } + }, [selectedSeason, episodeProgress, settings.episodeLayoutStyle, groupedEpisodes]); + if (loadingSeasons) { return ( @@ -480,6 +550,7 @@ export const SeriesContent: React.FC = ({ {settings.episodeLayoutStyle === 'horizontal' ? ( // Horizontal Layout (Netflix-style) { + if (key.includes(`series:${id}:`)) { + const episodeId = key.split(`series:${id}:`)[1]; + if (progress.lastUpdated > mostRecentTimestamp && progress.currentTime > 0) { + mostRecentTimestamp = progress.lastUpdated; + mostRecentEpisodeId = episodeId; + } + } + }); + + if (mostRecentEpisodeId) { + // Parse season number from episode ID + const parts = mostRecentEpisodeId.split(':'); + if (parts.length === 3) { + const watchProgressSeason = parseInt(parts[1], 10); + if (transformedEpisodes[watchProgressSeason]) { + selectedSeasonNumber = watchProgressSeason; + logger.log(`[useMetadata] Auto-selected season ${selectedSeasonNumber} based on most recent watch progress for ${mostRecentEpisodeId}`); + } + } else { + // Try to find episode by stremioId to get season + const allEpisodesList = Object.values(transformedEpisodes).flat(); + const episode = allEpisodesList.find(ep => ep.stremioId === mostRecentEpisodeId); + if (episode) { + selectedSeasonNumber = episode.season_number; + logger.log(`[useMetadata] Auto-selected season ${selectedSeasonNumber} based on most recent watch progress for episode with stremioId ${mostRecentEpisodeId}`); + } + } + } else { + // No watch progress found, use persistent storage as fallback + selectedSeasonNumber = getSeason(id, firstSeason); + logger.log(`[useMetadata] No watch progress found, using persistent season ${selectedSeasonNumber}`); + } + } catch (error) { + logger.error('[useMetadata] Error checking watch progress for season selection:', error); + // Fall back to persistent storage + selectedSeasonNumber = getSeason(id, firstSeason); + } + + // Set the selected season + setSelectedSeason(selectedSeasonNumber); // Set episodes for the selected season - setEpisodes(transformedEpisodes[persistedSeason] || []); + setEpisodes(transformedEpisodes[selectedSeasonNumber] || []); } } catch (error) { console.error('Failed to load episodes:', error); diff --git a/src/hooks/useWatchProgress.ts b/src/hooks/useWatchProgress.ts index b17e4345..ff47bf49 100644 --- a/src/hooks/useWatchProgress.ts +++ b/src/hooks/useWatchProgress.ts @@ -103,36 +103,27 @@ export const useWatchProgress = ( setWatchProgress(null); } } else { - // Find the first unfinished episode - const unfinishedEpisode = episodes.find(ep => { - const epId = ep.stremioId || `${id}:${ep.season_number}:${ep.episode_number}`; - const progress = seriesProgresses.find(p => p.episodeId === epId); - if (!progress) return true; - const percent = (progress.progress.currentTime / progress.progress.duration) * 100; - return percent < 95; - }); - - if (unfinishedEpisode) { - const epId = unfinishedEpisode.stremioId || - `${id}:${unfinishedEpisode.season_number}:${unfinishedEpisode.episode_number}`; - const progress = await storageService.getWatchProgress(id, type, epId); - if (progress) { - setWatchProgress({ - ...progress, - episodeId: epId, - traktSynced: progress.traktSynced, - traktProgress: progress.traktProgress - }); - } else { - setWatchProgress({ - currentTime: 0, - duration: 0, - lastUpdated: Date.now(), - episodeId: epId, - traktSynced: false - }); - } + // FIXED: Find the most recently watched episode instead of first unfinished + // Sort by lastUpdated timestamp (most recent first) + const sortedProgresses = seriesProgresses.sort((a, b) => + b.progress.lastUpdated - a.progress.lastUpdated + ); + + if (sortedProgresses.length > 0) { + // Use the most recently watched episode + const mostRecentProgress = sortedProgresses[0]; + const progress = mostRecentProgress.progress; + + logger.log(`[useWatchProgress] Using most recent progress for ${mostRecentProgress.episodeId}, updated at ${new Date(progress.lastUpdated).toLocaleString()}`); + + setWatchProgress({ + ...progress, + episodeId: mostRecentProgress.episodeId, + traktSynced: progress.traktSynced, + traktProgress: progress.traktProgress + }); } else { + // No watched episodes found setWatchProgress(null); } } diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 52efa750..9a248eeb 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -533,9 +533,9 @@ const HomeScreen = () => { console.log('[HomeScreen] Refreshing continue watching...'); if (continueWatchingRef.current) { try { - const hasContent = await continueWatchingRef.current.refresh(); + const hasContent = await continueWatchingRef.current.refresh(); console.log(`[HomeScreen] Continue watching has content: ${hasContent}`); - setHasContinueWatching(hasContent); + setHasContinueWatching(hasContent); // Debug: Let's check what's in storage const allProgress = await storageService.getAllWatchProgress(); @@ -667,7 +667,7 @@ const HomeScreen = () => { - + {catalogs.length > 0 ? ( catalogs.map((catalog, index) => (