From bd1d8e30ece7a044e99a19cd91988f0c0ab67f0a Mon Sep 17 00:00:00 2001 From: tapframe Date: Sun, 4 May 2025 18:35:04 +0530 Subject: [PATCH] Refactor FeaturedContent logo fetching logic for clarity and efficiency This update enhances the FeaturedContent component by improving the logo fetching logic. Key changes include clearer variable naming, streamlined ID extraction, and optimized error handling. The logic now better handles logo source preferences and ensures that existing logos are used as fallbacks when necessary. Additionally, the dependency array for the fetch effect has been refined for better performance. Overall, these modifications enhance code readability and maintainability. --- src/components/home/FeaturedContent.tsx | 217 +++++++++++------------- src/components/metadata/HeroSection.tsx | 7 +- src/hooks/useMetadataAssets.ts | 10 +- src/navigation/AppNavigator.tsx | 10 +- src/screens/LogoSourceSettings.tsx | 87 ++-------- 5 files changed, 132 insertions(+), 199 deletions(-) diff --git a/src/components/home/FeaturedContent.tsx b/src/components/home/FeaturedContent.tsx index eb4467f9c..2f88399df 100644 --- a/src/components/home/FeaturedContent.tsx +++ b/src/components/home/FeaturedContent.tsx @@ -122,153 +122,132 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat if (!featuredContent || logoFetchInProgress.current) return; const fetchLogo = async () => { - // Set fetch in progress flag logoFetchInProgress.current = true; try { const contentId = featuredContent.id; + const contentData = featuredContent; // Use a clearer variable name + const currentLogo = contentData.logo; - // Get logo source preference from settings - const logoPreference = settings.logoSourcePreference || 'metahub'; // Default to metahub if not set - const preferredLanguage = settings.tmdbLanguagePreference || 'en'; // Get preferred language + // Get preferences + const logoPreference = settings.logoSourcePreference || 'metahub'; + const preferredLanguage = settings.tmdbLanguagePreference || 'en'; - // Check if current logo matches preferences - const currentLogo = featuredContent.logo; - if (currentLogo) { - const isCurrentMetahub = isMetahubUrl(currentLogo); - const isCurrentTmdb = isTmdbUrl(currentLogo); - - // If logo already matches preference, use it - if ((logoPreference === 'metahub' && isCurrentMetahub) || - (logoPreference === 'tmdb' && isCurrentTmdb)) { - setLogoUrl(currentLogo); - logoFetchInProgress.current = false; - return; - } + // Reset state for new fetch + setLogoUrl(null); + setLogoLoadError(false); + + // Extract IDs + 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; } - // Extract IMDB ID if available - let imdbId = null; - if (featuredContent.id.startsWith('tt')) { - // If the ID itself is an IMDB ID - imdbId = featuredContent.id; - } else if ((featuredContent as any).imdbId) { - // Try to get IMDB ID from the content object if available - imdbId = (featuredContent as any).imdbId; + 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); } - // Extract TMDB ID if available - let tmdbId = null; - if (contentId.startsWith('tmdb:')) { - tmdbId = contentId.split(':')[1]; - } - - // First source based on preference - if (logoPreference === 'metahub' && imdbId) { - // Try to get logo from Metahub first - const metahubUrl = `https://images.metahub.space/logo/medium/${imdbId}/img`; - + // If we only have IMDB ID, try to find TMDB ID proactively + if (imdbId && !tmdbId) { try { - const response = await fetch(metahubUrl, { method: 'HEAD' }); - if (response.ok) { - setLogoUrl(metahubUrl); - logoFetchInProgress.current = false; - return; // Exit if Metahub logo was found + const tmdbService = TMDBService.getInstance(); + const foundData = await tmdbService.findTMDBIdByIMDB(imdbId); + if (foundData) { + tmdbId = String(foundData); } - } catch (error) { - // Removed logger.warn + } catch (findError) { + // logger.warn(`[FeaturedContent] Failed to find TMDB ID for ${imdbId}:`, findError); } - - // Fall back to TMDB if Metahub fails and we have a TMDB ID - if (tmdbId) { - const tmdbType = featuredContent.type === 'series' ? 'tv' : 'movie'; - try { - const tmdbService = TMDBService.getInstance(); - const logoUrl = await tmdbService.getContentLogo(tmdbType, tmdbId, preferredLanguage); - - if (logoUrl) { - setLogoUrl(logoUrl); - } else if (currentLogo) { - // If TMDB fails too, use existing logo if any - setLogoUrl(currentLogo); - } - } catch (error) { - // Removed logger.error - if (currentLogo) setLogoUrl(currentLogo); - } - } else if (currentLogo) { - // Use existing logo if we don't have TMDB ID - setLogoUrl(currentLogo); - } - } else if (logoPreference === 'tmdb') { - // Try to get logo from TMDB first - if (tmdbId) { - const tmdbType = featuredContent.type === 'series' ? 'tv' : 'movie'; - try { - const tmdbService = TMDBService.getInstance(); - const logoUrl = await tmdbService.getContentLogo(tmdbType, tmdbId, preferredLanguage); - - if (logoUrl) { - setLogoUrl(logoUrl); - logoFetchInProgress.current = false; - return; // Exit if TMDB logo was found - } - } catch (error) { - // Removed logger.error - } - } else if (imdbId) { - // If we have IMDB ID but no TMDB ID, try to find TMDB ID - try { - const tmdbService = TMDBService.getInstance(); - const foundTmdbId = await tmdbService.findTMDBIdByIMDB(imdbId); - - if (foundTmdbId) { - const tmdbType = featuredContent.type === 'series' ? 'tv' : 'movie'; - const logoUrl = await tmdbService.getContentLogo(tmdbType, foundTmdbId.toString(), preferredLanguage); - - if (logoUrl) { - setLogoUrl(logoUrl); - logoFetchInProgress.current = false; - return; // Exit if TMDB logo was found - } - } - } catch (error) { - // Removed logger.error - } - } - - // Fall back to Metahub if TMDB fails and we have an IMDB ID + } + + const tmdbType = contentData.type === 'series' ? 'tv' : 'movie'; + let finalLogoUrl: string | null = null; + let primaryAttempted = false; + let fallbackAttempted = false; + + // --- Logo Fetching Logic --- + + if (logoPreference === 'metahub') { + // Primary: Metahub (needs imdbId) if (imdbId) { + primaryAttempted = true; const metahubUrl = `https://images.metahub.space/logo/medium/${imdbId}/img`; - try { const response = await fetch(metahubUrl, { method: 'HEAD' }); if (response.ok) { - setLogoUrl(metahubUrl); - } else if (currentLogo) { - // If Metahub fails too, use existing logo if any - setLogoUrl(currentLogo); + finalLogoUrl = metahubUrl; } - } catch (error) { - // Removed logger.warn - if (currentLogo) setLogoUrl(currentLogo); - } - } else if (currentLogo) { - // Use existing logo if we don't have IMDB ID - setLogoUrl(currentLogo); + } catch (error) { /* Log if needed */ } + } + + // Fallback: TMDB (needs tmdbId) + if (!finalLogoUrl && tmdbId) { + fallbackAttempted = true; + try { + const tmdbService = TMDBService.getInstance(); + const logoUrl = await tmdbService.getContentLogo(tmdbType, tmdbId, preferredLanguage); + if (logoUrl) { + finalLogoUrl = logoUrl; + } + } catch (error) { /* Log if needed */ } + } + + } else { // logoPreference === 'tmdb' + // Primary: TMDB (needs tmdbId) + if (tmdbId) { + primaryAttempted = true; + try { + const tmdbService = TMDBService.getInstance(); + const logoUrl = await tmdbService.getContentLogo(tmdbType, tmdbId, preferredLanguage); + if (logoUrl) { + finalLogoUrl = logoUrl; + } + } catch (error) { /* Log if needed */ } + } + + // Fallback: Metahub (needs imdbId) + if (!finalLogoUrl && imdbId) { + fallbackAttempted = true; + const metahubUrl = `https://images.metahub.space/logo/medium/${imdbId}/img`; + try { + const response = await fetch(metahubUrl, { method: 'HEAD' }); + if (response.ok) { + finalLogoUrl = metahubUrl; + } + } catch (error) { /* Log if needed */ } } } + + // --- Set Final Logo --- + if (finalLogoUrl) { + setLogoUrl(finalLogoUrl); + } else if (currentLogo) { + // Use existing logo only if primary and fallback failed or weren't applicable + setLogoUrl(currentLogo); + } else { + // No logo found from any source + setLogoLoadError(true); + // logger.warn(`[FeaturedContent] No logo found for ${contentData.name} (${contentId}) with preference ${logoPreference}. Primary attempted: ${primaryAttempted}, Fallback attempted: ${fallbackAttempted}`); + } + } catch (error) { - // Removed logger.error - // Optionally set a fallback logo or handle the error state - setLogoUrl(featuredContent.logo ?? null); // Fallback to initial logo or null + // logger.error('[FeaturedContent] Error in fetchLogo:', error); + setLogoLoadError(true); } finally { logoFetchInProgress.current = false; } }; + // Trigger fetch when content changes fetchLogo(); - }, [featuredContent?.id, settings.logoSourcePreference, settings.tmdbLanguagePreference]); + }, [featuredContent, settings.logoSourcePreference, settings.tmdbLanguagePreference]); // Load poster and logo useEffect(() => { diff --git a/src/components/metadata/HeroSection.tsx b/src/components/metadata/HeroSection.tsx index cef9ec49d..be3c2119d 100644 --- a/src/components/metadata/HeroSection.tsx +++ b/src/components/metadata/HeroSection.tsx @@ -286,9 +286,10 @@ const HeroSection: React.FC = ({ })); const parallaxImageStyle = useAnimatedStyle(() => ({ - width: '100%', - height: '120%', + width: '120%', + height: '100%', top: '-10%', + left: '-10%', transform: [ { translateY: interpolate( @@ -302,7 +303,7 @@ const HeroSection: React.FC = ({ scale: interpolate( dampedScrollY.value, [0, 150, 300], - [1.1, 1.02, 0.95], + [1.05, 1.02, 0.99], Extrapolate.CLAMP ) } diff --git a/src/hooks/useMetadataAssets.ts b/src/hooks/useMetadataAssets.ts index 0b44bf094..5bd17f423 100644 --- a/src/hooks/useMetadataAssets.ts +++ b/src/hooks/useMetadataAssets.ts @@ -196,7 +196,15 @@ export const useMetadataAssets = ( else if (shouldFetchLogo && logoFetchInProgress.current) { logger.log(`[useMetadataAssets:Logo] Skipping logo fetch because logoFetchInProgress is true.`); } - }, [id, type, metadata, setMetadata, imdbId, settings.logoSourcePreference, settings.tmdbLanguagePreference]); // Added tmdbLanguagePreference dependency + }, [ + id, + type, + imdbId, + metadata?.logo, // Depend on the logo value itself, not the whole object + settings.logoSourcePreference, + settings.tmdbLanguagePreference, + setMetadata // Keep setMetadata, but ensure it's memoized in parent + ]); // Fetch banner image based on logo source preference - optimized version useEffect(() => { diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx index 6720cda31..8d8c4b8c6 100644 --- a/src/navigation/AppNavigator.tsx +++ b/src/navigation/AppNavigator.tsx @@ -686,7 +686,8 @@ const AppNavigator = () => { /> { { { settings.logoSourcePreference || 'metahub' ); - // TMDB Language Preference - const [selectedTmdbLanguage, setSelectedTmdbLanguage] = useState( - settings.tmdbLanguagePreference || 'en' - ); - // Make sure logoSource stays in sync with settings useEffect(() => { setLogoSource(settings.logoSourcePreference || 'metahub'); }, [settings.logoSourcePreference]); - // Keep selectedTmdbLanguage in sync with settings - useEffect(() => { - setSelectedTmdbLanguage(settings.tmdbLanguagePreference || 'en'); - }, [settings.tmdbLanguagePreference]); - - // Force reload settings from AsyncStorage when component mounts - useEffect(() => { - const loadSettingsFromStorage = async () => { - try { - const settingsJson = await AsyncStorage.getItem('app_settings'); - if (settingsJson) { - const storedSettings = JSON.parse(settingsJson); - - // Update local state to match stored settings - if (storedSettings.logoSourcePreference) { - setLogoSource(storedSettings.logoSourcePreference); - } - - if (storedSettings.tmdbLanguagePreference) { - setSelectedTmdbLanguage(storedSettings.tmdbLanguagePreference); - } - - logger.log('[LogoSourceSettings] Successfully loaded settings from AsyncStorage'); - } - } catch (error) { - logger.error('[LogoSourceSettings] Error loading settings from AsyncStorage:', error); - } - }; - - loadSettingsFromStorage(); - }, []); - // Selected example show const [selectedShow, setSelectedShow] = useState(EXAMPLE_SHOWS[0]); @@ -429,6 +392,9 @@ const LogoSourceSettings = () => { logger.log(`[LogoSourceSettings] Fetching ${show.name} with TMDB ID: ${tmdbId}, IMDB ID: ${imdbId}`); + // Get preferred language directly from settings + const preferredTmdbLanguage = settings.tmdbLanguagePreference || 'en'; + // Get TMDB logo and banner try { const apiKey = TMDB_API_KEY; @@ -451,15 +417,15 @@ const LogoSourceSettings = () => { // Find initial logo (prefer selectedTmdbLanguage, then 'en') let initialLogoPath: string | null = null; - let initialLanguage = selectedTmdbLanguage; + let initialLanguage = preferredTmdbLanguage; // First try to find a logo in the user's preferred language - const preferredLogo = imagesData.logos.find((logo: { iso_639_1: string; file_path: string }) => logo.iso_639_1 === selectedTmdbLanguage); + const preferredLogo = imagesData.logos.find((logo: { iso_639_1: string; file_path: string }) => logo.iso_639_1 === preferredTmdbLanguage); if (preferredLogo) { initialLogoPath = preferredLogo.file_path; - initialLanguage = selectedTmdbLanguage; - logger.log(`[LogoSourceSettings] Found initial ${selectedTmdbLanguage} TMDB logo for ${show.name}`); + initialLanguage = preferredTmdbLanguage; + logger.log(`[LogoSourceSettings] Found initial ${preferredTmdbLanguage} TMDB logo for ${show.name}`); } else { // Fallback to English logo const englishLogo = imagesData.logos.find((logo: { iso_639_1: string; file_path: string }) => logo.iso_639_1 === 'en'); @@ -478,7 +444,6 @@ const LogoSourceSettings = () => { if (initialLogoPath) { setTmdbLogo(`https://image.tmdb.org/t/p/original${initialLogoPath}`); - setSelectedTmdbLanguage(initialLanguage); // Set selected language based on found logo } else { logger.warn(`[LogoSourceSettings] No valid initial TMDB logo found for ${show.name}`); } @@ -588,9 +553,6 @@ const LogoSourceSettings = () => { // Handle TMDB language selection const handleTmdbLanguageSelect = (languageCode: string) => { - // First set local state for immediate UI updates - setSelectedTmdbLanguage(languageCode); - // Update the preview logo if possible if (tmdbLogosData) { const selectedLogoData = tmdbLogosData.find(logo => logo.iso_639_1 === languageCode); @@ -606,6 +568,9 @@ const LogoSourceSettings = () => { saveLanguagePreference(languageCode); }; + // Get preferred language directly from settings for UI rendering + const preferredTmdbLanguage = settings.tmdbLanguagePreference || 'en'; + // Save language preference with proper persistence const saveLanguagePreference = async (languageCode: string) => { logger.log(`[LogoSourceSettings] Saving TMDB language preference: ${languageCode}`); @@ -614,34 +579,6 @@ const LogoSourceSettings = () => { // First use the settings hook to update the setting - this is crucial updateSetting('tmdbLanguagePreference', languageCode); - // For extra assurance, also save directly to AsyncStorage - // Get current settings from AsyncStorage - const settingsJson = await AsyncStorage.getItem('app_settings'); - - if (settingsJson) { - const currentSettings = JSON.parse(settingsJson); - - // Update the language preference - const updatedSettings = { - ...currentSettings, - tmdbLanguagePreference: languageCode - }; - - // Save back to AsyncStorage using await to ensure it completes - await AsyncStorage.setItem('app_settings', JSON.stringify(updatedSettings)); - logger.log(`[LogoSourceSettings] Successfully saved TMDB language preference '${languageCode}' to AsyncStorage`); - } else { - // If no settings exist yet, create new settings object with this preference - const newSettings = { - ...DEFAULT_SETTINGS, - tmdbLanguagePreference: languageCode - }; - - // Save to AsyncStorage - await AsyncStorage.setItem('app_settings', JSON.stringify(newSettings)); - logger.log(`[LogoSourceSettings] Created new settings with TMDB language preference '${languageCode}'`); - } - // Clear any cached logo data await AsyncStorage.removeItem('_last_logos_'); @@ -875,7 +812,7 @@ const LogoSourceSettings = () => { key={langCode} // Use the unique code as key style={[ styles.languageItem, - selectedTmdbLanguage === langCode && styles.selectedLanguageItem + preferredTmdbLanguage === langCode && styles.selectedLanguageItem ]} onPress={() => handleTmdbLanguageSelect(langCode)} activeOpacity={0.7} @@ -884,7 +821,7 @@ const LogoSourceSettings = () => { {(langCode || '').toUpperCase() || '??'}