mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-21 00:32:04 +00:00
trailer scroll fix
This commit is contained in:
parent
b81435be29
commit
665ff06ad1
4 changed files with 113 additions and 200 deletions
|
|
@ -1106,6 +1106,9 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
||||||
// Guards to avoid repeated auto-starts
|
// Guards to avoid repeated auto-starts
|
||||||
const startedOnFocusRef = useRef(false);
|
const startedOnFocusRef = useRef(false);
|
||||||
const startedOnReadyRef = useRef(false);
|
const startedOnReadyRef = useRef(false);
|
||||||
|
// Debounced pause/resume flag to avoid blocking scroll
|
||||||
|
const pendingPauseResumeSV = useSharedValue(0); // 0 = no action, 1 = pause, 2 = resume
|
||||||
|
const pauseResumeTimerRef = useRef<any>(null);
|
||||||
|
|
||||||
// Animation values for trailer unmute effects
|
// Animation values for trailer unmute effects
|
||||||
const actionButtonsOpacity = useSharedValue(1);
|
const actionButtonsOpacity = useSharedValue(1);
|
||||||
|
|
@ -1672,6 +1675,7 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
||||||
}, [isFocused, setTrailerPlaying]);
|
}, [isFocused, setTrailerPlaying]);
|
||||||
|
|
||||||
// Ultra-optimized scroll-based pause/resume with cached calculations
|
// Ultra-optimized scroll-based pause/resume with cached calculations
|
||||||
|
// This worklet only sets flags - actual pause/resume happens asynchronously to avoid blocking scroll
|
||||||
useDerivedValue(() => {
|
useDerivedValue(() => {
|
||||||
'worklet';
|
'worklet';
|
||||||
try {
|
try {
|
||||||
|
|
@ -1684,21 +1688,49 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
||||||
const isPlaying = isPlayingSV.value === 1;
|
const isPlaying = isPlayingSV.value === 1;
|
||||||
const isPausedByScroll = pausedByScrollSV.value === 1;
|
const isPausedByScroll = pausedByScrollSV.value === 1;
|
||||||
|
|
||||||
// Optimized pause/resume logic with minimal branching
|
// Set flags for pause/resume - don't execute immediately to keep scroll smooth
|
||||||
if (y > pauseThreshold && isPlaying && !isPausedByScroll) {
|
if (y > pauseThreshold && isPlaying && !isPausedByScroll) {
|
||||||
pausedByScrollSV.value = 1;
|
pendingPauseResumeSV.value = 1; // Request pause
|
||||||
runOnJS(setTrailerPlaying)(false);
|
|
||||||
isPlayingSV.value = 0;
|
|
||||||
} else if (y < resumeThreshold && isPausedByScroll) {
|
} else if (y < resumeThreshold && isPausedByScroll) {
|
||||||
pausedByScrollSV.value = 0;
|
pendingPauseResumeSV.value = 2; // Request resume
|
||||||
runOnJS(setTrailerPlaying)(true);
|
|
||||||
isPlayingSV.value = 1;
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Silent error handling for performance
|
// Silent error handling for performance
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Debounced pause/resume effect - executes asynchronously to keep scroll smooth
|
||||||
|
useEffect(() => {
|
||||||
|
const checkPendingAction = () => {
|
||||||
|
const pendingAction = pendingPauseResumeSV.value;
|
||||||
|
|
||||||
|
if (pendingAction === 1) {
|
||||||
|
// Execute pause
|
||||||
|
pausedByScrollSV.value = 1;
|
||||||
|
setTrailerPlaying(false);
|
||||||
|
isPlayingSV.value = 0;
|
||||||
|
pendingPauseResumeSV.value = 0; // Clear flag
|
||||||
|
} else if (pendingAction === 2) {
|
||||||
|
// Execute resume
|
||||||
|
pausedByScrollSV.value = 0;
|
||||||
|
setTrailerPlaying(true);
|
||||||
|
isPlayingSV.value = 1;
|
||||||
|
pendingPauseResumeSV.value = 0; // Clear flag
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up a recurring check with small delay to avoid blocking scroll
|
||||||
|
const intervalId = setInterval(checkPendingAction, 100);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
if (pauseResumeTimerRef.current) {
|
||||||
|
clearTimeout(pauseResumeTimerRef.current);
|
||||||
|
pauseResumeTimerRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [setTrailerPlaying, pendingPauseResumeSV, pausedByScrollSV, isPlayingSV]);
|
||||||
|
|
||||||
// Memory management and cleanup
|
// Memory management and cleanup
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
|
|
|
||||||
|
|
@ -132,16 +132,14 @@ export function useFeaturedContent() {
|
||||||
genres: (item as any).genres,
|
genres: (item as any).genres,
|
||||||
inLibrary: Boolean((item as any).inLibrary),
|
inLibrary: Boolean((item as any).inLibrary),
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// If enrichment is disabled, use addon logo if available
|
|
||||||
if (!settings.enrichMetadataWithTMDB) {
|
if (!settings.enrichMetadataWithTMDB) {
|
||||||
if (base.logo && !isTmdbUrl(base.logo)) {
|
// When enrichment is OFF, keep addon logo or undefined
|
||||||
return base;
|
return { ...base, logo: base.logo || undefined };
|
||||||
}
|
|
||||||
return { ...base, logo: undefined };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only proceed with TMDB enrichment if enrichment is enabled
|
// When enrichment is ON, fetch from TMDB with language preference
|
||||||
const rawId = String(item.id);
|
const rawId = String(item.id);
|
||||||
const isTmdb = rawId.startsWith('tmdb:');
|
const isTmdb = rawId.startsWith('tmdb:');
|
||||||
const isImdb = rawId.startsWith('tt');
|
const isImdb = rawId.startsWith('tt');
|
||||||
|
|
@ -154,17 +152,15 @@ export function useFeaturedContent() {
|
||||||
const found = await tmdbService.findTMDBIdByIMDB(imdbId);
|
const found = await tmdbService.findTMDBIdByIMDB(imdbId);
|
||||||
tmdbId = found ? String(found) : null;
|
tmdbId = found ? String(found) : null;
|
||||||
}
|
}
|
||||||
if (!tmdbId && !imdbId) return base;
|
|
||||||
// Try TMDB if we have a TMDB id
|
|
||||||
if (tmdbId) {
|
if (tmdbId) {
|
||||||
const logoUrl = await tmdbService.getContentLogo(item.type === 'series' ? 'tv' : 'movie', tmdbId as string, preferredLanguage);
|
const logoUrl = await tmdbService.getContentLogo(item.type === 'series' ? 'tv' : 'movie', tmdbId as string, preferredLanguage);
|
||||||
if (logoUrl) {
|
return { ...base, logo: logoUrl || undefined }; // TMDB logo or undefined (no addon fallback)
|
||||||
return { ...base, logo: logoUrl };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return base;
|
|
||||||
|
return { ...base, logo: undefined }; // No TMDB ID means no logo
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return base;
|
return { ...base, logo: undefined }; // Error means no logo
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -599,6 +599,17 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
logger.error('Failed to fetch credits for movie:', error);
|
logger.error('Failed to fetch credits for movie:', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch movie logo from TMDB
|
||||||
|
try {
|
||||||
|
const preferredLanguage = settings.tmdbLanguagePreference || 'en';
|
||||||
|
const logoUrl = await tmdbService.getContentLogo('movie', tmdbId, preferredLanguage);
|
||||||
|
formattedMovie.logo = logoUrl || undefined; // TMDB logo or undefined (no addon fallback)
|
||||||
|
if (__DEV__) logger.log(`Successfully fetched logo for movie ${tmdbId} from TMDB`);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Failed to fetch logo from TMDB:', error);
|
||||||
|
formattedMovie.logo = undefined; // Error means no logo
|
||||||
|
}
|
||||||
|
|
||||||
setMetadata(formattedMovie);
|
setMetadata(formattedMovie);
|
||||||
cacheService.setMetadata(id, type, formattedMovie);
|
cacheService.setMetadata(id, type, formattedMovie);
|
||||||
const isInLib = catalogService.getLibraryItems().some(item => item.id === id);
|
const isInLib = catalogService.getLibraryItems().some(item => item.id === id);
|
||||||
|
|
@ -664,14 +675,13 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
|
|
||||||
// Fetch TV show logo from TMDB
|
// Fetch TV show logo from TMDB
|
||||||
try {
|
try {
|
||||||
const logoUrl = await tmdbService.getTvShowImages(tmdbId);
|
const preferredLanguage = settings.tmdbLanguagePreference || 'en';
|
||||||
if (logoUrl) {
|
const logoUrl = await tmdbService.getContentLogo('tv', tmdbId, preferredLanguage);
|
||||||
formattedShow.logo = logoUrl;
|
formattedShow.logo = logoUrl || undefined; // TMDB logo or undefined (no addon fallback)
|
||||||
if (__DEV__) logger.log(`Successfully fetched logo for TV show ${tmdbId} from TMDB`);
|
if (__DEV__) logger.log(`Successfully fetched logo for TV show ${tmdbId} from TMDB`);
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to fetch logo from TMDB:', error);
|
logger.error('Failed to fetch logo from TMDB:', error);
|
||||||
// Continue with execution, logo is optional
|
formattedShow.logo = undefined; // Error means no logo
|
||||||
}
|
}
|
||||||
|
|
||||||
setMetadata(formattedShow);
|
setMetadata(formattedShow);
|
||||||
|
|
@ -878,6 +888,55 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
if (__DEV__) console.log('[useMetadata] failed to merge localized TMDB text', e);
|
if (__DEV__) console.log('[useMetadata] failed to merge localized TMDB text', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Centralized logo fetching logic
|
||||||
|
try {
|
||||||
|
if (settings.enrichMetadataWithTMDB) {
|
||||||
|
// Only use TMDB logos when enrichment is ON
|
||||||
|
const tmdbService = TMDBService.getInstance();
|
||||||
|
const preferredLanguage = settings.tmdbLanguagePreference || 'en';
|
||||||
|
const contentType = type === 'series' ? 'tv' : 'movie';
|
||||||
|
|
||||||
|
// Get TMDB ID
|
||||||
|
let tmdbIdForLogo = null;
|
||||||
|
if (tmdbId) {
|
||||||
|
tmdbIdForLogo = String(tmdbId);
|
||||||
|
} else if (finalMetadata.imdb_id) {
|
||||||
|
const foundId = await tmdbService.findTMDBIdByIMDB(finalMetadata.imdb_id);
|
||||||
|
tmdbIdForLogo = foundId ? String(foundId) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmdbIdForLogo) {
|
||||||
|
const logoUrl = await tmdbService.getContentLogo(contentType, tmdbIdForLogo, preferredLanguage);
|
||||||
|
finalMetadata.logo = logoUrl || undefined; // TMDB logo or undefined (no addon fallback)
|
||||||
|
if (__DEV__) {
|
||||||
|
console.log('[useMetadata] Logo fetch result:', {
|
||||||
|
contentType,
|
||||||
|
tmdbIdForLogo,
|
||||||
|
preferredLanguage,
|
||||||
|
logoUrl: !!logoUrl,
|
||||||
|
enrichmentEnabled: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
finalMetadata.logo = undefined; // No TMDB ID means no logo
|
||||||
|
if (__DEV__) console.log('[useMetadata] No TMDB ID found for logo, will show text title');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// When enrichment is OFF, keep addon logo or undefined
|
||||||
|
finalMetadata.logo = finalMetadata.logo || undefined;
|
||||||
|
if (__DEV__) {
|
||||||
|
console.log('[useMetadata] TMDB enrichment disabled, using addon logo:', {
|
||||||
|
hasAddonLogo: !!finalMetadata.logo,
|
||||||
|
enrichmentEnabled: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Handle error silently, keep existing logo behavior
|
||||||
|
if (__DEV__) console.error('[useMetadata] Unexpected error in logo fetch:', error);
|
||||||
|
finalMetadata.logo = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
// Commit final metadata once and cache it
|
// Commit final metadata once and cache it
|
||||||
// Clear banner field if TMDB enrichment is enabled to prevent flash
|
// Clear banner field if TMDB enrichment is enabled to prevent flash
|
||||||
if (settings.enrichMetadataWithTMDB) {
|
if (settings.enrichMetadataWithTMDB) {
|
||||||
|
|
|
||||||
|
|
@ -62,13 +62,6 @@ export const useMetadataAssets = (
|
||||||
// Add source tracking to prevent mixing sources
|
// Add source tracking to prevent mixing sources
|
||||||
const [bannerSource, setBannerSource] = useState<'tmdb' | 'metahub' | 'default' | null>(null);
|
const [bannerSource, setBannerSource] = useState<'tmdb' | 'metahub' | 'default' | null>(null);
|
||||||
|
|
||||||
// State for logo loading
|
|
||||||
const [logoLoadError, setLogoLoadError] = useState(false);
|
|
||||||
const logoFetchInProgress = useRef<boolean>(false);
|
|
||||||
const logoRefreshCounter = useRef<number>(0);
|
|
||||||
const MAX_LOGO_REFRESHES = 2;
|
|
||||||
const forcedLogoRefreshDone = useRef<boolean>(false);
|
|
||||||
|
|
||||||
// For TMDB ID tracking
|
// For TMDB ID tracking
|
||||||
const [foundTmdbId, setFoundTmdbId] = useState<string | null>(null);
|
const [foundTmdbId, setFoundTmdbId] = useState<string | null>(null);
|
||||||
|
|
||||||
|
|
@ -78,173 +71,8 @@ export const useMetadataAssets = (
|
||||||
setBannerImage(null);
|
setBannerImage(null);
|
||||||
setBannerSource(null);
|
setBannerSource(null);
|
||||||
forcedBannerRefreshDone.current = false;
|
forcedBannerRefreshDone.current = false;
|
||||||
forcedLogoRefreshDone.current = false;
|
|
||||||
logoRefreshCounter.current = 0;
|
|
||||||
|
|
||||||
// Mark that we need to refetch logo but DON'T clear it yet
|
|
||||||
// This prevents text from showing during the transition
|
|
||||||
logoFetchInProgress.current = false;
|
|
||||||
}, [settings.logoSourcePreference]);
|
}, [settings.logoSourcePreference]);
|
||||||
|
|
||||||
// Original reset logo load error effect
|
|
||||||
useEffect(() => {
|
|
||||||
setLogoLoadError(false);
|
|
||||||
}, [metadata?.logo]);
|
|
||||||
|
|
||||||
// Optimized logo fetching
|
|
||||||
useEffect(() => {
|
|
||||||
const logoPreference = settings.logoSourcePreference || 'tmdb';
|
|
||||||
|
|
||||||
if (__DEV__) {
|
|
||||||
console.log('[useMetadataAssets] Logo fetch triggered:', {
|
|
||||||
id,
|
|
||||||
type,
|
|
||||||
logoPreference,
|
|
||||||
hasImdbId: !!imdbId,
|
|
||||||
tmdbEnrichmentEnabled: settings.enrichMetadataWithTMDB,
|
|
||||||
logoFetchInProgress: logoFetchInProgress.current
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const currentLogoUrl = metadata?.logo;
|
|
||||||
let shouldFetchLogo = false;
|
|
||||||
|
|
||||||
// If enrichment is disabled, use addon logo and don't fetch from external sources
|
|
||||||
if (!settings.enrichMetadataWithTMDB) {
|
|
||||||
// If we have an addon logo, preload it immediately for instant display
|
|
||||||
if (metadata?.logo && !isTmdbUrl(metadata.logo)) {
|
|
||||||
// Preload addon logo for instant display
|
|
||||||
FastImage.preload([{ uri: metadata.logo }]);
|
|
||||||
// This is an addon logo, keep it
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// If no addon logo, don't fetch external logos when enrichment is disabled
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When TMDB enrichment is ON, remove addon logos immediately
|
|
||||||
// We don't want to show addon logos briefly before TMDB logos load
|
|
||||||
if (settings.enrichMetadataWithTMDB && currentLogoUrl && !isTmdbUrl(currentLogoUrl)) {
|
|
||||||
// Clear addon logo when enrichment is enabled
|
|
||||||
setMetadata((prevMetadata: any) => ({ ...prevMetadata!, logo: undefined }));
|
|
||||||
shouldFetchLogo = true;
|
|
||||||
}
|
|
||||||
// Determine if we need to fetch a new logo (only when enrichment is enabled)
|
|
||||||
else if (!currentLogoUrl) {
|
|
||||||
shouldFetchLogo = true;
|
|
||||||
} else {
|
|
||||||
const isCurrentLogoTmdb = isTmdbUrl(currentLogoUrl);
|
|
||||||
|
|
||||||
if (logoPreference === 'tmdb' && !isCurrentLogoTmdb) {
|
|
||||||
shouldFetchLogo = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guard against infinite loops by checking if we're already fetching
|
|
||||||
if (shouldFetchLogo && !logoFetchInProgress.current) {
|
|
||||||
logoFetchInProgress.current = true;
|
|
||||||
|
|
||||||
const fetchLogo = async () => {
|
|
||||||
// Store the original logo to restore if needed
|
|
||||||
const originalLogoUrl = currentLogoUrl;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const preferredLanguage = settings.tmdbLanguagePreference || 'en';
|
|
||||||
|
|
||||||
if (logoPreference === 'tmdb') {
|
|
||||||
// TMDB path - optimized flow
|
|
||||||
let tmdbId: string | null = null;
|
|
||||||
let contentType = type === 'series' ? 'tv' : 'movie';
|
|
||||||
|
|
||||||
// Extract or find TMDB ID in one step
|
|
||||||
if (id.startsWith('tmdb:')) {
|
|
||||||
tmdbId = id.split(':')[1];
|
|
||||||
} else if (imdbId && settings.enrichMetadataWithTMDB) {
|
|
||||||
try {
|
|
||||||
const tmdbService = TMDBService.getInstance();
|
|
||||||
const foundId = await tmdbService.findTMDBIdByIMDB(imdbId);
|
|
||||||
if (foundId) {
|
|
||||||
tmdbId = String(foundId);
|
|
||||||
setFoundTmdbId(tmdbId); // Save for banner fetching
|
|
||||||
} else if (__DEV__) {
|
|
||||||
console.log('[useMetadataAssets] Could not find TMDB ID for IMDB:', imdbId);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (__DEV__) console.error('[useMetadataAssets] Error finding TMDB ID:', error);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const parsedId = parseInt(id, 10);
|
|
||||||
if (!isNaN(parsedId)) {
|
|
||||||
tmdbId = String(parsedId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tmdbId) {
|
|
||||||
try {
|
|
||||||
// Direct fetch - avoid multiple service calls
|
|
||||||
const tmdbService = TMDBService.getInstance();
|
|
||||||
const logoUrl = await tmdbService.getContentLogo(contentType as 'tv' | 'movie', tmdbId, preferredLanguage);
|
|
||||||
|
|
||||||
if (__DEV__) {
|
|
||||||
console.log('[useMetadataAssets] Logo fetch result:', {
|
|
||||||
contentType,
|
|
||||||
tmdbId,
|
|
||||||
preferredLanguage,
|
|
||||||
logoUrl,
|
|
||||||
logoPreference
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logoUrl) {
|
|
||||||
// Preload the image before setting it
|
|
||||||
await FastImage.preload([{ uri: logoUrl }]);
|
|
||||||
|
|
||||||
// Only update if we got a valid logo
|
|
||||||
setMetadata((prevMetadata: any) => ({ ...prevMetadata!, logo: logoUrl }));
|
|
||||||
} else {
|
|
||||||
// TMDB logo not found
|
|
||||||
// When enrichment is ON, don't fallback to addon logos - show text instead
|
|
||||||
if (__DEV__) {
|
|
||||||
console.log('[useMetadataAssets] No TMDB logo found for ID:', tmdbId);
|
|
||||||
}
|
|
||||||
// Keep logo as undefined to show text title
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// TMDB logo fetch failed
|
|
||||||
// When enrichment is ON, don't fallback to addon logos - show text instead
|
|
||||||
if (__DEV__) {
|
|
||||||
console.error('[useMetadataAssets] Logo fetch error:', error);
|
|
||||||
}
|
|
||||||
// Keep logo as undefined to show text title
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No TMDB ID found
|
|
||||||
// When enrichment is ON, don't use addon logos - show text instead
|
|
||||||
if (__DEV__) console.log('[useMetadataAssets] No TMDB ID found, will show text title');
|
|
||||||
// Keep logo as undefined to show text title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// Handle error silently, keep existing logo
|
|
||||||
if (__DEV__) console.error('[useMetadataAssets] Unexpected error in logo fetch:', error);
|
|
||||||
} finally {
|
|
||||||
logoFetchInProgress.current = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute fetch without awaiting
|
|
||||||
fetchLogo();
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
id,
|
|
||||||
type,
|
|
||||||
imdbId,
|
|
||||||
metadata?.logo,
|
|
||||||
settings.logoSourcePreference,
|
|
||||||
settings.tmdbLanguagePreference,
|
|
||||||
settings.enrichMetadataWithTMDB,
|
|
||||||
setMetadata
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Optimized banner fetching
|
// Optimized banner fetching
|
||||||
const fetchBanner = useCallback(async () => {
|
const fetchBanner = useCallback(async () => {
|
||||||
if (!metadata) return;
|
if (!metadata) return;
|
||||||
|
|
@ -354,9 +182,7 @@ export const useMetadataAssets = (
|
||||||
return {
|
return {
|
||||||
bannerImage,
|
bannerImage,
|
||||||
loadingBanner,
|
loadingBanner,
|
||||||
logoLoadError,
|
|
||||||
foundTmdbId,
|
foundTmdbId,
|
||||||
setLogoLoadError,
|
|
||||||
setBannerImage,
|
setBannerImage,
|
||||||
bannerSource,
|
bannerSource,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue