mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
Enhance ContinueWatchingSection with improved logging, validation, and UI updates
This update introduces a validation function for IMDB IDs, enhancing the robustness of the ContinueWatchingSection. It also adds detailed logging throughout the loading process, providing insights into the progress items being processed and any filtering based on completion percentage. The UI has been refined with new styles for content items, including a wider layout and improved progress display, ensuring a better user experience. Additionally, the HomeScreen has been updated to include debug buttons for managing watch progress, facilitating easier testing and interaction.
This commit is contained in:
parent
7fb168f530
commit
6c2259f6e8
4 changed files with 1555 additions and 58 deletions
1165
package-lock.json
generated
1165
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -9,6 +9,7 @@ import {
|
|||
AppState,
|
||||
AppStateStatus
|
||||
} from 'react-native';
|
||||
import Animated, { FadeIn } from 'react-native-reanimated';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { NavigationProp } from '@react-navigation/native';
|
||||
import { RootStackParamList } from '../../navigation/AppNavigator';
|
||||
|
|
@ -60,6 +61,13 @@ const { width } = Dimensions.get('window');
|
|||
const posterLayout = calculatePosterLayout(width);
|
||||
const POSTER_WIDTH = posterLayout.posterWidth;
|
||||
|
||||
// Function to validate IMDB ID format
|
||||
const isValidImdbId = (id: string): boolean => {
|
||||
// IMDB IDs should start with 'tt' followed by 7-10 digits
|
||||
const imdbPattern = /^tt\d{7,10}$/;
|
||||
return imdbPattern.test(id);
|
||||
};
|
||||
|
||||
// Create a proper imperative handle with React.forwardRef and updated type
|
||||
const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, ref) => {
|
||||
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
|
||||
|
|
@ -72,9 +80,13 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
|||
// Modified loadContinueWatching to be more efficient
|
||||
const loadContinueWatching = useCallback(async () => {
|
||||
try {
|
||||
console.log('[ContinueWatching] Starting to load continue watching items...');
|
||||
setLoading(true);
|
||||
const allProgress = await storageService.getAllWatchProgress();
|
||||
console.log(`[ContinueWatching] Found ${Object.keys(allProgress).length} progress items in storage`);
|
||||
|
||||
if (Object.keys(allProgress).length === 0) {
|
||||
console.log('[ContinueWatching] No progress items found, setting empty array');
|
||||
setContinueWatchingItems([]);
|
||||
return;
|
||||
}
|
||||
|
|
@ -85,33 +97,80 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
|||
|
||||
// Process each saved progress
|
||||
for (const key in allProgress) {
|
||||
console.log(`[ContinueWatching] Raw key from storage: "${key}"`);
|
||||
|
||||
// Parse the key to get type and id
|
||||
const [type, id, episodeId] = key.split(':');
|
||||
const keyParts = key.split(':');
|
||||
console.log(`[ContinueWatching] Key parts:`, keyParts);
|
||||
|
||||
const [type, id, ...episodeIdParts] = keyParts;
|
||||
const episodeId = episodeIdParts.length > 0 ? episodeIdParts.join(':') : undefined;
|
||||
const progress = allProgress[key];
|
||||
|
||||
console.log(`[ContinueWatching] Parsed - type: "${type}", id: "${id}", episodeId: "${episodeId}"`);
|
||||
|
||||
// Skip items that are more than 95% complete (effectively finished)
|
||||
const progressPercent = (progress.currentTime / progress.duration) * 100;
|
||||
if (progressPercent >= 95) continue;
|
||||
console.log(`[ContinueWatching] Progress for ${key}: ${progressPercent.toFixed(1)}%`);
|
||||
|
||||
if (progressPercent >= 95) {
|
||||
console.log(`[ContinueWatching] Skipping ${key} - too high progress (${progressPercent.toFixed(1)}%)`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const contentPromise = (async () => {
|
||||
try {
|
||||
// Validate IMDB ID format before attempting to fetch
|
||||
if (!isValidImdbId(id)) {
|
||||
console.log(`[ContinueWatching] Skipping ${type}:${id} - invalid IMDB ID format`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[ContinueWatching] Fetching content details for ${type}:${id}`);
|
||||
let content: StreamingContent | null = null;
|
||||
|
||||
// Get content details using catalogService
|
||||
content = await catalogService.getContentDetails(type, id);
|
||||
|
||||
if (content) {
|
||||
console.log(`[ContinueWatching] Successfully fetched content: ${content.name}`);
|
||||
|
||||
// Extract season and episode info from episodeId if available
|
||||
let season: number | undefined;
|
||||
let episode: number | undefined;
|
||||
let episodeTitle: string | undefined;
|
||||
|
||||
if (episodeId && type === 'series') {
|
||||
const match = episodeId.match(/s(\d+)e(\d+)/i);
|
||||
console.log(`[ContinueWatching] Parsing episode ID: ${episodeId}`);
|
||||
|
||||
// Try different episode ID formats
|
||||
let match = episodeId.match(/s(\d+)e(\d+)/i); // Format: s1e1
|
||||
if (match) {
|
||||
season = parseInt(match[1], 10);
|
||||
episode = parseInt(match[2], 10);
|
||||
episodeTitle = `Episode ${episode}`;
|
||||
console.log(`[ContinueWatching] Parsed s1e1 format: S${season}E${episode}`);
|
||||
} else {
|
||||
// Try format: seriesId:season:episode (e.g., tt0108778:4:6)
|
||||
const parts = episodeId.split(':');
|
||||
if (parts.length >= 3) {
|
||||
const seasonPart = parts[parts.length - 2]; // Second to last part
|
||||
const episodePart = parts[parts.length - 1]; // Last part
|
||||
|
||||
const seasonNum = parseInt(seasonPart, 10);
|
||||
const episodeNum = parseInt(episodePart, 10);
|
||||
|
||||
if (!isNaN(seasonNum) && !isNaN(episodeNum)) {
|
||||
season = seasonNum;
|
||||
episode = episodeNum;
|
||||
episodeTitle = `Episode ${episode}`;
|
||||
console.log(`[ContinueWatching] Parsed colon format: S${season}E${episode}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!season || !episode) {
|
||||
console.log(`[ContinueWatching] Failed to parse episode details from: ${episodeId}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -124,18 +183,31 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
|||
episodeTitle
|
||||
};
|
||||
|
||||
console.log(`[ContinueWatching] Created item for ${content.name}:`, {
|
||||
type,
|
||||
season,
|
||||
episode,
|
||||
episodeTitle,
|
||||
episodeId,
|
||||
originalKey: key
|
||||
});
|
||||
|
||||
if (type === 'series') {
|
||||
// For series, keep only the latest watched episode for each show
|
||||
if (!latestEpisodes[id] || latestEpisodes[id].lastUpdated < progress.lastUpdated) {
|
||||
latestEpisodes[id] = continueWatchingItem;
|
||||
console.log(`[ContinueWatching] Updated latest episode for series ${id}`);
|
||||
}
|
||||
} else {
|
||||
// For movies, add to the list directly
|
||||
progressItems.push(continueWatchingItem);
|
||||
console.log(`[ContinueWatching] Added movie to progress items`);
|
||||
}
|
||||
} else {
|
||||
console.log(`[ContinueWatching] Failed to fetch content details for ${type}:${id}`);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Failed to get content details for ${type}:${id}`, error);
|
||||
console.error(`[ContinueWatching] Failed to get content details for ${type}:${id}`, error);
|
||||
}
|
||||
})();
|
||||
|
||||
|
|
@ -143,18 +215,35 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
|||
}
|
||||
|
||||
// Wait for all content to be processed
|
||||
console.log(`[ContinueWatching] Waiting for ${contentPromises.length} content promises...`);
|
||||
await Promise.all(contentPromises);
|
||||
|
||||
// Add the latest episodes for each series to the items list
|
||||
progressItems.push(...Object.values(latestEpisodes));
|
||||
console.log(`[ContinueWatching] Total items after processing: ${progressItems.length}`);
|
||||
|
||||
// Sort by last updated time (most recent first)
|
||||
progressItems.sort((a, b) => b.lastUpdated - a.lastUpdated);
|
||||
|
||||
// Limit to 10 items
|
||||
setContinueWatchingItems(progressItems.slice(0, 10));
|
||||
const finalItems = progressItems.slice(0, 10);
|
||||
console.log(`[ContinueWatching] Final continue watching items: ${finalItems.length}`);
|
||||
|
||||
// Debug: Log the final items with their episode details
|
||||
finalItems.forEach((item, index) => {
|
||||
console.log(`[ContinueWatching] Item ${index}:`, {
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
season: item.season,
|
||||
episode: item.episode,
|
||||
episodeTitle: item.episodeTitle,
|
||||
progress: item.progress
|
||||
});
|
||||
});
|
||||
|
||||
setContinueWatchingItems(finalItems);
|
||||
} catch (error) {
|
||||
logger.error('Failed to load continue watching items:', error);
|
||||
console.error('[ContinueWatching] Failed to load continue watching items:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
@ -219,9 +308,12 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
|||
// Properly expose the refresh method
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
refresh: async () => {
|
||||
console.log('[ContinueWatching] Refresh method called');
|
||||
await loadContinueWatching();
|
||||
// Return whether there are items to help parent determine visibility
|
||||
return continueWatchingItems.length > 0;
|
||||
const hasItems = continueWatchingItems.length > 0;
|
||||
console.log(`[ContinueWatching] Refresh returning hasItems: ${hasItems}, items count: ${continueWatchingItems.length}`);
|
||||
return hasItems;
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
@ -235,7 +327,7 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
|||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Animated.View entering={FadeIn.duration(400).delay(250)} style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<View style={styles.titleContainer}>
|
||||
<Text style={[styles.title, { color: currentTheme.colors.highEmphasis }]}>Continue Watching</Text>
|
||||
|
|
@ -252,41 +344,91 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
|||
data={continueWatchingItems}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity
|
||||
style={[styles.contentItem, {
|
||||
style={[styles.wideContentItem, {
|
||||
backgroundColor: currentTheme.colors.elevation1,
|
||||
borderColor: currentTheme.colors.border,
|
||||
shadowColor: currentTheme.colors.black
|
||||
}]}
|
||||
activeOpacity={0.7}
|
||||
activeOpacity={0.8}
|
||||
onPress={() => handleContentPress(item.id, item.type)}
|
||||
>
|
||||
<View style={styles.contentItemContainer}>
|
||||
{/* Poster Image */}
|
||||
<View style={styles.posterContainer}>
|
||||
<ExpoImage
|
||||
source={{ uri: item.poster }}
|
||||
style={styles.poster}
|
||||
style={styles.widePoster}
|
||||
contentFit="cover"
|
||||
transition={200}
|
||||
cachePolicy="memory-disk"
|
||||
/>
|
||||
{item.type === 'series' && item.season && item.episode && (
|
||||
<View style={[styles.episodeInfoContainer, { backgroundColor: 'rgba(0, 0, 0, 0.7)' }]}>
|
||||
<Text style={[styles.episodeInfo, { color: currentTheme.colors.white }]}>
|
||||
S{item.season.toString().padStart(2, '0')}E{item.episode.toString().padStart(2, '0')}
|
||||
</Text>
|
||||
{item.episodeTitle && (
|
||||
<Text style={[styles.episodeTitle, { color: currentTheme.colors.white, opacity: 0.9 }]} numberOfLines={1}>
|
||||
{item.episodeTitle}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Content Details */}
|
||||
<View style={styles.contentDetails}>
|
||||
<View style={styles.titleRow}>
|
||||
<Text
|
||||
style={[styles.contentTitle, { color: currentTheme.colors.highEmphasis }]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{item.name}
|
||||
</Text>
|
||||
<View style={[styles.progressBadge, { backgroundColor: currentTheme.colors.primary }]}>
|
||||
<Text style={styles.progressText}>{Math.round(item.progress)}%</Text>
|
||||
</View>
|
||||
)}
|
||||
{/* Progress bar indicator */}
|
||||
<View style={styles.progressBarContainer}>
|
||||
<View
|
||||
style={[
|
||||
styles.progressBar,
|
||||
{ width: `${item.progress}%`, backgroundColor: currentTheme.colors.primary }
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Episode Info or Year */}
|
||||
{(() => {
|
||||
console.log(`[ContinueWatching] Rendering item:`, {
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
season: item.season,
|
||||
episode: item.episode,
|
||||
episodeTitle: item.episodeTitle,
|
||||
hasSeasonAndEpisode: !!(item.season && item.episode)
|
||||
});
|
||||
|
||||
if (item.type === 'series' && item.season && item.episode) {
|
||||
return (
|
||||
<View style={styles.episodeRow}>
|
||||
<Text style={[styles.episodeText, { color: currentTheme.colors.mediumEmphasis }]}>
|
||||
Season {item.season}
|
||||
</Text>
|
||||
{item.episodeTitle && (
|
||||
<Text
|
||||
style={[styles.episodeTitle, { color: currentTheme.colors.mediumEmphasis }]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{item.episodeTitle}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Text style={[styles.yearText, { color: currentTheme.colors.mediumEmphasis }]}>
|
||||
{item.year} • {item.type === 'movie' ? 'Movie' : 'Series'}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
})()}
|
||||
|
||||
{/* Progress Bar */}
|
||||
<View style={styles.wideProgressContainer}>
|
||||
<View style={styles.wideProgressTrack}>
|
||||
<View
|
||||
style={[
|
||||
styles.wideProgressBar,
|
||||
{
|
||||
width: `${item.progress}%`,
|
||||
backgroundColor: currentTheme.colors.primary
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
<Text style={[styles.progressLabel, { color: currentTheme.colors.textMuted }]}>
|
||||
{Math.round(item.progress)}% watched
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
|
@ -294,13 +436,13 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
|||
keyExtractor={(item) => `continue-${item.id}-${item.type}`}
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={styles.list}
|
||||
snapToInterval={POSTER_WIDTH + 10}
|
||||
contentContainerStyle={styles.wideList}
|
||||
snapToInterval={280 + 16} // Card width + margin
|
||||
decelerationRate="fast"
|
||||
snapToAlignment="start"
|
||||
ItemSeparatorComponent={() => <View style={{ width: 10 }} />}
|
||||
ItemSeparatorComponent={() => <View style={{ width: 16 }} />}
|
||||
/>
|
||||
</View>
|
||||
</Animated.View>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -315,7 +457,7 @@ const styles = StyleSheet.create({
|
|||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 16,
|
||||
marginBottom: 8,
|
||||
marginBottom: 12,
|
||||
},
|
||||
titleContainer: {
|
||||
position: 'relative',
|
||||
|
|
@ -335,6 +477,96 @@ const styles = StyleSheet.create({
|
|||
height: 3,
|
||||
borderRadius: 1.5,
|
||||
},
|
||||
wideList: {
|
||||
paddingHorizontal: 16,
|
||||
paddingBottom: 8,
|
||||
paddingTop: 4,
|
||||
},
|
||||
wideContentItem: {
|
||||
width: 280,
|
||||
height: 120,
|
||||
flexDirection: 'row',
|
||||
borderRadius: 12,
|
||||
overflow: 'hidden',
|
||||
elevation: 6,
|
||||
shadowOffset: { width: 0, height: 3 },
|
||||
shadowOpacity: 0.2,
|
||||
shadowRadius: 6,
|
||||
borderWidth: 1,
|
||||
},
|
||||
posterContainer: {
|
||||
width: 80,
|
||||
height: '100%',
|
||||
},
|
||||
widePoster: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
borderTopLeftRadius: 12,
|
||||
borderBottomLeftRadius: 12,
|
||||
},
|
||||
contentDetails: {
|
||||
flex: 1,
|
||||
padding: 12,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
titleRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'flex-start',
|
||||
marginBottom: 4,
|
||||
},
|
||||
contentTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
flex: 1,
|
||||
marginRight: 8,
|
||||
},
|
||||
progressBadge: {
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 3,
|
||||
borderRadius: 12,
|
||||
minWidth: 44,
|
||||
alignItems: 'center',
|
||||
},
|
||||
progressText: {
|
||||
fontSize: 12,
|
||||
fontWeight: '700',
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
episodeRow: {
|
||||
marginBottom: 8,
|
||||
},
|
||||
episodeText: {
|
||||
fontSize: 13,
|
||||
fontWeight: '600',
|
||||
marginBottom: 2,
|
||||
},
|
||||
episodeTitle: {
|
||||
fontSize: 12,
|
||||
},
|
||||
yearText: {
|
||||
fontSize: 13,
|
||||
fontWeight: '500',
|
||||
marginBottom: 8,
|
||||
},
|
||||
wideProgressContainer: {
|
||||
marginTop: 'auto',
|
||||
},
|
||||
wideProgressTrack: {
|
||||
height: 4,
|
||||
backgroundColor: 'rgba(255,255,255,0.1)',
|
||||
borderRadius: 2,
|
||||
marginBottom: 4,
|
||||
},
|
||||
wideProgressBar: {
|
||||
height: '100%',
|
||||
borderRadius: 2,
|
||||
},
|
||||
progressLabel: {
|
||||
fontSize: 11,
|
||||
fontWeight: '500',
|
||||
},
|
||||
// Keep old styles for backward compatibility
|
||||
list: {
|
||||
paddingHorizontal: 16,
|
||||
paddingBottom: 8,
|
||||
|
|
@ -377,9 +609,6 @@ const styles = StyleSheet.create({
|
|||
fontSize: 12,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
episodeTitle: {
|
||||
fontSize: 10,
|
||||
},
|
||||
progressBarContainer: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
|
|
|
|||
|
|
@ -488,7 +488,7 @@ const HomeScreen = () => {
|
|||
|
||||
await Promise.all(imagePromises);
|
||||
} catch (error) {
|
||||
console.error('Error preloading images:', error);
|
||||
// Silently handle preload errors
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
|
@ -530,9 +530,37 @@ const HomeScreen = () => {
|
|||
}, [featuredContent, navigation]);
|
||||
|
||||
const refreshContinueWatching = useCallback(async () => {
|
||||
console.log('[HomeScreen] Refreshing continue watching...');
|
||||
if (continueWatchingRef.current) {
|
||||
const hasContent = await continueWatchingRef.current.refresh();
|
||||
setHasContinueWatching(hasContent);
|
||||
try {
|
||||
const hasContent = await continueWatchingRef.current.refresh();
|
||||
console.log(`[HomeScreen] Continue watching has content: ${hasContent}`);
|
||||
setHasContinueWatching(hasContent);
|
||||
|
||||
// Debug: Let's check what's in storage
|
||||
const allProgress = await storageService.getAllWatchProgress();
|
||||
console.log('[HomeScreen] All watch progress in storage:', Object.keys(allProgress).length, 'items');
|
||||
console.log('[HomeScreen] Watch progress items:', allProgress);
|
||||
|
||||
// Check if any items are being filtered out due to >95% progress
|
||||
let filteredCount = 0;
|
||||
for (const [key, progress] of Object.entries(allProgress)) {
|
||||
const progressPercent = (progress.currentTime / progress.duration) * 100;
|
||||
if (progressPercent >= 95) {
|
||||
filteredCount++;
|
||||
console.log(`[HomeScreen] Filtered out ${key}: ${progressPercent.toFixed(1)}% complete`);
|
||||
} else {
|
||||
console.log(`[HomeScreen] Valid progress ${key}: ${progressPercent.toFixed(1)}% complete`);
|
||||
}
|
||||
}
|
||||
console.log(`[HomeScreen] Filtered out ${filteredCount} completed items`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('[HomeScreen] Error refreshing continue watching:', error);
|
||||
setHasContinueWatching(false);
|
||||
}
|
||||
} else {
|
||||
console.log('[HomeScreen] Continue watching ref is null');
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
|
@ -596,11 +624,50 @@ const HomeScreen = () => {
|
|||
<ThisWeekSection />
|
||||
</Animated.View>
|
||||
|
||||
{hasContinueWatching && (
|
||||
<Animated.View entering={FadeIn.duration(400).delay(250)}>
|
||||
<ContinueWatchingSection ref={continueWatchingRef} />
|
||||
</Animated.View>
|
||||
)}
|
||||
{/* Debug buttons for Continue Watching */}
|
||||
<View style={{ flexDirection: 'row', padding: 16, gap: 10 }}>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
backgroundColor: currentTheme.colors.primary,
|
||||
padding: 10,
|
||||
borderRadius: 8,
|
||||
flex: 1
|
||||
}}
|
||||
onPress={addTestWatchProgress}
|
||||
>
|
||||
<Text style={{ color: 'white', textAlign: 'center', fontSize: 12 }}>
|
||||
Add Test Progress
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
backgroundColor: currentTheme.colors.error || '#ff4444',
|
||||
padding: 10,
|
||||
borderRadius: 8,
|
||||
flex: 1
|
||||
}}
|
||||
onPress={clearAllWatchProgress}
|
||||
>
|
||||
<Text style={{ color: 'white', textAlign: 'center', fontSize: 12 }}>
|
||||
Clear All Progress
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
backgroundColor: currentTheme.colors.secondary,
|
||||
padding: 10,
|
||||
borderRadius: 8,
|
||||
flex: 1
|
||||
}}
|
||||
onPress={refreshContinueWatching}
|
||||
>
|
||||
<Text style={{ color: 'white', textAlign: 'center', fontSize: 12 }}>
|
||||
Refresh
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<ContinueWatchingSection ref={continueWatchingRef} />
|
||||
|
||||
{catalogs.length > 0 ? (
|
||||
catalogs.map((catalog, index) => (
|
||||
|
|
@ -642,6 +709,58 @@ const HomeScreen = () => {
|
|||
featuredContentSource
|
||||
]);
|
||||
|
||||
// Debug function to add test watch progress
|
||||
const addTestWatchProgress = useCallback(async () => {
|
||||
console.log('[HomeScreen] Adding test watch progress data...');
|
||||
try {
|
||||
// Add a test movie with 50% progress
|
||||
await storageService.setWatchProgress(
|
||||
'tt1375666', // Inception IMDB ID
|
||||
'movie',
|
||||
{
|
||||
currentTime: 3600, // 1 hour
|
||||
duration: 7200, // 2 hours (50% progress)
|
||||
lastUpdated: Date.now()
|
||||
}
|
||||
);
|
||||
|
||||
// Add a test series episode with 30% progress
|
||||
await storageService.setWatchProgress(
|
||||
'tt0944947', // Game of Thrones IMDB ID
|
||||
'series',
|
||||
{
|
||||
currentTime: 1800, // 30 minutes
|
||||
duration: 6000, // 100 minutes (30% progress)
|
||||
lastUpdated: Date.now() - 86400000 // 1 day ago
|
||||
},
|
||||
'tt0944947:1:1' // Season 1, Episode 1
|
||||
);
|
||||
|
||||
console.log('[HomeScreen] Test watch progress added successfully');
|
||||
|
||||
// Refresh the continue watching section
|
||||
await refreshContinueWatching();
|
||||
} catch (error) {
|
||||
console.error('[HomeScreen] Error adding test watch progress:', error);
|
||||
}
|
||||
}, [refreshContinueWatching]);
|
||||
|
||||
// Debug function to clear all watch progress
|
||||
const clearAllWatchProgress = useCallback(async () => {
|
||||
console.log('[HomeScreen] Clearing all watch progress...');
|
||||
try {
|
||||
const allProgress = await storageService.getAllWatchProgress();
|
||||
for (const key of Object.keys(allProgress)) {
|
||||
const [type, id, episodeId] = key.split(':');
|
||||
await storageService.removeWatchProgress(id, type, episodeId);
|
||||
}
|
||||
console.log('[HomeScreen] All watch progress cleared');
|
||||
await refreshContinueWatching();
|
||||
} catch (error) {
|
||||
console.error('[HomeScreen] Error clearing watch progress:', error);
|
||||
}
|
||||
}, [refreshContinueWatching]);
|
||||
|
||||
return isLoading ? renderLoadingScreen : renderMainContent;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -415,14 +415,11 @@ class StremioService {
|
|||
});
|
||||
}
|
||||
|
||||
logger.log(`Cinemeta catalog request URL: ${url}`);
|
||||
|
||||
const response = await this.retryRequest(async () => {
|
||||
return await axios.get(url);
|
||||
});
|
||||
|
||||
if (response.data && response.data.metas && Array.isArray(response.data.metas)) {
|
||||
logger.log(`Cinemeta returned ${response.data.metas.length} items`);
|
||||
return response.data.metas;
|
||||
}
|
||||
return [];
|
||||
|
|
@ -453,14 +450,11 @@ class StremioService {
|
|||
});
|
||||
}
|
||||
|
||||
logger.log(`${manifest.name} catalog request URL: ${url}`);
|
||||
|
||||
const response = await this.retryRequest(async () => {
|
||||
return await axios.get(url);
|
||||
});
|
||||
|
||||
if (response.data && response.data.metas && Array.isArray(response.data.metas)) {
|
||||
logger.log(`${manifest.name} returned ${response.data.metas.length} items`);
|
||||
return response.data.metas;
|
||||
}
|
||||
return [];
|
||||
|
|
|
|||
Loading…
Reference in a new issue