mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-11 17:45:38 +00:00
fixed backdrop zoom in laoding overlay.
This commit is contained in:
parent
03da6c9a0c
commit
d691189973
4 changed files with 44 additions and 141 deletions
1
react-native-vlc-media-player
Submodule
1
react-native-vlc-media-player
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 22fae0eb0964990c030889e2be3ed7a3d5c92a45
|
||||
|
|
@ -28,8 +28,6 @@ import Animated, {
|
|||
import { StreamingContent } from '../../services/catalogService';
|
||||
import { SkeletonFeatured } from './SkeletonLoaders';
|
||||
import { hasValidLogoFormat, isTmdbUrl } from '../../utils/logoUtils';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { TMDBService } from '../../services/tmdbService';
|
||||
import { logger } from '../../utils/logger';
|
||||
import { useTheme } from '../../contexts/ThemeContext';
|
||||
|
||||
|
|
@ -150,15 +148,11 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary, loadin
|
|||
const [showSkeleton, setShowSkeleton] = useState(true);
|
||||
const [logoError, setLogoError] = useState(false);
|
||||
const [bannerError, setBannerError] = useState(false);
|
||||
const { settings } = useSettings();
|
||||
const logoOpacity = useSharedValue(0);
|
||||
const bannerOpacity = useSharedValue(0);
|
||||
const posterOpacity = useSharedValue(0);
|
||||
const prevContentIdRef = useRef<string | null>(null);
|
||||
// Add state for tracking logo load errors
|
||||
const [logoLoadError, setLogoLoadError] = useState(false);
|
||||
// Add a ref to track logo fetch in progress
|
||||
const logoFetchInProgress = useRef<boolean>(false);
|
||||
const firstRenderTsRef = useRef<number>(nowMs());
|
||||
const lastContentChangeTsRef = useRef<number>(0);
|
||||
|
||||
|
|
@ -251,130 +245,29 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary, loadin
|
|||
setLogoLoadError(false);
|
||||
}, [featuredContent?.id]);
|
||||
|
||||
// Fetch logo when enrichment is enabled; otherwise only use addon logo
|
||||
// Use logo from featuredContent data (already processed by useFeaturedContent hook)
|
||||
useEffect(() => {
|
||||
if (!featuredContent || logoFetchInProgress.current) return;
|
||||
if (!featuredContent) {
|
||||
setLogoUrl(null);
|
||||
setLogoLoadError(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchLogo = async () => {
|
||||
logoFetchInProgress.current = true;
|
||||
const t0 = nowMs();
|
||||
logger.info('[FeaturedContent] fetchLogo:start', { id: featuredContent?.id, type: featuredContent?.type });
|
||||
|
||||
try {
|
||||
const contentId = featuredContent.id;
|
||||
const contentData = featuredContent; // Use a clearer variable name
|
||||
const currentLogo = contentData.logo;
|
||||
|
||||
// Get language preference (only relevant when enrichment is enabled)
|
||||
const preferredLanguage = settings.tmdbLanguagePreference || 'en';
|
||||
|
||||
// If enrichment is disabled, use addon logo and don't fetch from external sources
|
||||
if (!settings.enrichMetadataWithTMDB) {
|
||||
logger.info('[FeaturedContent] enrichment disabled, checking for addon logo', {
|
||||
hasLogo: !!contentData.logo,
|
||||
logo: contentData.logo,
|
||||
isExternal: contentData.logo ? isTmdbUrl(contentData.logo) : false,
|
||||
isTmdb: contentData.logo ? isTmdbUrl(contentData.logo) : false
|
||||
// Simply use the logo that's already been processed by the useFeaturedContent hook
|
||||
const logo = featuredContent.logo;
|
||||
logger.info('[FeaturedContent] using logo from data', {
|
||||
id: featuredContent.id,
|
||||
name: featuredContent.name,
|
||||
hasLogo: Boolean(logo),
|
||||
logo: logo,
|
||||
logoSource: logo ? (isTmdbUrl(logo) ? 'tmdb' : 'addon') : 'none',
|
||||
type: featuredContent.type
|
||||
});
|
||||
|
||||
// If we have an addon logo, use it and don't fetch external logos
|
||||
if (contentData.logo) {
|
||||
logger.info('[FeaturedContent] enrichment disabled, using addon logo', { logo: contentData.logo });
|
||||
setLogoUrl(contentData.logo);
|
||||
logoFetchInProgress.current = false;
|
||||
return;
|
||||
}
|
||||
// If no addon logo, don't fetch external logos when enrichment is disabled
|
||||
logger.info('[FeaturedContent] enrichment disabled, no addon logo available');
|
||||
logoFetchInProgress.current = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset state for new fetch only if switching to a different item
|
||||
if (prevContentIdRef.current !== contentId) {
|
||||
setLogoUrl(null);
|
||||
}
|
||||
setLogoLoadError(false);
|
||||
|
||||
// Extract IDs (only when enrichment is enabled)
|
||||
let imdbId: string | null = null;
|
||||
if (contentData.id.startsWith('tt')) {
|
||||
imdbId = contentData.id;
|
||||
} else if ((contentData as any).imdbId) {
|
||||
imdbId = (contentData as any).imdbId;
|
||||
} else if ((contentData as any).externalIds?.imdb_id) {
|
||||
imdbId = (contentData as any).externalIds.imdb_id;
|
||||
}
|
||||
|
||||
let tmdbId: string | null = null;
|
||||
if (contentData.id.startsWith('tmdb:')) {
|
||||
tmdbId = contentData.id.split(':')[1];
|
||||
} else if ((contentData as any).tmdb_id) {
|
||||
tmdbId = String((contentData as any).tmdb_id);
|
||||
}
|
||||
|
||||
// If we only have IMDB ID, try to find TMDB ID proactively (only when enrichment is enabled)
|
||||
if (imdbId && !tmdbId) {
|
||||
try {
|
||||
const tmdbService = TMDBService.getInstance();
|
||||
const foundData = await tmdbService.findTMDBIdByIMDB(imdbId);
|
||||
if (foundData) {
|
||||
tmdbId = String(foundData);
|
||||
}
|
||||
} catch (findError) {
|
||||
// logger.warn(`[FeaturedContent] Failed to find TMDB ID for ${imdbId}:`, findError);
|
||||
}
|
||||
}
|
||||
|
||||
const tmdbType = contentData.type === 'series' ? 'tv' : 'movie';
|
||||
let finalLogoUrl: string | null = null;
|
||||
let primaryAttempted = false;
|
||||
let fallbackAttempted = false;
|
||||
|
||||
// --- Logo Fetching Logic (TMDB only when enrichment is enabled) ---
|
||||
logger.debug('[FeaturedContent] fetchLogo:ids', { imdbId, tmdbId, lang: preferredLanguage });
|
||||
|
||||
// Try TMDB if we have a TMDB id
|
||||
if (tmdbId) {
|
||||
primaryAttempted = true;
|
||||
try {
|
||||
const tmdbService = TMDBService.getInstance();
|
||||
const tTmdb = nowMs();
|
||||
const logoUrl = await tmdbService.getContentLogo(tmdbType, tmdbId, preferredLanguage);
|
||||
if (logoUrl) {
|
||||
finalLogoUrl = logoUrl;
|
||||
logger.debug('[FeaturedContent] fetchLogo:tmdb:ok', { url: logoUrl, duration: since(tTmdb) });
|
||||
}
|
||||
} catch (error) { /* Log if needed */ }
|
||||
}
|
||||
|
||||
// --- Set Final Logo ---
|
||||
if (finalLogoUrl) {
|
||||
setLogoUrl(finalLogoUrl);
|
||||
logger.info('[FeaturedContent] fetchLogo:done', { id: contentId, result: 'tmdb', url: finalLogoUrl, duration: since(t0) });
|
||||
} else if (currentLogo) {
|
||||
// Use existing logo only if primary and fallback failed or weren't applicable
|
||||
setLogoUrl(currentLogo);
|
||||
logger.info('[FeaturedContent] fetchLogo:done', { id: contentId, result: 'addon', url: currentLogo, duration: since(t0) });
|
||||
} else {
|
||||
// No logo found from any source
|
||||
setLogoLoadError(true);
|
||||
logger.warn('[FeaturedContent] fetchLogo:none', { id: contentId, primaryAttempted, fallbackAttempted, duration: since(t0) });
|
||||
// logger.warn(`[FeaturedContent] No logo found for ${contentData.name} (${contentId}) with preference ${logoPreference}. Primary attempted: ${primaryAttempted}, Fallback attempted: ${fallbackAttempted}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
// logger.error('[FeaturedContent] Error in fetchLogo:', error);
|
||||
setLogoLoadError(true);
|
||||
logger.error('[FeaturedContent] fetchLogo:error', { error: String(error), duration: since(t0) });
|
||||
} finally {
|
||||
logoFetchInProgress.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Trigger fetch when content changes
|
||||
fetchLogo();
|
||||
}, [featuredContent, settings.tmdbLanguagePreference, settings.enrichMetadataWithTMDB]);
|
||||
setLogoUrl(logo || null);
|
||||
setLogoLoadError(!logo);
|
||||
setLogoError(false); // Reset any previous errors
|
||||
}, [featuredContent]);
|
||||
|
||||
// Load poster and logo
|
||||
useEffect(() => {
|
||||
|
|
@ -475,17 +368,20 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary, loadin
|
|||
// Load logo if available with enhanced timing
|
||||
if (logoUrl) {
|
||||
const tLogo = nowMs();
|
||||
// Try to preload but don't fail if it times out - still show the logo
|
||||
const logoSuccess = await preloadImage(logoUrl);
|
||||
if (logoSuccess) {
|
||||
logger.debug('[FeaturedContent] logo:preload:success', { id: contentId, duration: since(tLogo) });
|
||||
} else {
|
||||
logger.debug('[FeaturedContent] logo:preload:failed', { id: contentId, duration: since(tLogo) });
|
||||
}
|
||||
|
||||
// Always animate in the logo since we have the URL
|
||||
logoOpacity.value = withDelay(500, withTiming(1, {
|
||||
duration: 600,
|
||||
easing: Easing.out(Easing.cubic)
|
||||
}));
|
||||
logger.debug('[FeaturedContent] logo:ready', { id: contentId, duration: since(tLogo) });
|
||||
} else {
|
||||
setLogoLoadError(true);
|
||||
logger.warn('[FeaturedContent] logo:failed', { id: contentId, duration: since(tLogo) });
|
||||
}
|
||||
logger.debug('[FeaturedContent] logo:animated', { id: contentId });
|
||||
}
|
||||
logger.info('[FeaturedContent] images:load:done', { id: contentId, total: since(t0) });
|
||||
};
|
||||
|
|
@ -495,7 +391,7 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary, loadin
|
|||
|
||||
const onLogoLoadError = () => {
|
||||
setLogoLoaded(true); // Treat error as "loaded" to stop spinner
|
||||
setLogoError(true);
|
||||
setLogoLoadError(true);
|
||||
logger.warn('[FeaturedContent] logo:onError', { id: featuredContent?.id, url: logoUrl });
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
|
||||
import { View, TouchableOpacity, TouchableWithoutFeedback, Dimensions, Animated, ActivityIndicator, Platform, NativeModules, StatusBar, Text, StyleSheet, Modal, AppState } from 'react-native';
|
||||
import { View, TouchableOpacity, TouchableWithoutFeedback, Dimensions, Animated, ActivityIndicator, Platform, NativeModules, StatusBar, Text, StyleSheet, Modal, AppState, Image } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import Video, { VideoRef, SelectedTrack, SelectedTrackType, BufferingStrategyType, ViewType } from 'react-native-video';
|
||||
import FastImage from '@d11/react-native-fast-image';
|
||||
|
|
@ -3129,10 +3129,10 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
opacity: backdropImageOpacityAnim
|
||||
}
|
||||
]}>
|
||||
<FastImage
|
||||
<Image
|
||||
source={{ uri: backdrop }}
|
||||
style={StyleSheet.absoluteFillObject}
|
||||
resizeMode={FastImage.resizeMode.cover}
|
||||
resizeMode="cover"
|
||||
/>
|
||||
</Animated.View>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ export function useFeaturedContent() {
|
|||
logoSource: c.logo ? (isTmdbUrl(String(c.logo)) ? 'tmdb' : 'addon') : 'none',
|
||||
logo: c.logo || undefined,
|
||||
}));
|
||||
logger.debug('[useFeaturedContent] catalogs:logos:details', { items: details });
|
||||
logger.info('[useFeaturedContent] catalogs:logos:details (enrich=true)', { items: details });
|
||||
} catch {}
|
||||
} else {
|
||||
// When enrichment is disabled, prefer addon-provided logos; if missing, fetch basic meta to pull logo (like HeroSection)
|
||||
|
|
@ -257,7 +257,7 @@ export function useFeaturedContent() {
|
|||
logoSource: c.logo ? (isTmdbUrl(String(c.logo)) ? 'tmdb' : 'addon') : 'none',
|
||||
logo: c.logo || undefined,
|
||||
}));
|
||||
logger.debug('[useFeaturedContent] catalogs:logos:details (no-enrich)', { items: details });
|
||||
logger.info('[useFeaturedContent] catalogs:logos:details (no-enrich)', { items: details });
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
|
@ -295,6 +295,12 @@ export function useFeaturedContent() {
|
|||
if (formattedContent.length > 0) {
|
||||
persistentStore.featuredContent = formattedContent[0];
|
||||
setFeaturedContent(formattedContent[0]);
|
||||
logger.info('[useFeaturedContent] setting featuredContent', {
|
||||
id: formattedContent[0].id,
|
||||
name: formattedContent[0].name,
|
||||
hasLogo: Boolean(formattedContent[0].logo),
|
||||
logo: formattedContent[0].logo
|
||||
});
|
||||
currentIndexRef.current = 0;
|
||||
// Persist cache for fast startup (skipped when cache disabled)
|
||||
if (!DISABLE_CACHE) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue