diff --git a/src/hooks/useMetadata.ts b/src/hooks/useMetadata.ts index d47aa1a8..751e8c83 100644 --- a/src/hooks/useMetadata.ts +++ b/src/hooks/useMetadata.ts @@ -1604,22 +1604,26 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat }); // Add local scrapers if enabled - localScrapers.filter((scraper: ScraperInfo) => scraper.enabled).forEach((scraper: ScraperInfo) => { - initialStatuses.push({ - id: scraper.id, - name: scraper.name, - isLoading: true, - hasCompleted: false, - error: null, - startTime: Date.now(), - endTime: null + const currentSettings = await mmkvStorage.getItem('app_settings'); + const enableLocalScrapersNow = currentSettings ? JSON.parse(currentSettings).enableLocalScrapers !== false : true; + + if (enableLocalScrapersNow) { + localScrapers.filter((scraper: ScraperInfo) => scraper.enabled).forEach((scraper: ScraperInfo) => { + initialStatuses.push({ + id: scraper.id, + name: scraper.name, + isLoading: true, + hasCompleted: false, + error: null, + startTime: Date.now(), + endTime: null + }); + initialActiveFetching.push(scraper.name); }); - initialActiveFetching.push(scraper.name); - }); + } setScraperStatuses(initialStatuses); setActiveFetchingScrapers(initialActiveFetching); - console.log('🔍 [loadStreams] Initialized activeFetchingScrapers:', initialActiveFetching); // If no scrapers are available, stop loading immediately if (initialStatuses.length === 0) { @@ -1740,23 +1744,27 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat initialActiveFetching.push(addon.name); }); - // Add local scrapers if enabled - localScrapers.filter((scraper: ScraperInfo) => scraper.enabled).forEach((scraper: ScraperInfo) => { - initialStatuses.push({ - id: scraper.id, - name: scraper.name, - isLoading: true, - hasCompleted: false, - error: null, - startTime: Date.now(), - endTime: null + // Add local scrapers if enabled (read from storage to avoid stale closure) + const currentSettings = await mmkvStorage.getItem('app_settings'); + const enableLocalScrapersNow = currentSettings ? JSON.parse(currentSettings).enableLocalScrapers !== false : true; + + if (enableLocalScrapersNow) { + localScrapers.filter((scraper: ScraperInfo) => scraper.enabled).forEach((scraper: ScraperInfo) => { + initialStatuses.push({ + id: scraper.id, + name: scraper.name, + isLoading: true, + hasCompleted: false, + error: null, + startTime: Date.now(), + endTime: null + }); + initialActiveFetching.push(scraper.name); }); - initialActiveFetching.push(scraper.name); - }); + } setScraperStatuses(initialStatuses); setActiveFetchingScrapers(initialActiveFetching); - console.log('🔍 [loadEpisodeStreams] Initialized activeFetchingScrapers:', initialActiveFetching); // If no scrapers are available, stop loading immediately if (initialStatuses.length === 0) { diff --git a/src/i18n/locales/ar.json b/src/i18n/locales/ar.json index e5820d71..a42c202a 100644 --- a/src/i18n/locales/ar.json +++ b/src/i18n/locales/ar.json @@ -1090,8 +1090,8 @@ "external_title": "مشغل خارجي", "external_desc": "فتح البثوث في مشغل الفيديو المفضل لديك", "section_playback": "خيارات التشغيل", - "autoplay_title": "تشغيل أفضل بث تلقائياً", - "autoplay_desc": "بدء أعلى جودة بث متاحة تلقائياً.", + "autoplay_title": "تشغيل أول بث تلقائياً", + "autoplay_desc": "بدء أول بث معروض في القائمة تلقائياً.", "resume_title": "استكمال دائماً", "resume_desc": "تخطي مطالبة الاستكمال والمتابعة تلقائياً من حيث توقفت (إذا تمت مشاهدة أقل من 85%).", "engine_title": "محرك مشغل الفيديو", diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 961b42a6..4bca4397 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -1093,8 +1093,8 @@ "external_title": "External Player", "external_desc": "Open streams in your preferred video player", "section_playback": "PLAYBACK OPTIONS", - "autoplay_title": "Auto-play Best Stream", - "autoplay_desc": "Automatically start the highest quality stream available.", + "autoplay_title": "Auto-play First Stream", + "autoplay_desc": "Automatically start the first stream shown in the list.", "resume_title": "Always Resume", "resume_desc": "Skip the resume prompt and automatically continue where you left off (if less than 85% watched).", "engine_title": "Video Player Engine", diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index a795dc0a..2325eb33 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -1090,8 +1090,8 @@ "external_title": "Reproductor externo", "external_desc": "Abrir fuentes en tu reproductor de video preferido", "section_playback": "OPCIONES DE REPRODUCCIÓN", - "autoplay_title": "Autorreproducir la mejor fuente", - "autoplay_desc": "Iniciar automáticamente la fuente de mayor calidad disponible.", + "autoplay_title": "Autorreproducir la primera fuente", + "autoplay_desc": "Iniciar automáticamente la primera fuente mostrada en la lista.", "resume_title": "Reanudar siempre", "resume_desc": "Saltar el aviso de reanudar y continuar automáticamente donde lo dejaste (si se ha visto menos del 85%).", "engine_title": "Motor del reproductor", diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 7dd57310..90177c82 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -1090,8 +1090,8 @@ "external_title": "Lecteur externe", "external_desc": "Ouvrir les flux dans votre lecteur vidéo préféré", "section_playback": "OPTIONS DE LECTURE", - "autoplay_title": "Lecture automatique du meilleur flux", - "autoplay_desc": "Démarrer automatiquement le flux de la plus haute qualité disponible.", + "autoplay_title": "Lecture automatique du premier flux", + "autoplay_desc": "Démarrer automatiquement le premier flux affiché dans la liste.", "resume_title": "Toujours reprendre", "resume_desc": "Passer l'invite de reprise et continuer automatiquement là où vous vous étiez arrêté (si moins de 85% vus).", "engine_title": "Moteur du lecteur vidéo", diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 809cd27b..42bc7b0e 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -1090,8 +1090,8 @@ "external_title": "Player Esterno", "external_desc": "Apri gli stream nel tuo video player preferito", "section_playback": "OPZIONI RIPRODUZIONE", - "autoplay_title": "Auto-play Miglior Stream", - "autoplay_desc": "Avvia automaticamente lo stream alla massima qualità disponibile.", + "autoplay_title": "Auto-play Primo Stream", + "autoplay_desc": "Avvia automaticamente il primo stream mostrato nella lista.", "resume_title": "Riprendi Sempre", "resume_desc": "Salta la richiesta di ripresa e continua automaticamente da dove avevi interrotto (se visto meno dell'85%).", "engine_title": "Motore Video Player", diff --git a/src/i18n/locales/pt-BR.json b/src/i18n/locales/pt-BR.json index 9310a044..2c3f5bdf 100644 --- a/src/i18n/locales/pt-BR.json +++ b/src/i18n/locales/pt-BR.json @@ -981,8 +981,8 @@ "external_title": "Player Externo", "external_desc": "Abrir streams no seu player de vídeo preferido", "section_playback": "OPÇÕES DE REPRODUÇÃO", - "autoplay_title": "Reprodução Automática (Melhor Stream)", - "autoplay_desc": "Iniciar automaticamente o stream de melhor qualidade disponível.", + "autoplay_title": "Reprodução Automática (Primeiro Stream)", + "autoplay_desc": "Iniciar automaticamente o primeiro stream mostrado na lista.", "resume_title": "Sempre Retomar", "resume_desc": "Pular o aviso de retomar e continuar automaticamente de onde parou (se assistido menos de 85%).", "engine_title": "Motor do Player de Vídeo", diff --git a/src/i18n/locales/pt-PT.json b/src/i18n/locales/pt-PT.json index 1b590498..a40280ed 100644 --- a/src/i18n/locales/pt-PT.json +++ b/src/i18n/locales/pt-PT.json @@ -981,8 +981,8 @@ "external_title": "Reprodutor Externo", "external_desc": "Abrir streams no teu reprodutor de vídeo preferido", "section_playback": "OPÇÕES DE REPRODUÇÃO", - "autoplay_title": "Reprodução Automática (Melhor Stream)", - "autoplay_desc": "Iniciar automaticamente o stream de melhor qualidade disponível.", + "autoplay_title": "Reprodução Automática (Primeiro Stream)", + "autoplay_desc": "Iniciar automaticamente o primeiro stream mostrado na lista.", "resume_title": "Sempre Retomar", "resume_desc": "Saltar o aviso de retomar e continuar automaticamente de onde parou (se assistido menos de 85%).", "engine_title": "Motor do reprodutor", diff --git a/src/screens/PlayerSettingsScreen.tsx b/src/screens/PlayerSettingsScreen.tsx index 047ed368..93f4031d 100644 --- a/src/screens/PlayerSettingsScreen.tsx +++ b/src/screens/PlayerSettingsScreen.tsx @@ -294,48 +294,14 @@ const PlayerSettingsScreen: React.FC = () => { updateSetting('autoplayBestStream', value)} - thumbColor={settings.autoplayBestStream ? currentTheme.colors.primary : undefined} + trackColor={{ false: '#767577', true: currentTheme.colors.primary }} + thumbColor={settings.autoplayBestStream ? '#ffffff' : '#f4f3f4'} + ios_backgroundColor="#3e3e3e" /> - - - - - - - - {t('player.resume_title')} - - - {t('player.resume_desc')} - - - updateSetting('alwaysResume', value)} - thumbColor={settings.alwaysResume ? currentTheme.colors.primary : undefined} - /> - - + {/* Video Player Engine for Android */} {Platform.OS === 'android' && !settings.useExternalPlayer && ( diff --git a/src/screens/streams/useStreamsScreen.ts b/src/screens/streams/useStreamsScreen.ts index 704252a3..1689a017 100644 --- a/src/screens/streams/useStreamsScreen.ts +++ b/src/screens/streams/useStreamsScreen.ts @@ -48,7 +48,7 @@ export const useStreamsScreen = () => { const route = useRoute>(); const navigation = useNavigation(); const { id, type, episodeId, episodeThumbnail, fromPlayer } = route.params; - const { settings } = useSettings(); + const { settings, isLoaded: settingsLoaded } = useSettings(); const { currentTheme } = useTheme(); const { colors } = currentTheme; const { pauseTrailer, resumeTrailer } = useTrailer(); @@ -586,6 +586,16 @@ export const useStreamsScreen = () => { setAutoplayTriggered(false); }, [selectedEpisode]); + // Initialize autoplay waiting state when settings are loaded + // This runs after settings are fully loaded to avoid race conditions + useEffect(() => { + if (!settingsLoaded) return; // Wait for settings to load + + if (settings.autoplayBestStream && !fromPlayer && !autoplayTriggered) { + setIsAutoplayWaiting(true); + } + }, [settingsLoaded, settings.autoplayBestStream, fromPlayer, autoplayTriggered]); + // Reset provider if no longer available useEffect(() => { const isSpecialFilter = @@ -659,11 +669,7 @@ export const useStreamsScreen = () => { } setAutoplayTriggered(false); - if (settings.autoplayBestStream && !fromPlayer) { - setIsAutoplayWaiting(true); - } else { - setIsAutoplayWaiting(false); - } + // Note: isAutoplayWaiting is now handled by a separate effect that waits for settings to load } } finally { isLoadingStreamsRef.current = false; @@ -678,6 +684,8 @@ export const useStreamsScreen = () => { useEffect(() => { if (settings.autoplayBestStream && !autoplayTriggered && isAutoplayWaiting) { const streams = selectedEpisode ? episodeStreams : groupedStreams; + const hasLoadingStarted = streamsLoadStart !== null; + const isStillLoading = !hasLoadingStarted || loadingStreams || loadingEpisodeStreams || activeFetchingScrapers.length > 0; if (Object.keys(streams).length > 0) { const bestStream = getBestStream(streams); @@ -687,9 +695,11 @@ export const useStreamsScreen = () => { setAutoplayTriggered(true); setIsAutoplayWaiting(false); handleStreamPress(bestStream); - } else { + } else if (!isStillLoading) { setIsAutoplayWaiting(false); } + } else if (!isStillLoading) { + setIsAutoplayWaiting(false); } } }, [ @@ -703,6 +713,10 @@ export const useStreamsScreen = () => { handleStreamPress, metadata, selectedEpisode, + loadingStreams, + loadingEpisodeStreams, + activeFetchingScrapers.length, + streamsLoadStart, ]); // Cleanup on unmount