Refactor FeaturedContent and RatingsSection components to enhance logging and error handling

This update removes unnecessary logging statements from the FeaturedContent and RatingsSection components, streamlining the code for better readability. Additionally, it improves error handling by ensuring fallback logos are set appropriately when fetching fails. The useMetadataAssets hook is also optimized for logo and banner fetching, incorporating clearer conditions for asset retrieval based on user preferences. Overall, these changes enhance the maintainability and performance of the components.
This commit is contained in:
tapframe 2025-05-04 01:03:38 +05:30
parent b8484e432f
commit 190c1a7371
4 changed files with 230 additions and 195 deletions

View file

@ -91,22 +91,18 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat
try { try {
const isValid = await isValidMetahubLogo(url); const isValid = await isValidMetahubLogo(url);
if (!isValid) { if (!isValid) {
console.warn(`[FeaturedContent] Metahub logo validation failed: ${url}`);
return false; return false;
} }
} catch (validationError) { } catch (validationError) {
// If validation fails, still try to load the image // If validation fails, still try to load the image
console.warn(`[FeaturedContent] Logo validation error, will try to load anyway: ${url}`, validationError);
} }
} }
// Always attempt to prefetch the image regardless of format validation // Always attempt to prefetch the image regardless of format validation
await ExpoImage.prefetch(url); await ExpoImage.prefetch(url);
imageCache[url] = true; imageCache[url] = true;
console.log(`[FeaturedContent] Successfully preloaded image: ${url}`);
return true; return true;
} catch (error) { } catch (error) {
console.error('[FeaturedContent] Error preloading image:', error);
return false; return false;
} }
}; };
@ -146,8 +142,6 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat
} }
} }
logger.log(`[FeaturedContent] Fetching logo with preference: ${logoPreference}, language: ${preferredLanguage}, ID: ${contentId}`);
// Extract IMDB ID if available // Extract IMDB ID if available
let imdbId = null; let imdbId = null;
if (featuredContent.id.startsWith('tt')) { if (featuredContent.id.startsWith('tt')) {
@ -172,13 +166,12 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat
try { try {
const response = await fetch(metahubUrl, { method: 'HEAD' }); const response = await fetch(metahubUrl, { method: 'HEAD' });
if (response.ok) { if (response.ok) {
logger.log(`[FeaturedContent] Using Metahub logo: ${metahubUrl}`);
setLogoUrl(metahubUrl); setLogoUrl(metahubUrl);
logoFetchInProgress.current = false; logoFetchInProgress.current = false;
return; // Exit if Metahub logo was found return; // Exit if Metahub logo was found
} }
} catch (error) { } catch (error) {
logger.warn(`[FeaturedContent] Failed to fetch Metahub logo:`, error); // Removed logger.warn
} }
// Fall back to TMDB if Metahub fails and we have a TMDB ID // Fall back to TMDB if Metahub fails and we have a TMDB ID
@ -189,14 +182,13 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat
const logoUrl = await tmdbService.getContentLogo(tmdbType, tmdbId, preferredLanguage); const logoUrl = await tmdbService.getContentLogo(tmdbType, tmdbId, preferredLanguage);
if (logoUrl) { if (logoUrl) {
logger.log(`[FeaturedContent] Using fallback TMDB logo (${preferredLanguage}): ${logoUrl}`);
setLogoUrl(logoUrl); setLogoUrl(logoUrl);
} else if (currentLogo) { } else if (currentLogo) {
// If TMDB fails too, use existing logo if any // If TMDB fails too, use existing logo if any
setLogoUrl(currentLogo); setLogoUrl(currentLogo);
} }
} catch (error) { } catch (error) {
logger.error('[FeaturedContent] Error fetching TMDB logo:', error); // Removed logger.error
if (currentLogo) setLogoUrl(currentLogo); if (currentLogo) setLogoUrl(currentLogo);
} }
} else if (currentLogo) { } else if (currentLogo) {
@ -212,13 +204,12 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat
const logoUrl = await tmdbService.getContentLogo(tmdbType, tmdbId, preferredLanguage); const logoUrl = await tmdbService.getContentLogo(tmdbType, tmdbId, preferredLanguage);
if (logoUrl) { if (logoUrl) {
logger.log(`[FeaturedContent] Using TMDB logo (${preferredLanguage}): ${logoUrl}`);
setLogoUrl(logoUrl); setLogoUrl(logoUrl);
logoFetchInProgress.current = false; logoFetchInProgress.current = false;
return; // Exit if TMDB logo was found return; // Exit if TMDB logo was found
} }
} catch (error) { } catch (error) {
logger.error('[FeaturedContent] Error fetching TMDB logo:', error); // Removed logger.error
} }
} else if (imdbId) { } else if (imdbId) {
// If we have IMDB ID but no TMDB ID, try to find TMDB ID // If we have IMDB ID but no TMDB ID, try to find TMDB ID
@ -231,14 +222,13 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat
const logoUrl = await tmdbService.getContentLogo(tmdbType, foundTmdbId.toString(), preferredLanguage); const logoUrl = await tmdbService.getContentLogo(tmdbType, foundTmdbId.toString(), preferredLanguage);
if (logoUrl) { if (logoUrl) {
logger.log(`[FeaturedContent] Using TMDB logo (${preferredLanguage}) via IMDB lookup: ${logoUrl}`);
setLogoUrl(logoUrl); setLogoUrl(logoUrl);
logoFetchInProgress.current = false; logoFetchInProgress.current = false;
return; // Exit if TMDB logo was found return; // Exit if TMDB logo was found
} }
} }
} catch (error) { } catch (error) {
logger.error('[FeaturedContent] Error finding TMDB ID from IMDB:', error); // Removed logger.error
} }
} }
@ -249,14 +239,13 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat
try { try {
const response = await fetch(metahubUrl, { method: 'HEAD' }); const response = await fetch(metahubUrl, { method: 'HEAD' });
if (response.ok) { if (response.ok) {
logger.log(`[FeaturedContent] Using fallback Metahub logo: ${metahubUrl}`);
setLogoUrl(metahubUrl); setLogoUrl(metahubUrl);
} else if (currentLogo) { } else if (currentLogo) {
// If Metahub fails too, use existing logo if any // If Metahub fails too, use existing logo if any
setLogoUrl(currentLogo); setLogoUrl(currentLogo);
} }
} catch (error) { } catch (error) {
logger.warn(`[FeaturedContent] Failed to fetch fallback Metahub logo:`, error); // Removed logger.warn
if (currentLogo) setLogoUrl(currentLogo); if (currentLogo) setLogoUrl(currentLogo);
} }
} else if (currentLogo) { } else if (currentLogo) {
@ -265,10 +254,10 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat
} }
} }
} catch (error) { } catch (error) {
logger.error('[FeaturedContent] Error fetching logo:', error); // Removed logger.error
if (featuredContent?.logo) setLogoUrl(featuredContent.logo); // Optionally set a fallback logo or handle the error state
setLogoUrl(featuredContent.logo ?? null); // Fallback to initial logo or null
} finally { } finally {
// Clear fetch in progress flag
logoFetchInProgress.current = false; logoFetchInProgress.current = false;
} }
}; };

View file

@ -2,9 +2,6 @@ import React, { useEffect, useState, useRef } from 'react';
import { View, Text, StyleSheet, ActivityIndicator, Image, Animated } from 'react-native'; import { View, Text, StyleSheet, ActivityIndicator, Image, Animated } from 'react-native';
import { colors } from '../../styles/colors'; import { colors } from '../../styles/colors';
import { useMDBListRatings } from '../../hooks/useMDBListRatings'; import { useMDBListRatings } from '../../hooks/useMDBListRatings';
import { logger } from '../../utils/logger';
import { MaterialIcons } from '@expo/vector-icons';
import { FontAwesome } from '@expo/vector-icons';
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import { isMDBListEnabled, RATING_PROVIDERS_STORAGE_KEY } from '../../screens/MDBListSettingsScreen'; import { isMDBListEnabled, RATING_PROVIDERS_STORAGE_KEY } from '../../screens/MDBListSettingsScreen';
@ -67,9 +64,7 @@ export const RatingsSection: React.FC<RatingsSectionProps> = ({ imdbId, type })
try { try {
const enabled = await isMDBListEnabled(); const enabled = await isMDBListEnabled();
setIsMDBEnabled(enabled); setIsMDBEnabled(enabled);
logger.log('[RatingsSection] MDBList enabled:', enabled);
} catch (error) { } catch (error) {
logger.error('[RatingsSection] Failed to check if MDBList is enabled:', error);
setIsMDBEnabled(true); // Default to enabled setIsMDBEnabled(true); // Default to enabled
} }
}; };
@ -88,26 +83,21 @@ export const RatingsSection: React.FC<RatingsSectionProps> = ({ imdbId, type })
setEnabledProviders(defaultSettings); setEnabledProviders(defaultSettings);
} }
} catch (error) { } catch (error) {
logger.error('[RatingsSection] Failed to load provider settings:', error);
} }
}; };
useEffect(() => { useEffect(() => {
logger.log(`[RatingsSection] Mounted for ${type}:`, imdbId);
return () => { return () => {
logger.log(`[RatingsSection] Unmounted for ${type}:`, imdbId);
}; };
}, [imdbId, type]); }, [imdbId, type]);
useEffect(() => { useEffect(() => {
if (error) { if (error) {
logger.error('[RatingsSection] Error state:', error);
} }
}, [error]); }, [error]);
useEffect(() => { useEffect(() => {
if (ratings) { if (ratings) {
logger.log('[RatingsSection] Received ratings:', ratings);
} }
}, [ratings]); }, [ratings]);
@ -124,12 +114,10 @@ export const RatingsSection: React.FC<RatingsSectionProps> = ({ imdbId, type })
// If MDBList is disabled, don't show anything // If MDBList is disabled, don't show anything
if (!isMDBEnabled) { if (!isMDBEnabled) {
logger.log('[RatingsSection] MDBList is disabled, not showing ratings');
return null; return null;
} }
if (loading) { if (loading) {
logger.log('[RatingsSection] Loading state');
return ( return (
<View style={styles.loadingContainer}> <View style={styles.loadingContainer}>
<ActivityIndicator size="small" color={colors.primary} /> <ActivityIndicator size="small" color={colors.primary} />
@ -138,12 +126,9 @@ export const RatingsSection: React.FC<RatingsSectionProps> = ({ imdbId, type })
} }
if (error || !ratings || Object.keys(ratings).length === 0) { if (error || !ratings || Object.keys(ratings).length === 0) {
logger.log('[RatingsSection] No ratings to display');
return null; return null;
} }
logger.log('[RatingsSection] Rendering ratings:', Object.keys(ratings).length);
// Define the order and icons/colors for the ratings // Define the order and icons/colors for the ratings
const ratingConfig = { const ratingConfig = {
imdb: { imdb: {

View file

@ -61,47 +61,83 @@ export const useMetadataAssets = (
// Fetch logo immediately for TMDB content - with guard against recursive updates // Fetch logo immediately for TMDB content - with guard against recursive updates
useEffect(() => { useEffect(() => {
const logoPreference = settings.logoSourcePreference || 'metahub';
const currentLogoUrl = metadata?.logo;
let shouldFetchLogo = false;
// Determine if we need to fetch a new logo
if (!currentLogoUrl) {
logger.log(`[useMetadataAssets:Logo] Condition check: No current logo exists. Proceeding with fetch.`);
shouldFetchLogo = true;
} else {
const isCurrentLogoMetahub = isMetahubUrl(currentLogoUrl);
const isCurrentLogoTmdb = isTmdbUrl(currentLogoUrl);
if (logoPreference === 'tmdb' && !isCurrentLogoTmdb) {
logger.log(`[useMetadataAssets:Logo] Condition check: Preference is TMDB, but current logo is not TMDB (${currentLogoUrl}). Proceeding with fetch.`);
shouldFetchLogo = true;
} else if (logoPreference === 'metahub' && !isCurrentLogoMetahub) {
logger.log(`[useMetadataAssets:Logo] Condition check: Preference is Metahub, but current logo is not Metahub (${currentLogoUrl}). Proceeding with fetch.`);
shouldFetchLogo = true;
} else {
logger.log(`[useMetadataAssets:Logo] Condition check: Skipping fetch. Preference (${logoPreference}) matches existing logo source. Current logo: ${currentLogoUrl}`);
}
}
// Guard against infinite loops by checking if we're already fetching // Guard against infinite loops by checking if we're already fetching
if (metadata && !metadata.logo && !logoFetchInProgress.current) { if (shouldFetchLogo && !logoFetchInProgress.current) {
logger.log(`[useMetadataAssets:Logo] Starting logo fetch. Current metadata logo: ${currentLogoUrl}`);
logoFetchInProgress.current = true; logoFetchInProgress.current = true;
const fetchLogo = async () => { const fetchLogo = async () => {
// Clear existing logo before fetching new one to avoid briefly showing wrong logo
// Only do this if we decided to fetch because of a mismatch or non-existence
if (shouldFetchLogo) {
logger.log(`[useMetadataAssets:Logo] Clearing existing logo in metadata state before fetch.`);
setMetadata((prevMetadata: any) => ({ ...prevMetadata!, logo: undefined }));
}
try { try {
// Get logo source preference from settings // Get logo source preference from settings
const logoPreference = settings.logoSourcePreference || 'metahub'; // const logoPreference = settings.logoSourcePreference || 'metahub'; // Already defined above
const preferredLanguage = settings.tmdbLanguagePreference || 'en'; const preferredLanguage = settings.tmdbLanguagePreference || 'en';
logger.log(`[useMetadataAssets] Fetching logo with strict preference: ${logoPreference}`); logger.log(`[useMetadataAssets:Logo] Fetching logo. Preference: ${logoPreference}, Language: ${preferredLanguage}, IMDB ID: ${imdbId}`);
if (logoPreference === 'metahub' && imdbId) { if (logoPreference === 'metahub' && imdbId) {
// Metahub path - direct fetch without HEAD request for speed // Metahub path - direct fetch without HEAD request for speed
logger.log(`[useMetadataAssets:Logo] Preference is Metahub. Attempting Metahub fetch for ${imdbId}.`);
const metahubUrl = `https://images.metahub.space/logo/medium/${imdbId}/img`; const metahubUrl = `https://images.metahub.space/logo/medium/${imdbId}/img`;
try { try {
// Verify Metahub image exists to prevent showing broken images // Verify Metahub image exists to prevent showing broken images
logger.log(`[useMetadataAssets:Logo] Checking Metahub logo existence: ${metahubUrl}`);
const response = await fetch(metahubUrl, { method: 'HEAD' }); const response = await fetch(metahubUrl, { method: 'HEAD' });
if (response.ok) { if (response.ok) {
// Update metadata with Metahub logo // Update metadata with Metahub logo
setMetadata((prevMetadata: any) => ({ logger.log(`[useMetadataAssets:Logo] Metahub logo found. Updating metadata state.`);
...prevMetadata!, setMetadata((prevMetadata: any) => {
logo: metahubUrl logger.log(`[useMetadataAssets:Logo] setMetadata called with Metahub logo: ${metahubUrl}`);
})); return { ...prevMetadata!, logo: metahubUrl };
logger.log(`[useMetadataAssets] Set Metahub logo: ${metahubUrl}`); });
} else { } else {
logger.warn(`[useMetadataAssets] Metahub logo not found for ${imdbId}`); logger.warn(`[useMetadataAssets:Logo] Metahub logo HEAD request failed with status ${response.status} for ${imdbId}`);
} }
} catch (error) { } catch (error) {
logger.error(`[useMetadataAssets] Error checking Metahub logo:`, error); logger.error(`[useMetadataAssets:Logo] Error checking Metahub logo:`, error);
} }
} else if (logoPreference === 'tmdb') { } else if (logoPreference === 'tmdb') {
// TMDB path - optimized flow // TMDB path - optimized flow
logger.log(`[useMetadataAssets:Logo] Preference is TMDB. Attempting TMDB fetch.`);
let tmdbId: string | null = null; let tmdbId: string | null = null;
let contentType = type === 'series' ? 'tv' : 'movie'; let contentType = type === 'series' ? 'tv' : 'movie';
// Extract or find TMDB ID in one step // Extract or find TMDB ID in one step
if (id.startsWith('tmdb:')) { if (id.startsWith('tmdb:')) {
tmdbId = id.split(':')[1]; tmdbId = id.split(':')[1];
logger.log(`[useMetadataAssets:Logo] Extracted TMDB ID from route ID: ${tmdbId}`);
} else if (imdbId) { } else if (imdbId) {
logger.log(`[useMetadataAssets:Logo] Attempting to find TMDB ID from IMDB ID: ${imdbId}`);
// Only look up TMDB ID if we don't already have it // Only look up TMDB ID if we don't already have it
try { try {
const tmdbService = TMDBService.getInstance(); const tmdbService = TMDBService.getInstance();
@ -109,33 +145,46 @@ export const useMetadataAssets = (
if (foundId) { if (foundId) {
tmdbId = String(foundId); tmdbId = String(foundId);
setFoundTmdbId(tmdbId); // Save for banner fetching setFoundTmdbId(tmdbId); // Save for banner fetching
logger.log(`[useMetadataAssets:Logo] Found TMDB ID: ${tmdbId}`);
} else {
logger.warn(`[useMetadataAssets:Logo] Could not find TMDB ID for IMDB ID: ${imdbId}`);
} }
} catch (error) { } catch (error) {
logger.error(`[useMetadataAssets] Error finding TMDB ID:`, error); logger.error(`[useMetadataAssets:Logo] Error finding TMDB ID:`, error);
} }
} else {
logger.warn(`[useMetadataAssets:Logo] Cannot attempt TMDB fetch: No TMDB ID in route and no IMDB ID provided.`);
} }
if (tmdbId) { if (tmdbId) {
try { try {
// Direct fetch - avoid multiple service calls // Direct fetch - avoid multiple service calls
logger.log(`[useMetadataAssets:Logo] Fetching TMDB logo for ${contentType} ID: ${tmdbId}, Language: ${preferredLanguage}`);
const tmdbService = TMDBService.getInstance(); const tmdbService = TMDBService.getInstance();
const logoUrl = await tmdbService.getContentLogo(contentType as 'tv' | 'movie', tmdbId, preferredLanguage); const logoUrl = await tmdbService.getContentLogo(contentType as 'tv' | 'movie', tmdbId, preferredLanguage);
if (logoUrl) { if (logoUrl) {
setMetadata((prevMetadata: any) => ({ logger.log(`[useMetadataAssets:Logo] TMDB logo found. Updating metadata state.`);
...prevMetadata!, setMetadata((prevMetadata: any) => {
logo: logoUrl logger.log(`[useMetadataAssets:Logo] setMetadata called with TMDB logo: ${logoUrl}`);
})); return { ...prevMetadata!, logo: logoUrl };
logger.log(`[useMetadataAssets] Set TMDB logo: ${logoUrl}`); });
} else {
logger.warn(`[useMetadataAssets:Logo] No TMDB logo found for ${contentType}/${tmdbId}.`);
} }
} catch (error) { } catch (error) {
logger.error(`[useMetadataAssets] Error fetching TMDB logo:`, error); logger.error(`[useMetadataAssets:Logo] Error fetching TMDB logo:`, error);
} }
} else {
logger.warn(`[useMetadataAssets:Logo] Skipping TMDB logo fetch as no TMDB ID was determined.`);
} }
} else {
logger.log(`[useMetadataAssets:Logo] Preference not Metahub and no IMDB ID, or preference not TMDB. No logo fetched.`);
} }
} catch (error) { } catch (error) {
logger.error(`[useMetadataAssets] Error in fetchLogo:`, error); logger.error(`[useMetadataAssets:Logo] Error in outer fetchLogo try block:`, error);
} finally { } finally {
logger.log(`[useMetadataAssets:Logo] Finished logo fetch attempt.`);
logoFetchInProgress.current = false; logoFetchInProgress.current = false;
} }
}; };
@ -143,22 +192,37 @@ export const useMetadataAssets = (
// Execute fetch without awaiting // Execute fetch without awaiting
fetchLogo(); fetchLogo();
} }
}, [id, type, metadata, setMetadata, imdbId, settings.logoSourcePreference]); // Add logging for when fetch is skipped due to already fetching
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
// Fetch banner image based on logo source preference - optimized version // Fetch banner image based on logo source preference - optimized version
useEffect(() => { useEffect(() => {
// Skip if no metadata or already completed with the correct source // Skip if no metadata or already completed with the correct source
if (!metadata) return; if (!metadata) {
logger.log(`[useMetadataAssets:Banner] Skipping banner fetch: No metadata.`);
return;
}
// Check if we need to refresh the banner based on source // Check if we need to refresh the banner based on source
const currentPreference = settings.logoSourcePreference || 'metahub'; const currentPreference = settings.logoSourcePreference || 'metahub';
logger.log(`[useMetadataAssets:Banner] Checking banner fetch. Preference: ${currentPreference}, Current Banner Source: ${bannerSource}, Forced Refresh Done: ${forcedBannerRefreshDone.current}`);
if (bannerSource === currentPreference && forcedBannerRefreshDone.current) { if (bannerSource === currentPreference && forcedBannerRefreshDone.current) {
logger.log(`[useMetadataAssets:Banner] Skipping fetch: Banner already loaded with correct source (${currentPreference}).`);
return; // Already have the correct source, no need to refresh return; // Already have the correct source, no need to refresh
} }
const fetchBanner = async () => { const fetchBanner = async () => {
logger.log(`[useMetadataAssets:Banner] Starting banner fetch.`);
setLoadingBanner(true); setLoadingBanner(true);
setBannerImage(null); // Clear existing banner to prevent mixed sources setBannerImage(null); // Clear existing banner to prevent mixed sources
setBannerSource(null); // Clear source tracking
let finalBanner: string | null = null;
let bannerSourceType: 'tmdb' | 'metahub' | 'default' = 'default';
try { try {
// Extract all possible IDs at once // Extract all possible IDs at once
@ -173,20 +237,36 @@ export const useMetadataAssets = (
tmdbId = foundTmdbId; tmdbId = foundTmdbId;
} else if ((metadata as any).tmdbId) { } else if ((metadata as any).tmdbId) {
tmdbId = (metadata as any).tmdbId; tmdbId = (metadata as any).tmdbId;
} else if (imdbId) {
// Last attempt: Look up TMDB ID if we haven't yet
logger.log(`[useMetadataAssets:Banner] Attempting TMDB ID lookup from IMDB ID: ${imdbId} for banner fetch.`);
try {
const tmdbService = TMDBService.getInstance();
const foundId = await tmdbService.findTMDBIdByIMDB(imdbId);
if (foundId) {
tmdbId = String(foundId);
logger.log(`[useMetadataAssets:Banner] Found TMDB ID: ${tmdbId}`);
} else {
logger.warn(`[useMetadataAssets:Banner] Could not find TMDB ID for IMDB ID: ${imdbId}`);
}
} catch (lookupError) {
logger.error(`[useMetadataAssets:Banner] Error looking up TMDB ID:`, lookupError);
}
} }
logger.log(`[useMetadataAssets:Banner] Determined TMDB ID for banner fetch: ${tmdbId}`);
// Default fallback to use if nothing else works // Default fallback to use if nothing else works
let finalBanner: string | null = null;
let bannerSourceType: 'tmdb' | 'metahub' | 'default' = 'default';
if (currentPreference === 'tmdb' && tmdbId) { if (currentPreference === 'tmdb' && tmdbId) {
// TMDB direct path // TMDB direct path
const endpoint = contentType === 'tv' ? 'tv' : 'movie'; logger.log(`[useMetadataAssets:Banner] Preference is TMDB. Attempting TMDB banner fetch for ${contentType}/${tmdbId}.`);
const endpoint = contentType === 'tv' ? 'tv' : 'movie';
try { try {
// Use TMDBService instead of direct fetch with hardcoded API key // Use TMDBService instead of direct fetch with hardcoded API key
const tmdbService = TMDBService.getInstance(); const tmdbService = TMDBService.getInstance();
logger.log(`[useMetadataAssets] Fetching TMDB details for ${endpoint}/${tmdbId}`); logger.log(`[useMetadataAssets:Banner] Fetching TMDB details for ${endpoint}/${tmdbId}`);
try { try {
// Get details with backdrop path using TMDBService // Get details with backdrop path using TMDBService
@ -196,111 +276,161 @@ export const useMetadataAssets = (
// Step 1: Get basic details // Step 1: Get basic details
if (endpoint === 'movie') { if (endpoint === 'movie') {
details = await tmdbService.getMovieDetails(tmdbId); details = await tmdbService.getMovieDetails(tmdbId);
logger.log(`[useMetadataAssets:Banner] TMDB getMovieDetails result:`, details ? `Found backdrop: ${!!details.backdrop_path}, Found poster: ${!!details.poster_path}` : 'null');
// Step 2: Get images separately if details succeeded // Step 2: Get images separately if details succeeded (This call might not be needed for banner)
if (details) { // if (details) {
try { // try {
// Use getMovieImages to get image data - this returns a logo URL but we need more // await tmdbService.getMovieImages(tmdbId, preferredLanguage);
await tmdbService.getMovieImages(tmdbId, preferredLanguage); // logger.log(`[useMetadataAssets:Banner] Got movie images for ${tmdbId}`);
// } catch (imageError) {
// We'll use the backdrop from the details // logger.warn(`[useMetadataAssets:Banner] Could not get movie images: ${imageError}`);
logger.log(`[useMetadataAssets] Got movie details for ${tmdbId}`); // }
} catch (imageError) { //}
logger.warn(`[useMetadataAssets] Could not get movie images: ${imageError}`); } else { // TV Show
}
}
} else {
details = await tmdbService.getTVShowDetails(Number(tmdbId)); details = await tmdbService.getTVShowDetails(Number(tmdbId));
logger.log(`[useMetadataAssets:Banner] TMDB getTVShowDetails result:`, details ? `Found backdrop: ${!!details.backdrop_path}, Found poster: ${!!details.poster_path}` : 'null');
// Step 2: Get images separately if details succeeded // Step 2: Get images separately if details succeeded (This call might not be needed for banner)
if (details) { // if (details) {
try { // try {
// Use getTvShowImages to get image data - this returns a logo URL but we need more // await tmdbService.getTvShowImages(tmdbId, preferredLanguage);
await tmdbService.getTvShowImages(tmdbId, preferredLanguage); // logger.log(`[useMetadataAssets:Banner] Got TV images for ${tmdbId}`);
// } catch (imageError) {
// We'll use the backdrop from the details // logger.warn(`[useMetadataAssets:Banner] Could not get TV images: ${imageError}`);
logger.log(`[useMetadataAssets] Got TV details for ${tmdbId}`); // }
} catch (imageError) { // }
logger.warn(`[useMetadataAssets] Could not get TV images: ${imageError}`);
}
}
} }
// Check if we have a backdrop path from details // Check if we have a backdrop path from details
if (details && details.backdrop_path) { if (details && details.backdrop_path) {
finalBanner = tmdbService.getImageUrl(details.backdrop_path); finalBanner = tmdbService.getImageUrl(details.backdrop_path);
bannerSourceType = 'tmdb'; bannerSourceType = 'tmdb';
logger.log(`[useMetadataAssets] Using TMDB backdrop from details: ${finalBanner}`); logger.log(`[useMetadataAssets:Banner] Using TMDB backdrop from details: ${finalBanner}`);
} }
// If no backdrop, try poster as fallback // If no backdrop, try poster as fallback
else if (details && details.poster_path) { else if (details && details.poster_path) {
logger.warn(`[useMetadataAssets] No backdrop available, using poster as fallback`); logger.warn(`[useMetadataAssets:Banner] No TMDB backdrop available, using poster as fallback.`);
finalBanner = tmdbService.getImageUrl(details.poster_path); finalBanner = tmdbService.getImageUrl(details.poster_path);
bannerSourceType = 'tmdb'; bannerSourceType = 'tmdb';
} }
else { else {
logger.warn(`[useMetadataAssets] No backdrop or poster found for ${endpoint}/${tmdbId}`); logger.warn(`[useMetadataAssets:Banner] No TMDB backdrop or poster found for ${endpoint}/${tmdbId}. TMDB path failed.`);
// Explicitly set finalBanner to null if TMDB fails
finalBanner = null;
} }
} catch (innerErr) { } catch (innerErr) {
logger.error(`[useMetadataAssets] Error fetching TMDB details/images:`, innerErr); logger.error(`[useMetadataAssets:Banner] Error fetching TMDB details/images:`, innerErr);
} finalBanner = null; // Ensure failure case nullifies banner
} catch (err) {
logger.error(`[useMetadataAssets] TMDB service initialization error:`, err);
} }
} catch (err) {
logger.error(`[useMetadataAssets:Banner] TMDB service initialization error:`, err);
finalBanner = null; // Ensure failure case nullifies banner
}
} else if (currentPreference === 'metahub' && imdbId) { } else if (currentPreference === 'metahub' && imdbId) {
// Metahub path - verify it exists to prevent broken images // Metahub path - verify it exists to prevent broken images
logger.log(`[useMetadataAssets:Banner] Preference is Metahub. Attempting Metahub banner fetch for ${imdbId}.`);
const metahubUrl = `https://images.metahub.space/background/medium/${imdbId}/img`; const metahubUrl = `https://images.metahub.space/background/medium/${imdbId}/img`;
try { try {
logger.log(`[useMetadataAssets:Banner] Checking Metahub banner existence: ${metahubUrl}`);
const response = await fetch(metahubUrl, { method: 'HEAD' }); const response = await fetch(metahubUrl, { method: 'HEAD' });
if (response.ok) { if (response.ok) {
finalBanner = metahubUrl; finalBanner = metahubUrl;
bannerSourceType = 'metahub'; bannerSourceType = 'metahub';
logger.log(`[useMetadataAssets] Using Metahub banner: ${finalBanner}`); logger.log(`[useMetadataAssets:Banner] Metahub banner found: ${finalBanner}`);
} else { } else {
logger.warn(`[useMetadataAssets] Metahub banner not found, using default`); logger.warn(`[useMetadataAssets:Banner] Metahub banner HEAD request failed with status ${response.status}, using default.`);
finalBanner = null; // Ensure fallback if Metahub fails
} }
} catch (error) { } catch (error) {
logger.error(`[useMetadataAssets] Error checking Metahub banner:`, error); logger.error(`[useMetadataAssets:Banner] Error checking Metahub banner:`, error);
finalBanner = null; // Ensure fallback if Metahub errors
} }
} else {
// This case handles:
// 1. Preference is TMDB but no tmdbId could be found.
// 2. Preference is Metahub but no imdbId was provided.
logger.log(`[useMetadataAssets:Banner] Skipping direct fetch: Preference=${currentPreference}, tmdbId=${tmdbId}, imdbId=${imdbId}. Will rely on default/fallback.`);
finalBanner = null; // Explicitly nullify banner if preference conditions aren't met
} }
// If no source-specific banner was found, use default // Fallback logic if preferred source failed or wasn't attempted
if (!finalBanner) { if (!finalBanner) {
finalBanner = metadata.banner || metadata.poster; logger.log(`[useMetadataAssets:Banner] Preferred source (${currentPreference}) did not yield a banner. Checking fallbacks.`);
bannerSourceType = 'default'; // Fallback 1: Try the *other* source if the preferred one failed
logger.log(`[useMetadataAssets] Using default banner: ${finalBanner}`); if (currentPreference === 'tmdb' && imdbId) { // If preferred was TMDB, try Metahub
} logger.log(`[useMetadataAssets:Banner] Fallback: Trying Metahub for ${imdbId}.`);
const metahubUrl = `https://images.metahub.space/background/medium/${imdbId}/img`;
try {
const response = await fetch(metahubUrl, { method: 'HEAD' });
if (response.ok) {
finalBanner = metahubUrl;
bannerSourceType = 'metahub';
logger.log(`[useMetadataAssets:Banner] Fallback Metahub banner found: ${finalBanner}`);
} else {
logger.warn(`[useMetadataAssets:Banner] Fallback Metahub HEAD failed: ${response.status}`);
}
} catch (fallbackError) {
logger.error(`[useMetadataAssets:Banner] Fallback Metahub check error:`, fallbackError);
}
} else if (currentPreference === 'metahub' && tmdbId) { // If preferred was Metahub, try TMDB
logger.log(`[useMetadataAssets:Banner] Fallback: Trying TMDB for ${contentType}/${tmdbId}.`);
const endpoint = contentType === 'tv' ? 'tv' : 'movie';
try {
const tmdbService = TMDBService.getInstance();
let details = endpoint === 'movie' ? await tmdbService.getMovieDetails(tmdbId) : await tmdbService.getTVShowDetails(Number(tmdbId));
if (details?.backdrop_path) {
finalBanner = tmdbService.getImageUrl(details.backdrop_path);
bannerSourceType = 'tmdb';
logger.log(`[useMetadataAssets:Banner] Fallback TMDB banner found (backdrop): ${finalBanner}`);
} else if (details?.poster_path) {
finalBanner = tmdbService.getImageUrl(details.poster_path);
bannerSourceType = 'tmdb';
logger.log(`[useMetadataAssets:Banner] Fallback TMDB banner found (poster): ${finalBanner}`);
} else {
logger.warn(`[useMetadataAssets:Banner] Fallback TMDB fetch found no backdrop or poster.`);
}
} catch (fallbackError) {
logger.error(`[useMetadataAssets:Banner] Fallback TMDB check error:`, fallbackError);
}
}
// Set banner image once at the end // Fallback 2: Use metadata banner/poster if other source also failed
setBannerImage(finalBanner); if (!finalBanner) {
setBannerSource(bannerSourceType); logger.log(`[useMetadataAssets:Banner] Fallback source also failed or not applicable. Using metadata.banner or metadata.poster.`);
finalBanner = metadata?.banner || metadata?.poster || null;
bannerSourceType = 'default';
if (finalBanner) {
logger.log(`[useMetadataAssets:Banner] Using default banner from metadata: ${finalBanner}`);
} else {
logger.warn(`[useMetadataAssets:Banner] No default banner found in metadata either.`);
}
}
}
} catch (error) { // Set the final state
logger.error(`[useMetadataAssets] Banner fetch error:`, error); logger.log(`[useMetadataAssets:Banner] Final decision: Setting banner to ${finalBanner} (Source: ${bannerSourceType})`);
// Use default banner if error occurred setBannerImage(finalBanner);
setBannerImage(metadata.banner || metadata.poster); setBannerSource(bannerSourceType); // Track the source of the final image
forcedBannerRefreshDone.current = true; // Mark this cycle as complete
} catch (error) {
logger.error(`[useMetadataAssets:Banner] Error in outer fetchBanner try block:`, error);
// Ensure fallback to default even on outer error
const defaultBanner = metadata?.banner || metadata?.poster || null;
setBannerImage(defaultBanner);
setBannerSource('default'); setBannerSource('default');
} finally { logger.log(`[useMetadataAssets:Banner] Setting default banner due to outer error: ${defaultBanner}`);
setLoadingBanner(false); } finally {
forcedBannerRefreshDone.current = true; logger.log(`[useMetadataAssets:Banner] Finished banner fetch attempt.`);
setLoadingBanner(false);
} }
}; };
fetchBanner(); fetchBanner();
}, [metadata, id, type, imdbId, settings.logoSourcePreference, foundTmdbId, bannerSource]);
// Original reset forced refresh effect }, [metadata, id, type, imdbId, settings.logoSourcePreference, settings.tmdbLanguagePreference, setMetadata, foundTmdbId, bannerSource]); // Added bannerSource dependency to re-evaluate if it changes unexpectedly
useEffect(() => {
if (forcedBannerRefreshDone.current) {
logger.log(`[useMetadataAssets] Logo preference changed, resetting banner refresh flag`);
forcedBannerRefreshDone.current = false;
// Clear the banner image immediately to prevent showing the wrong source briefly
setBannerImage(null);
setBannerSource(null);
// This will trigger the banner fetch effect to run again
}
}, [settings.logoSourcePreference]);
return { return {
bannerImage, bannerImage,

View file

@ -1,5 +1,4 @@
import axios from 'axios'; import axios from 'axios';
import { logger } from '../utils/logger';
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
// TMDB API configuration // TMDB API configuration
@ -100,15 +99,12 @@ export class TMDBService {
if (this.useCustomKey && savedKey) { if (this.useCustomKey && savedKey) {
this.apiKey = savedKey; this.apiKey = savedKey;
logger.log('Using custom TMDb API key');
} else { } else {
this.apiKey = DEFAULT_API_KEY; this.apiKey = DEFAULT_API_KEY;
logger.log('Using default TMDb API key');
} }
this.apiKeyLoaded = true; this.apiKeyLoaded = true;
} catch (error) { } catch (error) {
logger.error('Failed to load TMDb API key from storage, using default:', error);
this.apiKey = DEFAULT_API_KEY; this.apiKey = DEFAULT_API_KEY;
this.apiKeyLoaded = true; this.apiKeyLoaded = true;
} }
@ -157,7 +153,6 @@ export class TMDBService {
}); });
return response.data.results; return response.data.results;
} catch (error) { } catch (error) {
logger.error('Failed to search TV show:', error);
return []; return [];
} }
} }
@ -175,7 +170,6 @@ export class TMDBService {
}); });
return response.data; return response.data;
} catch (error) { } catch (error) {
logger.error('Failed to get TV show details:', error);
return null; return null;
} }
} }
@ -198,7 +192,6 @@ export class TMDBService {
); );
return response.data; return response.data;
} catch (error) { } catch (error) {
logger.error('Failed to get episode external IDs:', error);
return null; return null;
} }
} }
@ -234,7 +227,6 @@ export class TMDBService {
TMDBService.ratingCache.set(cacheKey, rating); TMDBService.ratingCache.set(cacheKey, rating);
return rating; return rating;
} catch (error) { } catch (error) {
logger.error('Failed to get IMDb rating:', error);
// Cache the failed result too to prevent repeated failed requests // Cache the failed result too to prevent repeated failed requests
TMDBService.ratingCache.set(cacheKey, null); TMDBService.ratingCache.set(cacheKey, null);
return null; return null;
@ -289,7 +281,6 @@ export class TMDBService {
return season; return season;
} catch (error) { } catch (error) {
logger.error('Failed to get season details:', error);
return null; return null;
} }
} }
@ -314,7 +305,6 @@ export class TMDBService {
); );
return response.data; return response.data;
} catch (error) { } catch (error) {
logger.error('Failed to get episode details:', error);
return null; return null;
} }
} }
@ -333,7 +323,6 @@ export class TMDBService {
const tmdbId = await this.findTMDBIdByIMDB(imdbId); const tmdbId = await this.findTMDBIdByIMDB(imdbId);
return tmdbId; return tmdbId;
} catch (error) { } catch (error) {
logger.error('Failed to extract TMDB ID from Stremio ID:', error);
return null; return null;
} }
} }
@ -366,7 +355,6 @@ export class TMDBService {
return null; return null;
} catch (error) { } catch (error) {
logger.error('Failed to find TMDB ID by IMDB ID:', error);
return null; return null;
} }
} }
@ -376,13 +364,11 @@ export class TMDBService {
*/ */
getImageUrl(path: string | null, size: 'original' | 'w500' | 'w300' | 'w185' | 'profile' = 'original'): string | null { getImageUrl(path: string | null, size: 'original' | 'w500' | 'w300' | 'w185' | 'profile' = 'original'): string | null {
if (!path) { if (!path) {
logger.warn(`[TMDBService] Cannot construct image URL from null path`);
return null; return null;
} }
const baseImageUrl = 'https://image.tmdb.org/t/p/'; const baseImageUrl = 'https://image.tmdb.org/t/p/';
const fullUrl = `${baseImageUrl}${size}${path}`; const fullUrl = `${baseImageUrl}${size}${path}`;
logger.log(`[TMDBService] Constructed image URL: ${fullUrl}`);
return fullUrl; return fullUrl;
} }
@ -411,7 +397,6 @@ export class TMDBService {
await Promise.all(seasonPromises); await Promise.all(seasonPromises);
return allEpisodes; return allEpisodes;
} catch (error) { } catch (error) {
logger.error('Failed to get all episodes:', error);
return {}; return {};
} }
} }
@ -472,7 +457,6 @@ export class TMDBService {
crew: response.data.crew || [] crew: response.data.crew || []
}; };
} catch (error) { } catch (error) {
logger.error('Failed to fetch credits:', error);
return { cast: [], crew: [] }; return { cast: [], crew: [] };
} }
} }
@ -487,7 +471,6 @@ export class TMDBService {
}); });
return response.data; return response.data;
} catch (error) { } catch (error) {
logger.error('Failed to fetch person details:', error);
return null; return null;
} }
} }
@ -506,14 +489,12 @@ export class TMDBService {
); );
return response.data; return response.data;
} catch (error) { } catch (error) {
logger.error('Failed to get show external IDs:', error);
return null; return null;
} }
} }
async getRecommendations(type: 'movie' | 'tv', tmdbId: string): Promise<any[]> { async getRecommendations(type: 'movie' | 'tv', tmdbId: string): Promise<any[]> {
if (!this.apiKey) { if (!this.apiKey) {
logger.error('TMDB API key not set');
return []; return [];
} }
try { try {
@ -523,7 +504,6 @@ export class TMDBService {
}); });
return response.data.results || []; return response.data.results || [];
} catch (error) { } catch (error) {
logger.error(`Error fetching TMDB ${type} recommendations for ID ${tmdbId}:`, error);
return []; return [];
} }
} }
@ -541,7 +521,6 @@ export class TMDBService {
}); });
return response.data.results; return response.data.results;
} catch (error) { } catch (error) {
logger.error('Failed to search multi:', error);
return []; return [];
} }
} }
@ -560,7 +539,6 @@ export class TMDBService {
}); });
return response.data; return response.data;
} catch (error) { } catch (error) {
logger.error('Failed to get movie details:', error);
return null; return null;
} }
} }
@ -570,8 +548,6 @@ export class TMDBService {
*/ */
async getMovieImages(movieId: number | string, preferredLanguage: string = 'en'): Promise<string | null> { async getMovieImages(movieId: number | string, preferredLanguage: string = 'en'): Promise<string | null> {
try { try {
logger.log(`[TMDBService] Fetching movie images for TMDB ID: ${movieId}, preferred language: ${preferredLanguage}`);
const response = await axios.get(`${BASE_URL}/movie/${movieId}/images`, { const response = await axios.get(`${BASE_URL}/movie/${movieId}/images`, {
headers: await this.getHeaders(), headers: await this.getHeaders(),
params: await this.getParams({ params: await this.getParams({
@ -580,7 +556,6 @@ export class TMDBService {
}); });
const images = response.data; const images = response.data;
logger.log(`[TMDBService] Retrieved ${images?.logos?.length || 0} logos for movie ID ${movieId}`);
if (images && images.logos && images.logos.length > 0) { if (images && images.logos && images.logos.length > 0) {
// First prioritize preferred language SVG logos if not English // First prioritize preferred language SVG logos if not English
@ -591,7 +566,6 @@ export class TMDBService {
logo.iso_639_1 === preferredLanguage logo.iso_639_1 === preferredLanguage
); );
if (preferredSvgLogo) { if (preferredSvgLogo) {
logger.log(`[TMDBService] Found ${preferredLanguage} SVG logo for movie ID ${movieId}: ${preferredSvgLogo.file_path}`);
return this.getImageUrl(preferredSvgLogo.file_path); return this.getImageUrl(preferredSvgLogo.file_path);
} }
@ -602,7 +576,6 @@ export class TMDBService {
logo.iso_639_1 === preferredLanguage logo.iso_639_1 === preferredLanguage
); );
if (preferredPngLogo) { if (preferredPngLogo) {
logger.log(`[TMDBService] Found ${preferredLanguage} PNG logo for movie ID ${movieId}: ${preferredPngLogo.file_path}`);
return this.getImageUrl(preferredPngLogo.file_path); return this.getImageUrl(preferredPngLogo.file_path);
} }
@ -611,7 +584,6 @@ export class TMDBService {
logo.iso_639_1 === preferredLanguage logo.iso_639_1 === preferredLanguage
); );
if (preferredLogo) { if (preferredLogo) {
logger.log(`[TMDBService] Found ${preferredLanguage} logo for movie ID ${movieId}: ${preferredLogo.file_path}`);
return this.getImageUrl(preferredLogo.file_path); return this.getImageUrl(preferredLogo.file_path);
} }
} }
@ -623,7 +595,6 @@ export class TMDBService {
logo.iso_639_1 === 'en' logo.iso_639_1 === 'en'
); );
if (enSvgLogo) { if (enSvgLogo) {
logger.log(`[TMDBService] Found English SVG logo for movie ID ${movieId}: ${enSvgLogo.file_path}`);
return this.getImageUrl(enSvgLogo.file_path); return this.getImageUrl(enSvgLogo.file_path);
} }
@ -634,7 +605,6 @@ export class TMDBService {
logo.iso_639_1 === 'en' logo.iso_639_1 === 'en'
); );
if (enPngLogo) { if (enPngLogo) {
logger.log(`[TMDBService] Found English PNG logo for movie ID ${movieId}: ${enPngLogo.file_path}`);
return this.getImageUrl(enPngLogo.file_path); return this.getImageUrl(enPngLogo.file_path);
} }
@ -643,7 +613,6 @@ export class TMDBService {
logo.iso_639_1 === 'en' logo.iso_639_1 === 'en'
); );
if (enLogo) { if (enLogo) {
logger.log(`[TMDBService] Found English logo for movie ID ${movieId}: ${enLogo.file_path}`);
return this.getImageUrl(enLogo.file_path); return this.getImageUrl(enLogo.file_path);
} }
@ -652,7 +621,6 @@ export class TMDBService {
logo.file_path && logo.file_path.endsWith('.svg') logo.file_path && logo.file_path.endsWith('.svg')
); );
if (svgLogo) { if (svgLogo) {
logger.log(`[TMDBService] Found SVG logo for movie ID ${movieId}: ${svgLogo.file_path}`);
return this.getImageUrl(svgLogo.file_path); return this.getImageUrl(svgLogo.file_path);
} }
@ -661,20 +629,15 @@ export class TMDBService {
logo.file_path && logo.file_path.endsWith('.png') logo.file_path && logo.file_path.endsWith('.png')
); );
if (pngLogo) { if (pngLogo) {
logger.log(`[TMDBService] Found PNG logo for movie ID ${movieId}: ${pngLogo.file_path}`);
return this.getImageUrl(pngLogo.file_path); return this.getImageUrl(pngLogo.file_path);
} }
// Last resort: any logo // Last resort: any logo
logger.log(`[TMDBService] Using first available logo for movie ID ${movieId}: ${images.logos[0].file_path}`);
return this.getImageUrl(images.logos[0].file_path); return this.getImageUrl(images.logos[0].file_path);
} }
logger.warn(`[TMDBService] No logos found for movie ID ${movieId}`);
return null; // No logos found return null; // No logos found
} catch (error) { } catch (error) {
// Log error but don't throw, just return null if fetching images fails
logger.error(`[TMDBService] Failed to get movie images for ID ${movieId}:`, error);
return null; return null;
} }
} }
@ -684,8 +647,6 @@ export class TMDBService {
*/ */
async getTvShowImages(showId: number | string, preferredLanguage: string = 'en'): Promise<string | null> { async getTvShowImages(showId: number | string, preferredLanguage: string = 'en'): Promise<string | null> {
try { try {
logger.log(`[TMDBService] Fetching TV show images for TMDB ID: ${showId}, preferred language: ${preferredLanguage}`);
const response = await axios.get(`${BASE_URL}/tv/${showId}/images`, { const response = await axios.get(`${BASE_URL}/tv/${showId}/images`, {
headers: await this.getHeaders(), headers: await this.getHeaders(),
params: await this.getParams({ params: await this.getParams({
@ -694,7 +655,6 @@ export class TMDBService {
}); });
const images = response.data; const images = response.data;
logger.log(`[TMDBService] Retrieved ${images?.logos?.length || 0} logos for TV show ID ${showId}`);
if (images && images.logos && images.logos.length > 0) { if (images && images.logos && images.logos.length > 0) {
// First prioritize preferred language SVG logos if not English // First prioritize preferred language SVG logos if not English
@ -705,7 +665,6 @@ export class TMDBService {
logo.iso_639_1 === preferredLanguage logo.iso_639_1 === preferredLanguage
); );
if (preferredSvgLogo) { if (preferredSvgLogo) {
logger.log(`[TMDBService] Found ${preferredLanguage} SVG logo for TV show ID ${showId}: ${preferredSvgLogo.file_path}`);
return this.getImageUrl(preferredSvgLogo.file_path); return this.getImageUrl(preferredSvgLogo.file_path);
} }
@ -716,7 +675,6 @@ export class TMDBService {
logo.iso_639_1 === preferredLanguage logo.iso_639_1 === preferredLanguage
); );
if (preferredPngLogo) { if (preferredPngLogo) {
logger.log(`[TMDBService] Found ${preferredLanguage} PNG logo for TV show ID ${showId}: ${preferredPngLogo.file_path}`);
return this.getImageUrl(preferredPngLogo.file_path); return this.getImageUrl(preferredPngLogo.file_path);
} }
@ -725,7 +683,6 @@ export class TMDBService {
logo.iso_639_1 === preferredLanguage logo.iso_639_1 === preferredLanguage
); );
if (preferredLogo) { if (preferredLogo) {
logger.log(`[TMDBService] Found ${preferredLanguage} logo for TV show ID ${showId}: ${preferredLogo.file_path}`);
return this.getImageUrl(preferredLogo.file_path); return this.getImageUrl(preferredLogo.file_path);
} }
} }
@ -737,7 +694,6 @@ export class TMDBService {
logo.iso_639_1 === 'en' logo.iso_639_1 === 'en'
); );
if (enSvgLogo) { if (enSvgLogo) {
logger.log(`[TMDBService] Found English SVG logo for TV show ID ${showId}: ${enSvgLogo.file_path}`);
return this.getImageUrl(enSvgLogo.file_path); return this.getImageUrl(enSvgLogo.file_path);
} }
@ -748,7 +704,6 @@ export class TMDBService {
logo.iso_639_1 === 'en' logo.iso_639_1 === 'en'
); );
if (enPngLogo) { if (enPngLogo) {
logger.log(`[TMDBService] Found English PNG logo for TV show ID ${showId}: ${enPngLogo.file_path}`);
return this.getImageUrl(enPngLogo.file_path); return this.getImageUrl(enPngLogo.file_path);
} }
@ -757,7 +712,6 @@ export class TMDBService {
logo.iso_639_1 === 'en' logo.iso_639_1 === 'en'
); );
if (enLogo) { if (enLogo) {
logger.log(`[TMDBService] Found English logo for TV show ID ${showId}: ${enLogo.file_path}`);
return this.getImageUrl(enLogo.file_path); return this.getImageUrl(enLogo.file_path);
} }
@ -766,7 +720,6 @@ export class TMDBService {
logo.file_path && logo.file_path.endsWith('.svg') logo.file_path && logo.file_path.endsWith('.svg')
); );
if (svgLogo) { if (svgLogo) {
logger.log(`[TMDBService] Found SVG logo for TV show ID ${showId}: ${svgLogo.file_path}`);
return this.getImageUrl(svgLogo.file_path); return this.getImageUrl(svgLogo.file_path);
} }
@ -775,20 +728,15 @@ export class TMDBService {
logo.file_path && logo.file_path.endsWith('.png') logo.file_path && logo.file_path.endsWith('.png')
); );
if (pngLogo) { if (pngLogo) {
logger.log(`[TMDBService] Found PNG logo for TV show ID ${showId}: ${pngLogo.file_path}`);
return this.getImageUrl(pngLogo.file_path); return this.getImageUrl(pngLogo.file_path);
} }
// Last resort: any logo // Last resort: any logo
logger.log(`[TMDBService] Using first available logo for TV show ID ${showId}: ${images.logos[0].file_path}`);
return this.getImageUrl(images.logos[0].file_path); return this.getImageUrl(images.logos[0].file_path);
} }
logger.warn(`[TMDBService] No logos found for TV show ID ${showId}`);
return null; // No logos found return null; // No logos found
} catch (error) { } catch (error) {
// Log error but don't throw, just return null if fetching images fails
logger.error(`[TMDBService] Failed to get TV show images for ID ${showId}:`, error);
return null; return null;
} }
} }
@ -798,21 +746,16 @@ export class TMDBService {
*/ */
async getContentLogo(type: 'movie' | 'tv', id: number | string, preferredLanguage: string = 'en'): Promise<string | null> { async getContentLogo(type: 'movie' | 'tv', id: number | string, preferredLanguage: string = 'en'): Promise<string | null> {
try { try {
logger.log(`[TMDBService] Getting content logo for ${type} with ID ${id}, preferred language: ${preferredLanguage}`);
const result = type === 'movie' const result = type === 'movie'
? await this.getMovieImages(id, preferredLanguage) ? await this.getMovieImages(id, preferredLanguage)
: await this.getTvShowImages(id, preferredLanguage); : await this.getTvShowImages(id, preferredLanguage);
if (result) { if (result) {
logger.log(`[TMDBService] Successfully retrieved logo for ${type} ID ${id}: ${result}`);
} else { } else {
logger.warn(`[TMDBService] No logo found for ${type} ID ${id}`);
} }
return result; return result;
} catch (error) { } catch (error) {
logger.error(`[TMDBService] Failed to get content logo for ${type} ID ${id}:`, error);
return null; return null;
} }
} }
@ -847,7 +790,6 @@ export class TMDBService {
} }
return null; return null;
} catch (error) { } catch (error) {
logger.error('Error fetching certification:', error);
return null; return null;
} }
} }
@ -883,7 +825,6 @@ export class TMDBService {
external_ids: externalIdsResponse.data external_ids: externalIdsResponse.data
}; };
} catch (error) { } catch (error) {
logger.error(`Failed to get external IDs for ${type} ${item.id}:`, error);
return item; return item;
} }
}) })
@ -891,7 +832,6 @@ export class TMDBService {
return resultsWithExternalIds; return resultsWithExternalIds;
} catch (error) { } catch (error) {
logger.error(`Failed to get trending ${type} content:`, error);
return []; return [];
} }
} }
@ -928,7 +868,6 @@ export class TMDBService {
external_ids: externalIdsResponse.data external_ids: externalIdsResponse.data
}; };
} catch (error) { } catch (error) {
logger.error(`Failed to get external IDs for ${type} ${item.id}:`, error);
return item; return item;
} }
}) })
@ -936,7 +875,6 @@ export class TMDBService {
return resultsWithExternalIds; return resultsWithExternalIds;
} catch (error) { } catch (error) {
logger.error(`Failed to get popular ${type} content:`, error);
return []; return [];
} }
} }
@ -976,7 +914,6 @@ export class TMDBService {
external_ids: externalIdsResponse.data external_ids: externalIdsResponse.data
}; };
} catch (error) { } catch (error) {
logger.error(`Failed to get external IDs for ${type} ${item.id}:`, error);
return item; return item;
} }
}) })
@ -984,7 +921,6 @@ export class TMDBService {
return resultsWithExternalIds; return resultsWithExternalIds;
} catch (error) { } catch (error) {
logger.error(`Failed to get upcoming ${type} content:`, error);
return []; return [];
} }
} }
@ -1002,7 +938,6 @@ export class TMDBService {
}); });
return response.data.genres || []; return response.data.genres || [];
} catch (error) { } catch (error) {
logger.error('Failed to fetch movie genres:', error);
return []; return [];
} }
} }
@ -1020,7 +955,6 @@ export class TMDBService {
}); });
return response.data.genres || []; return response.data.genres || [];
} catch (error) { } catch (error) {
logger.error('Failed to fetch TV genres:', error);
return []; return [];
} }
} }
@ -1041,7 +975,6 @@ export class TMDBService {
const genre = genreList.find(g => g.name.toLowerCase() === genreName.toLowerCase()); const genre = genreList.find(g => g.name.toLowerCase() === genreName.toLowerCase());
if (!genre) { if (!genre) {
logger.error(`Genre ${genreName} not found`);
return []; return [];
} }
@ -1075,7 +1008,6 @@ export class TMDBService {
external_ids: externalIdsResponse.data external_ids: externalIdsResponse.data
}; };
} catch (error) { } catch (error) {
logger.error(`Failed to get external IDs for ${type} ${item.id}:`, error);
return item; return item;
} }
}) })
@ -1083,7 +1015,6 @@ export class TMDBService {
return resultsWithExternalIds; return resultsWithExternalIds;
} catch (error) { } catch (error) {
logger.error(`Failed to discover ${type} by genre ${genreName}:`, error);
return []; return [];
} }
} }