From 741550d72dd5fffb9c367d68d5cf686c56121787 Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Tue, 17 Mar 2026 06:12:04 +0530 Subject: [PATCH] logs cleanup --- App.tsx | 2 - src/components/common/DogLoadingSpinner.tsx | 4 +- src/components/common/LoadingSpinner.tsx | 4 +- src/components/metadata/MetadataDetails.tsx | 2 +- src/components/metadata/RatingsSection.tsx | 2 +- src/components/metadata/SeriesContent.tsx | 20 +- src/components/metadata/TrailersSection.tsx | 10 +- src/components/promotions/CampaignManager.tsx | 2 - src/hooks/useMDBListRatings.ts | 2 +- src/hooks/useMetadata.ts | 289 +++++++----------- src/navigation/AppNavigator.tsx | 4 - src/screens/MDBListSettingsScreen.tsx | 40 +-- src/screens/MetadataScreen.tsx | 67 ++-- src/services/campaignService.ts | 7 - src/services/catalog/content-details.ts | 116 ------- src/services/catalog/library.ts | 21 +- src/services/mdblistConstants.ts | 31 ++ src/services/mdblistService.ts | 3 +- src/services/telemetryService.ts | 1 - src/utils/logger.ts | 4 +- 20 files changed, 218 insertions(+), 413 deletions(-) create mode 100644 src/services/mdblistConstants.ts diff --git a/App.tsx b/App.tsx index 7ce219f0..960fe6c8 100644 --- a/App.tsx +++ b/App.tsx @@ -195,11 +195,9 @@ const ThemedApp = () => { // Initialize memory monitoring service to prevent OutOfMemoryError memoryMonitorService; // Just accessing it starts the monitoring - console.log('Memory monitoring service initialized'); // Initialize AI service await aiService.initialize(); - console.log('AI service initialized'); } catch (error) { console.error('Error initializing app:', error); diff --git a/src/components/common/DogLoadingSpinner.tsx b/src/components/common/DogLoadingSpinner.tsx index f65e18dd..4a553e82 100644 --- a/src/components/common/DogLoadingSpinner.tsx +++ b/src/components/common/DogLoadingSpinner.tsx @@ -76,9 +76,7 @@ const LoadingSpinner: React.FC = ({ renderMode: 'SOFTWARE' as any, // Fallback to software rendering if hardware fails })} // Error handling - onAnimationFinish={() => { - if (__DEV__) console.log('Lottie animation finished'); - }} + onAnimationFinish={() => {}} onAnimationFailure={(error) => { if (__DEV__) console.warn('Lottie animation failed:', error); }} diff --git a/src/components/common/LoadingSpinner.tsx b/src/components/common/LoadingSpinner.tsx index 45b8654f..6097a3a9 100644 --- a/src/components/common/LoadingSpinner.tsx +++ b/src/components/common/LoadingSpinner.tsx @@ -76,9 +76,7 @@ const LoadingSpinner: React.FC = ({ renderMode: 'SOFTWARE' as any, // Fallback to software rendering if hardware fails })} // Error handling - onAnimationFinish={() => { - if (__DEV__) console.log('Lottie animation finished'); - }} + onAnimationFinish={() => {}} onAnimationFailure={(error) => { if (__DEV__) console.warn('Lottie animation failed:', error); }} diff --git a/src/components/metadata/MetadataDetails.tsx b/src/components/metadata/MetadataDetails.tsx index cde9ab4d..8d869051 100644 --- a/src/components/metadata/MetadataDetails.tsx +++ b/src/components/metadata/MetadataDetails.tsx @@ -19,7 +19,7 @@ import Animated, { Extrapolate, } from 'react-native-reanimated'; import { useTheme } from '../../contexts/ThemeContext'; -import { isMDBListEnabled } from '../../screens/MDBListSettingsScreen'; +import { isMDBListEnabled } from '../../services/mdblistConstants'; import { getAgeRatingColor } from '../../utils/ageRatingColors'; import AgeRatingBadge from '../common/AgeRatingBadge'; diff --git a/src/components/metadata/RatingsSection.tsx b/src/components/metadata/RatingsSection.tsx index 6d552425..ea569ec0 100644 --- a/src/components/metadata/RatingsSection.tsx +++ b/src/components/metadata/RatingsSection.tsx @@ -5,7 +5,7 @@ import { useTheme } from '../../contexts/ThemeContext'; import FastImage from '@d11/react-native-fast-image'; import { useMDBListRatings } from '../../hooks/useMDBListRatings'; import { mmkvStorage } from '../../services/mmkvStorage'; -import { isMDBListEnabled, RATING_PROVIDERS_STORAGE_KEY } from '../../screens/MDBListSettingsScreen'; +import { isMDBListEnabled, RATING_PROVIDERS_STORAGE_KEY } from '../../services/mdblistConstants'; // Import SVG icons import LetterboxdIcon from '../../../assets/rating-icons/letterboxd.svg'; diff --git a/src/components/metadata/SeriesContent.tsx b/src/components/metadata/SeriesContent.tsx index c0c23833..b2eb5c78 100644 --- a/src/components/metadata/SeriesContent.tsx +++ b/src/components/metadata/SeriesContent.tsx @@ -15,10 +15,18 @@ import { useFocusEffect } from '@react-navigation/native'; import Animated, { FadeIn, FadeOut, SlideInRight, SlideOutLeft } from 'react-native-reanimated'; import { TraktService } from '../../services/traktService'; import { watchedService } from '../../services/watchedService'; -import { logger } from '../../utils/logger'; import { mmkvStorage } from '../../services/mmkvStorage'; import { MalSync } from '../../services/mal/MalSync'; +const noop = (..._args: unknown[]) => {}; +const logger = { + log: noop, + error: noop, + warn: noop, + info: noop, + debug: noop, +}; + // ... other imports const BREAKPOINTS = { phone: 0, @@ -212,10 +220,10 @@ const SeriesContentComponent: React.FC = ({ const savedMode = await mmkvStorage.getItem('global_season_view_mode'); if (savedMode === 'text' || savedMode === 'posters') { setSeasonViewMode(savedMode); - if (__DEV__) console.log('[SeriesContent] Loaded global view mode:', savedMode); + if (__DEV__) logger.log('[SeriesContent] Loaded global view mode:', savedMode); } } catch (error) { - if (__DEV__) console.log('[SeriesContent] Error loading global view mode preference:', error); + if (__DEV__) logger.log('[SeriesContent] Error loading global view mode preference:', error); } }; @@ -239,7 +247,7 @@ const SeriesContentComponent: React.FC = ({ const updateViewMode = (newMode: 'posters' | 'text') => { setSeasonViewMode(newMode); mmkvStorage.setItem('global_season_view_mode', newMode).catch((error: any) => { - if (__DEV__) console.log('[SeriesContent] Error saving global view mode preference:', error); + if (__DEV__) logger.log('[SeriesContent] Error saving global view mode preference:', error); }); }; @@ -491,7 +499,7 @@ const SeriesContentComponent: React.FC = ({ useEffect(() => { return () => { // Clear any pending timeouts - if (__DEV__) console.log('[SeriesContent] Component unmounted, cleaning up memory'); + if (__DEV__) logger.log('[SeriesContent] Component unmounted, cleaning up memory'); // Force garbage collection if available (development only) if (__DEV__ && global.gc) { @@ -854,7 +862,7 @@ const SeriesContentComponent: React.FC = ({ onPress={() => { const newMode = seasonViewMode === 'posters' ? 'text' : 'posters'; updateViewMode(newMode); - if (__DEV__) console.log('[SeriesContent] View mode changed to:', newMode, 'Current ref value:', seasonViewMode); + if (__DEV__) logger.log('[SeriesContent] View mode changed to:', newMode, 'Current ref value:', seasonViewMode); }} activeOpacity={0.7} > diff --git a/src/components/metadata/TrailersSection.tsx b/src/components/metadata/TrailersSection.tsx index 579a51cc..ca0b789d 100644 --- a/src/components/metadata/TrailersSection.tsx +++ b/src/components/metadata/TrailersSection.tsx @@ -17,12 +17,20 @@ import FastImage from '@d11/react-native-fast-image'; import { useTheme } from '../../contexts/ThemeContext'; import { useSettings } from '../../hooks/useSettings'; import { useTrailer } from '../../contexts/TrailerContext'; -import { logger } from '../../utils/logger'; import TrailerService from '../../services/trailerService'; import { TMDBService } from '../../services/tmdbService'; import TrailerModal from './TrailerModal'; import Animated, { useSharedValue, withTiming, withDelay, useAnimatedStyle } from 'react-native-reanimated'; +const noop = (..._args: unknown[]) => {}; +const logger = { + log: noop, + error: noop, + warn: noop, + info: noop, + debug: noop, +}; + // Enhanced responsive breakpoints for Trailers Section const BREAKPOINTS = { phone: 0, diff --git a/src/components/promotions/CampaignManager.tsx b/src/components/promotions/CampaignManager.tsx index 725f0fe1..d24cfabe 100644 --- a/src/components/promotions/CampaignManager.tsx +++ b/src/components/promotions/CampaignManager.tsx @@ -216,11 +216,9 @@ export const CampaignManager: React.FC = () => { const checkForCampaigns = useCallback(async () => { try { - console.log('[CampaignManager] Checking for campaigns...'); await new Promise(resolve => setTimeout(resolve, 1500)); const campaign = await campaignService.getActiveCampaign(); - console.log('[CampaignManager] Got campaign:', campaign?.id, campaign?.type); if (campaign) { setActiveCampaign(campaign); diff --git a/src/hooks/useMDBListRatings.ts b/src/hooks/useMDBListRatings.ts index 46bcc868..d866f5ff 100644 --- a/src/hooks/useMDBListRatings.ts +++ b/src/hooks/useMDBListRatings.ts @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react'; import { mdblistService, MDBListRatings } from '../services/mdblistService'; import { logger } from '../utils/logger'; -import { isMDBListEnabled } from '../screens/MDBListSettingsScreen'; +import { isMDBListEnabled } from '../services/mdblistConstants'; export const useMDBListRatings = (imdbId: string, mediaType: 'movie' | 'show') => { const [ratings, setRatings] = useState(null); diff --git a/src/hooks/useMetadata.ts b/src/hooks/useMetadata.ts index 0b5c90c8..291c8293 100644 --- a/src/hooks/useMetadata.ts +++ b/src/hooks/useMetadata.ts @@ -7,7 +7,6 @@ import { cacheService } from '../services/cacheService'; import { localScraperService, ScraperInfo } from '../services/pluginService'; import { Cast, Episode, GroupedEpisodes, GroupedStreams } from '../types/metadata'; import { TMDBService } from '../services/tmdbService'; -import { logger } from '../utils/logger'; import { usePersistentSeasons } from './usePersistentSeasons'; import { mmkvStorage } from '../services/mmkvStorage'; import { Stream } from '../types/metadata'; @@ -15,6 +14,15 @@ import { storageService } from '../services/storageService'; import { useSettings } from './useSettings'; import { MalSync } from '../services/mal/MalSync'; +const noop = (..._args: unknown[]) => {}; +const logger = { + log: noop, + error: noop, + warn: noop, + info: noop, + debug: noop, +}; + // Constants for timeouts and retries const API_TIMEOUT = 10000; // 10 seconds const MAX_RETRIES = 1; // Reduced since stremioService already retries @@ -163,8 +171,6 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat // Memory optimization: Stream cleanup and garbage collection const cleanupStreams = useCallback(() => { - if (__DEV__) console.log('[useMetadata] Running stream cleanup to free memory'); - // Clear preloaded streams cache setPreloadedStreams({}); setPreloadedEpisodeStreams({}); @@ -222,25 +228,11 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat (streams, addonId, addonName, error, installationId) => { const processTime = Date.now() - sourceStartTime; - console.log('🔍 [processStremioSource] Callback received:', { - addonId, - addonName, - installationId, - streamCount: streams?.length || 0, - error: error?.message || null, - processTime - }); - // ALWAYS remove from active fetching list when callback is received // This ensures that even failed scrapers are removed from the "Fetching from:" chip if (addonName) { setActiveFetchingScrapers(prev => { const updated = prev.filter(name => name !== addonName); - console.log('🔍 [processStremioSource] Removing from activeFetchingScrapers:', { - addonName, - before: prev, - after: updated - }); return updated; }); } @@ -496,18 +488,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const loadMetadata = async () => { try { - console.log('🚀 [useMetadata] loadMetadata CALLED for:', { id, type }); - console.log('🔍 [useMetadata] loadMetadata started:', { - id, - type, - addonId, - loadAttempts, - maxRetries: MAX_RETRIES, - settingsLoaded: settingsLoaded - }); - if (loadAttempts >= MAX_RETRIES) { - console.log('🔍 [useMetadata] Max retries exceeded:', { loadAttempts, maxRetries: MAX_RETRIES }); setError(`Failed to load content after ${MAX_RETRIES + 1} attempts. Please check your connection and try again.`); setLoading(false); return; @@ -520,14 +501,6 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat // Check metadata screen cache const cachedScreen = cacheService.getMetadataScreen(id, normalizedType); if (cachedScreen) { - console.log('🔍 [useMetadata] Using cached metadata:', { - id, - type, - hasMetadata: !!cachedScreen.metadata, - hasCast: !!cachedScreen.cast, - hasEpisodes: !!cachedScreen.episodes, - tmdbId: cachedScreen.tmdbId - }); setMetadata(cachedScreen.metadata); setCast(cachedScreen.cast); if (normalizedType === 'series' && cachedScreen.episodes) { @@ -545,7 +518,6 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat setLoading(false); return; } else { - console.log('🔍 [useMetadata] No cached metadata found, proceeding with fresh fetch'); } // Handle TMDB-specific IDs @@ -556,7 +528,6 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat // STRICT MODE: Do NOT convert to IMDb/Cinemeta. // We want to force the app to use AnimeKitsu (or other MAL-compatible addons) for metadata. // This ensures we get correct Season/Episode mapping (Separate entries) instead of Cinemeta's "S1E26" mess. - console.log('🔍 [useMetadata] Keeping MAL ID for metadata fetch:', id); // Note: Stream fetching (stremioService) WILL still convert this to IMDb secretly // to ensure Torrentio works, but the Metadata UI will stay purely MAL-based. @@ -564,13 +535,10 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat if (id.startsWith('tmdb:')) { // Always try the original TMDB ID first - let addons decide if they support it - console.log('🔍 [useMetadata] TMDB ID detected, trying original ID first:', { originalId: id }); - // If enrichment disabled, try original ID first, then fallback to conversion if needed if (!settings.enrichMetadataWithTMDB) { // Keep the original TMDB ID - let the addon system handle it dynamically actualId = id; - console.log('🔍 [useMetadata] TMDB enrichment disabled, using original TMDB ID:', { actualId }); } else { const tmdbId = id.split(':')[1]; // For TMDB IDs, we need to handle metadata differently @@ -730,7 +698,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat // Load series data (episodes) setTmdbId(parseInt(tmdbId)); - loadSeriesData().catch((error) => { if (__DEV__) console.error(error); }); + loadSeriesData().catch((error) => { if (__DEV__) logger.error(error); }); (async () => { const items = await catalogService.getLibraryItems(); @@ -749,7 +717,6 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat } // Load all data in parallel - console.log('🔍 [useMetadata] Starting parallel data fetch:', { type, actualId, addonId, apiTimeout: API_TIMEOUT }); if (__DEV__) logger.log('[loadMetadata] fetching addon metadata', { type, actualId, addonId }); let contentResult: any = null; @@ -761,7 +728,6 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat if (preferExternal) { // Try external meta addons first try { - console.log('🔍 [useMetadata] Trying external meta addons first'); const [content, castData] = await Promise.allSettled([ withRetry(async () => { // Get all installed addons @@ -791,20 +757,17 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat ); if (result) { - console.log('🔍 [useMetadata] Got metadata from external addon:', addon.name); if (actualId.startsWith('tt')) { setImdbId(actualId); } return result; } } catch (error) { - console.log('🔍 [useMetadata] External addon failed:', addon.name, error); continue; } } // If no external addon worked, fall back to catalog addon - console.log('🔍 [useMetadata] No external meta addon worked, falling back to catalog addon'); const result = await withTimeout( catalogService.getEnhancedContentDetails(normalizedType, actualId, addonId), API_TIMEOUT @@ -819,39 +782,29 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat contentResult = content; if (content.status === 'fulfilled' && content.value) { - console.log('🔍 [useMetadata] Successfully got metadata with external meta addon priority'); + if (__DEV__) { + logger.log('[useMetadata] External meta addon priority success'); + } } else { - console.log('🔍 [useMetadata] External meta addon priority failed, will try fallback'); lastError = (content as any)?.reason; } } catch (error) { - console.log('🔍 [useMetadata] External meta addon attempt failed:', { error: error instanceof Error ? error.message : String(error) }); lastError = error; } } else { // Original behavior: try with original ID first try { - console.log('🔍 [useMetadata] Attempting metadata fetch with original ID:', { type, actualId, addonId }); const [content, castData] = await Promise.allSettled([ // Load content with timeout and retry withRetry(async () => { - console.log('⚡ [useMetadata] Calling catalogService.getEnhancedContentDetails...'); - console.log('🔍 [useMetadata] Calling catalogService.getEnhancedContentDetails:', { type, actualId, addonId }); const result = await withTimeout( catalogService.getEnhancedContentDetails(normalizedType, actualId, addonId), API_TIMEOUT ); - console.log('✅ [useMetadata] catalogService returned:', result ? 'DATA' : 'NULL'); // Store the actual ID used (could be IMDB) if (actualId.startsWith('tt')) { setImdbId(actualId); } - console.log('🔍 [useMetadata] catalogService.getEnhancedContentDetails result:', { - hasResult: Boolean(result), - resultId: result?.id, - resultName: result?.name, - resultType: result?.type - }); if (__DEV__) logger.log('[loadMetadata] addon metadata fetched', { hasResult: Boolean(result) }); return result; }), @@ -861,13 +814,13 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat contentResult = content; if (content.status === 'fulfilled' && content.value) { - console.log('🔍 [useMetadata] Successfully got metadata with original ID'); + if (__DEV__) { + logger.log('[useMetadata] Original ID metadata fetch succeeded'); + } } else { - console.log('🔍 [useMetadata] Original ID failed, will try fallback conversion'); lastError = (content as any)?.reason; } } catch (error) { - console.log('🔍 [useMetadata] Original ID attempt failed:', { error: error instanceof Error ? error.message : String(error) }); lastError = error; } } @@ -875,12 +828,10 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat // If original TMDB ID failed and enrichment is disabled, try ID conversion as fallback if (!contentResult || (contentResult.status === 'fulfilled' && !contentResult.value) || contentResult.status === 'rejected') { if (id.startsWith('tmdb:') && !settings.enrichMetadataWithTMDB) { - console.log('🔍 [useMetadata] Original TMDB ID failed, trying ID conversion fallback'); const tmdbRaw = id.split(':')[1]; try { const stremioId = await catalogService.getStremioId(normalizedType === 'series' ? 'tv' : 'movie', tmdbRaw); if (stremioId && stremioId !== id) { - console.log('🔍 [useMetadata] Trying converted ID:', { originalId: id, convertedId: stremioId }); const [content, castData] = await Promise.allSettled([ withRetry(async () => { const result = await withTimeout( @@ -897,7 +848,9 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat contentResult = content; } } catch (e) { - console.log('🔍 [useMetadata] ID conversion fallback also failed:', { error: e instanceof Error ? e.message : String(e) }); + if (__DEV__) { + logger.log('[useMetadata] ID conversion fallback failed'); + } } } } @@ -905,22 +858,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const content = contentResult || { status: 'rejected' as const, reason: lastError || new Error('No content result') }; const castData = { status: 'fulfilled' as const, value: undefined }; - console.log('🔍 [useMetadata] Promise.allSettled results:', { - contentStatus: content.status, - contentFulfilled: content.status === 'fulfilled', - hasContentValue: content.status === 'fulfilled' ? !!content.value : false, - castStatus: castData.status, - castFulfilled: castData.status === 'fulfilled' - }); - if (content.status === 'fulfilled' && content.value) { - console.log('🔍 [useMetadata] Content fetch successful:', { - id: content.value?.id, - type: content.value?.type, - name: content.value?.name, - hasDescription: !!content.value?.description, - hasPoster: !!content.value?.poster - }); if (__DEV__) logger.log('[loadMetadata] addon metadata:success', { id: content.value?.id, type: content.value?.type, name: content.value?.name }); // Start with addon metadata @@ -1025,7 +963,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat } } } catch (e) { - if (__DEV__) console.log('[useMetadata] failed to merge TMDB title/description', e); + if (__DEV__) logger.log('[useMetadata] failed to merge TMDB title/description', e); } // Centralized logo fetching logic @@ -1050,7 +988,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat // Use TMDB logo if found, otherwise fall back to addon logo finalMetadata.logo = logoUrl || addonLogo || undefined; if (__DEV__) { - console.log('[useMetadata] Logo fetch result:', { + logger.log('[useMetadata] Logo fetch result:', { contentType, tmdbIdForLogo, preferredLanguage, @@ -1062,13 +1000,13 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat } else { // No TMDB ID, fall back to addon logo finalMetadata.logo = addonLogo || undefined; - if (__DEV__) console.log('[useMetadata] No TMDB ID found for logo, using addon logo'); + if (__DEV__) logger.log('[useMetadata] No TMDB ID found for logo, using addon logo'); } } else { // When enrichment or logos is OFF, use addon logo finalMetadata.logo = addonLogo || finalMetadata.logo || undefined; if (__DEV__) { - console.log('[useMetadata] TMDB logo enrichment disabled, using addon logo:', { + logger.log('[useMetadata] TMDB logo enrichment disabled, using addon logo:', { hasAddonLogo: !!finalMetadata.logo, enrichmentEnabled: settings.enrichMetadataWithTMDB, logosEnabled: settings.tmdbEnrichLogos @@ -1077,7 +1015,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat } } catch (error) { // Handle error silently, keep existing logo behavior - if (__DEV__) console.error('[useMetadata] Unexpected error in logo fetch:', error); + if (__DEV__) logger.error('[useMetadata] Unexpected error in logo fetch:', error); finalMetadata.logo = undefined; } @@ -1114,17 +1052,8 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const reason = (content as any)?.reason; const reasonMessage = reason?.message || String(reason); - console.log('🔍 [useMetadata] Content fetch failed:', { - status: content.status, - reason: reasonMessage, - fullReason: reason, - isAxiosError: reason?.isAxiosError, - responseStatus: reason?.response?.status, - responseData: reason?.response?.data - }); - if (__DEV__) { - console.log('[loadMetadata] addon metadata:not found or failed', { + logger.log('[loadMetadata] addon metadata:not found or failed', { status: content.status, reason: reasonMessage, fullReason: reason @@ -1139,28 +1068,23 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat reasonMessage.includes('Network Error') || reasonMessage.includes('Request failed') )) { - console.log('🔍 [useMetadata] Detected server/network error, preserving original error'); // This was a server/network error, preserve the original error message throw reason instanceof Error ? reason : new Error(reasonMessage); } else { - console.log('🔍 [useMetadata] Detected content not found error, throwing generic error'); // This was likely a content not found error throw new Error('Content not found'); } } } catch (error) { - console.log('🔍 [useMetadata] loadMetadata caught error:', { - errorMessage: error instanceof Error ? error.message : String(error), - errorType: typeof error, - isAxiosError: (error as any)?.isAxiosError, - responseStatus: (error as any)?.response?.status, - responseData: (error as any)?.response?.data, - stack: error instanceof Error ? error.stack : undefined - }); - if (__DEV__) { - console.error('Failed to load metadata:', error); - console.log('Error message being set:', error instanceof Error ? error.message : String(error)); + logger.log('[loadMetadata] failed with error', { + errorMessage: error instanceof Error ? error.message : String(error), + errorType: typeof error, + isAxiosError: (error as any)?.isAxiosError, + responseStatus: (error as any)?.response?.status, + responseData: (error as any)?.response?.data, + stack: error instanceof Error ? error.stack : undefined + }); } // Preserve the original error details for better error parsing @@ -1173,7 +1097,6 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat setGroupedEpisodes({}); setEpisodes([]); } finally { - console.log('🔍 [useMetadata] loadMetadata completed, setting loading to false'); setLoading(false); } }; @@ -1309,7 +1232,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat if (__DEV__) logger.log('[useMetadata] merged episode names/overviews from TMDB (batch)'); } } catch (e) { - if (__DEV__) console.log('[useMetadata] failed to merge episode text from TMDB', e); + if (__DEV__) logger.log('[useMetadata] failed to merge episode text from TMDB', e); } } @@ -1477,7 +1400,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat } } } catch (error) { - if (__DEV__) console.error('Failed to load episodes:', error); + if (__DEV__) logger.error('Failed to load episodes:', error); } finally { setLoadingSeasons(false); } @@ -1531,7 +1454,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat } if (allEmbeddedStreams.length > 0) { - if (__DEV__) console.log(`✅ [extractEmbeddedStreams] Found ${allEmbeddedStreams.length} embedded streams from ${addonName}`); + if (__DEV__) logger.log(`✅ [extractEmbeddedStreams] Found ${allEmbeddedStreams.length} embedded streams from ${addonName}`); // Add to grouped streams setGroupedStreams(prevStreams => ({ @@ -1566,7 +1489,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat ); if (episodeVideo && episodeVideo.streams && episodeVideo.streams.length > 0) { - if (__DEV__) console.log(`✅ [extractEmbeddedStreams] Found embedded streams for episode ${episodeToUse}`); + if (__DEV__) logger.log(`✅ [extractEmbeddedStreams] Found embedded streams for episode ${episodeToUse}`); const episodeStreamsList: Stream[] = episodeVideo.streams.map((stream: any) => ({ ...stream, @@ -1592,7 +1515,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const loadStreams = async () => { const startTime = Date.now(); try { - if (__DEV__) console.log('🚀 [loadStreams] START - Loading streams for:', id); + if (__DEV__) logger.log('🚀 [loadStreams] START - Loading streams for:', id); updateLoadingState(); // Reset scraper tracking @@ -1600,22 +1523,22 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat setActiveFetchingScrapers([]); setAddonResponseOrder([]); // Reset response order - if (__DEV__) console.log('🔍 [loadStreams] Getting TMDB ID for:', id); + if (__DEV__) logger.log('🔍 [loadStreams] Getting TMDB ID for:', id); let tmdbId; let stremioId = id; let effectiveStreamType: string = type; if (id.startsWith('tmdb:')) { tmdbId = id.split(':')[1]; - if (__DEV__) console.log('✅ [loadStreams] Using TMDB ID from ID:', tmdbId); + if (__DEV__) logger.log('✅ [loadStreams] Using TMDB ID from ID:', tmdbId); // Try to get IMDb ID from metadata first, then convert if needed if (metadata?.imdb_id) { stremioId = metadata.imdb_id; - if (__DEV__) console.log('✅ [loadStreams] Using IMDb ID from metadata for Stremio:', stremioId); + if (__DEV__) logger.log('✅ [loadStreams] Using IMDb ID from metadata for Stremio:', stremioId); } else if (imdbId) { stremioId = imdbId; - if (__DEV__) console.log('✅ [loadStreams] Using stored IMDb ID for Stremio:', stremioId); + if (__DEV__) logger.log('✅ [loadStreams] Using stored IMDb ID for Stremio:', stremioId); } else { // Convert TMDB ID to IMDb ID for Stremio addons (they expect IMDb format) try { @@ -1629,28 +1552,28 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat if (externalIds?.imdb_id) { stremioId = externalIds.imdb_id; - if (__DEV__) console.log('✅ [loadStreams] Converted TMDB to IMDb ID for Stremio:', stremioId); + if (__DEV__) logger.log('✅ [loadStreams] Converted TMDB to IMDb ID for Stremio:', stremioId); } else { - if (__DEV__) console.log('âš ī¸ [loadStreams] No IMDb ID found for TMDB ID, using original:', stremioId); + if (__DEV__) logger.log('âš ī¸ [loadStreams] No IMDb ID found for TMDB ID, using original:', stremioId); } } catch (error) { - if (__DEV__) console.log('âš ī¸ [loadStreams] Failed to convert TMDB to IMDb, using original ID:', error); + if (__DEV__) logger.log('âš ī¸ [loadStreams] Failed to convert TMDB to IMDb, using original ID:', error); } } } else if (id.startsWith('tt')) { // This is already an IMDB ID, perfect for Stremio stremioId = id; if (settings.enrichMetadataWithTMDB) { - if (__DEV__) console.log('📝 [loadStreams] Converting IMDB ID to TMDB ID...'); + if (__DEV__) logger.log('📝 [loadStreams] Converting IMDB ID to TMDB ID...'); tmdbId = await withTimeout(tmdbService.findTMDBIdByIMDB(id), API_TIMEOUT); - if (__DEV__) console.log('✅ [loadStreams] Converted to TMDB ID:', tmdbId); + if (__DEV__) logger.log('✅ [loadStreams] Converted to TMDB ID:', tmdbId); } else { - if (__DEV__) console.log('📝 [loadStreams] TMDB enrichment disabled, skipping IMDB to TMDB conversion'); + if (__DEV__) logger.log('📝 [loadStreams] TMDB enrichment disabled, skipping IMDB to TMDB conversion'); } } else { tmdbId = id; stremioId = id; - if (__DEV__) console.log('â„šī¸ [loadStreams] Using ID as both TMDB and Stremio ID:', tmdbId); + if (__DEV__) logger.log('â„šī¸ [loadStreams] Using ID as both TMDB and Stremio ID:', tmdbId); } // Initialize scraper tracking @@ -1710,14 +1633,14 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat if (fallback.length > 0) { effectiveStreamType = fallbackType; eligibleStreamAddons = fallback; - if (__DEV__) console.log(`[useMetadata.loadStreams] No addons for '${requestedStreamType}', falling back to '${fallbackType}'`); + if (__DEV__) logger.log(`[useMetadata.loadStreams] No addons for '${requestedStreamType}', falling back to '${fallbackType}'`); break; } } } const streamAddons = eligibleStreamAddons; - if (__DEV__) console.log('[useMetadata.loadStreams] Eligible stream addons:', streamAddons.map(a => a.id), { requestedStreamType, effectiveStreamType }); + if (__DEV__) logger.log('[useMetadata.loadStreams] Eligible stream addons:', streamAddons.map(a => a.id), { requestedStreamType, effectiveStreamType }); // Initialize scraper statuses for tracking const initialStatuses: ScraperStatus[] = []; @@ -1764,11 +1687,11 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat setLoadingStreams(false); } } catch (error) { - if (__DEV__) console.error('Failed to initialize scraper tracking:', error); + if (__DEV__) logger.error('Failed to initialize scraper tracking:', error); } // Start Stremio request using the converted ID format - if (__DEV__) console.log('đŸŽŦ [loadStreams] Using ID for Stremio addons:', stremioId); + if (__DEV__) logger.log('đŸŽŦ [loadStreams] Using ID for Stremio addons:', stremioId); // Use the effective type we selected when building the eligible addon list. // This stays aligned with Stremio manifest filtering rules and avoids hard-mapping non-standard types. processStremioSource(effectiveStreamType, stremioId, false); @@ -1807,7 +1730,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat }, 60000); } catch (error) { - if (__DEV__) console.error('❌ [loadStreams] Failed to load streams:', error); + if (__DEV__) logger.error('❌ [loadStreams] Failed to load streams:', error); // Preserve the original error details for better error parsing const errorMessage = error instanceof Error ? error.message : 'Failed to load streams'; setError(errorMessage); @@ -1818,7 +1741,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const loadEpisodeStreams = async (episodeId: string) => { const startTime = Date.now(); try { - if (__DEV__) console.log('🚀 [loadEpisodeStreams] START - Loading episode streams for:', episodeId); + if (__DEV__) logger.log('🚀 [loadEpisodeStreams] START - Loading episode streams for:', episodeId); updateEpisodeLoadingState(); // Reset scraper tracking for episodes @@ -1861,7 +1784,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const fallback = pickStreamCapableAddons(fallbackType); if (fallback.length > 0) { streamAddons = fallback; - if (__DEV__) console.log(`[useMetadata.loadEpisodeStreams] No addons for '${requestedEpisodeType}', falling back to '${fallbackType}'`); + if (__DEV__) logger.log(`[useMetadata.loadEpisodeStreams] No addons for '${requestedEpisodeType}', falling back to '${fallbackType}'`); break; } } @@ -1912,12 +1835,12 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat setLoadingEpisodeStreams(false); } } catch (error) { - if (__DEV__) console.error('Failed to initialize episode scraper tracking:', error); + if (__DEV__) logger.error('Failed to initialize episode scraper tracking:', error); } // Get TMDB ID for external sources and determine the correct ID for Stremio addons const isImdb = id.startsWith('tt'); - if (__DEV__) console.log('🔍 [loadEpisodeStreams] Getting TMDB ID for:', id); + if (__DEV__) logger.log('🔍 [loadEpisodeStreams] Getting TMDB ID for:', id); let tmdbId; let stremioEpisodeId = episodeId; // Default to original episode ID let isCollection = false; @@ -1965,13 +1888,13 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat showIdStr = parts.join(':'); } - if (__DEV__) console.log(`🔍 [loadEpisodeStreams] Parsed ID: show=${showIdStr}, s=${seasonNum}, e=${episodeNum}`); + if (__DEV__) logger.log(`🔍 [loadEpisodeStreams] Parsed ID: show=${showIdStr}, s=${seasonNum}, e=${episodeNum}`); } catch (e) { - if (__DEV__) console.warn('âš ī¸ [loadEpisodeStreams] Failed to parse episode ID:', episodeId); + if (__DEV__) logger.warn('âš ī¸ [loadEpisodeStreams] Failed to parse episode ID:', episodeId); } if (isCollection && collectionAddon) { - if (__DEV__) console.log(`đŸŽŦ [loadEpisodeStreams] Detected collection from addon: ${collectionAddon.name}, treating episodes as individual movies`); + if (__DEV__) logger.log(`đŸŽŦ [loadEpisodeStreams] Detected collection from addon: ${collectionAddon.name}, treating episodes as individual movies`); // For collections, extract the individual movie ID from the episodeId // episodeId format for collections: "tt7888964" (IMDb ID of individual movie) @@ -1981,7 +1904,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat tmdbId = await withTimeout(tmdbService.findTMDBIdByIMDB(episodeId), API_TIMEOUT); } stremioEpisodeId = episodeId; // Use the IMDb ID directly for Stremio addons - if (__DEV__) console.log('✅ [loadEpisodeStreams] Collection movie - using IMDb ID:', episodeId, 'TMDB ID:', tmdbId); + if (__DEV__) logger.log('✅ [loadEpisodeStreams] Collection movie - using IMDb ID:', episodeId, 'TMDB ID:', tmdbId); } else { // Fallback: try to verify if it's a tmdb id const isTmdb = episodeId.startsWith('tmdb:') || !isNaN(Number(episodeId)); @@ -1992,20 +1915,20 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat } else { stremioEpisodeId = episodeId; } - if (__DEV__) console.log('âš ī¸ [loadEpisodeStreams] Collection movie - using episodeId as-is:', episodeId); + if (__DEV__) logger.log('âš ī¸ [loadEpisodeStreams] Collection movie - using episodeId as-is:', episodeId); } } else if (id.startsWith('tmdb:')) { tmdbId = id.split(':')[1]; - if (__DEV__) console.log('✅ [loadEpisodeStreams] Using TMDB ID from ID:', tmdbId); + if (__DEV__) logger.log('✅ [loadEpisodeStreams] Using TMDB ID from ID:', tmdbId); // Try to get IMDb ID from metadata first, then convert if needed if (metadata?.imdb_id) { // Use format: imdb_id:season:episode stremioEpisodeId = `${metadata.imdb_id}:${seasonNum}:${episodeNum}`; - if (__DEV__) console.log('✅ [loadEpisodeStreams] Using IMDb ID from metadata for Stremio episode:', stremioEpisodeId); + if (__DEV__) logger.log('✅ [loadEpisodeStreams] Using IMDb ID from metadata for Stremio episode:', stremioEpisodeId); } else if (imdbId) { stremioEpisodeId = `${imdbId}:${seasonNum}:${episodeNum}`; - if (__DEV__) console.log('✅ [loadEpisodeStreams] Using stored IMDb ID for Stremio episode:', stremioEpisodeId); + if (__DEV__) logger.log('✅ [loadEpisodeStreams] Using stored IMDb ID for Stremio episode:', stremioEpisodeId); } else { // Convert TMDB ID to IMDb ID for Stremio addons try { @@ -2013,27 +1936,27 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat if (externalIds?.imdb_id) { stremioEpisodeId = `${externalIds.imdb_id}:${seasonNum}:${episodeNum}`; - if (__DEV__) console.log('✅ [loadEpisodeStreams] Converted TMDB to IMDb ID for Stremio episode:', stremioEpisodeId); + if (__DEV__) logger.log('✅ [loadEpisodeStreams] Converted TMDB to IMDb ID for Stremio episode:', stremioEpisodeId); } else { // Fallback to TMDB format if conversions fail // e.g. tmdb:123:1:1 stremioEpisodeId = `${id}:${seasonNum}:${episodeNum}`; - if (__DEV__) console.log('âš ī¸ [loadEpisodeStreams] No IMDb ID found for TMDB ID, using TMDB episode ID:', stremioEpisodeId); + if (__DEV__) logger.log('âš ī¸ [loadEpisodeStreams] No IMDb ID found for TMDB ID, using TMDB episode ID:', stremioEpisodeId); } } catch (error) { stremioEpisodeId = `${id}:${seasonNum}:${episodeNum}`; - if (__DEV__) console.log('âš ī¸ [loadEpisodeStreams] Failed to convert TMDB to IMDb, using TMDB episode ID:', error); + if (__DEV__) logger.log('âš ī¸ [loadEpisodeStreams] Failed to convert TMDB to IMDb, using TMDB episode ID:', error); } } } else if (isImdb) { // This is already an IMDB ID, perfect for Stremio if (settings.enrichMetadataWithTMDB) { - if (__DEV__) console.log('📝 [loadEpisodeStreams] Converting IMDB ID to TMDB ID...'); + if (__DEV__) logger.log('📝 [loadEpisodeStreams] Converting IMDB ID to TMDB ID...'); tmdbId = await withTimeout(tmdbService.findTMDBIdByIMDB(id), API_TIMEOUT); } else { - if (__DEV__) console.log('📝 [loadEpisodeStreams] TMDB enrichment disabled, skipping IMDB to TMDB conversion'); + if (__DEV__) logger.log('📝 [loadEpisodeStreams] TMDB enrichment disabled, skipping IMDB to TMDB conversion'); } - if (__DEV__) console.log('✅ [loadEpisodeStreams] Converted to TMDB ID:', tmdbId); + if (__DEV__) logger.log('✅ [loadEpisodeStreams] Converted to TMDB ID:', tmdbId); // Ensure consistent format or fallback to episodeId if parsing failed. // If the episode's namespace differs from the show's tt id (e.g. kitsu:48363:8 @@ -2048,7 +1971,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const baseId = showIdStr && showIdStr !== id ? showIdStr : id; stremioEpisodeId = `${baseId}:${seasonNum}:${episodeNum}`; } - if (__DEV__) console.log('🔧 [loadEpisodeStreams] Normalized episode ID for addons:', stremioEpisodeId); + if (__DEV__) logger.log('🔧 [loadEpisodeStreams] Normalized episode ID for addons:', stremioEpisodeId); } else { tmdbId = id; // If season/episode parsing failed (empty strings), use the raw episode ID @@ -2067,22 +1990,22 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const baseId = showIdStr && showIdStr !== id ? showIdStr : id; stremioEpisodeId = `${baseId}:${seasonNum}:${episodeNum}`; } - if (__DEV__) console.log('â„šī¸ [loadEpisodeStreams] Using ID as both TMDB and Stremio ID:', tmdbId, '| stremioEpisodeId:', stremioEpisodeId); + if (__DEV__) logger.log('â„šī¸ [loadEpisodeStreams] Using ID as both TMDB and Stremio ID:', tmdbId, '| stremioEpisodeId:', stremioEpisodeId); } // Extract episode info from the episodeId for logging const episodeQuery = `?s=${seasonNum}&e=${episodeNum}`; - if (__DEV__) console.log(`â„šī¸ [loadEpisodeStreams] Episode query: ${episodeQuery}`); + if (__DEV__) logger.log(`â„šī¸ [loadEpisodeStreams] Episode query: ${episodeQuery}`); - if (__DEV__) console.log('🔄 [loadEpisodeStreams] Starting stream requests'); + if (__DEV__) logger.log('🔄 [loadEpisodeStreams] Starting stream requests'); // Start Stremio request using the converted episode ID format - if (__DEV__) console.log('đŸŽŦ [loadEpisodeStreams] Using episode ID for Stremio addons:', stremioEpisodeId); + if (__DEV__) logger.log('đŸŽŦ [loadEpisodeStreams] Using episode ID for Stremio addons:', stremioEpisodeId); // For collections, treat episodes as individual movies, not series // For other types (e.g. StreamsPPV), preserve the original type unless it's explicitly 'series' logic we want const contentType = isCollection ? 'movie' : type; - if (__DEV__) console.log(`đŸŽŦ [loadEpisodeStreams] Using content type: ${contentType} for ${isCollection ? 'collection' : type}`); + if (__DEV__) logger.log(`đŸŽŦ [loadEpisodeStreams] Using content type: ${contentType} for ${isCollection ? 'collection' : type}`); processStremioSource(contentType, stremioEpisodeId, true); @@ -2121,7 +2044,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat }, 60000); } catch (error) { - if (__DEV__) console.error('❌ [loadEpisodeStreams] Failed to load episode streams:', error); + if (__DEV__) logger.error('❌ [loadEpisodeStreams] Failed to load episode streams:', error); // Preserve the original error details for better error parsing const errorMessage = error instanceof Error ? error.message : 'Failed to load episode streams'; setError(errorMessage); @@ -2187,7 +2110,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat // This will be handled by the StreamsScreen component // The useMetadata hook focuses on metadata and episodes } catch (error) { - if (__DEV__) console.log('[useMetadata] Error checking cached streams on mount:', error); + if (__DEV__) logger.log('[useMetadata] Error checking cached streams on mount:', error); } }; @@ -2206,7 +2129,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat useEffect(() => { if (metadata && metadata.videos && metadata.videos.length > 0) { logger.log(`đŸŽŦ Metadata updated with ${metadata.videos.length} episodes, reloading series data`); - loadSeriesData().catch((error) => { if (__DEV__) console.error(error); }); + loadSeriesData().catch((error) => { if (__DEV__) logger.error(error); }); // Also extract embedded streams from metadata videos (PPV-style addons) extractEmbeddedStreams(); } @@ -2214,7 +2137,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const loadRecommendations = useCallback(async () => { if (!settings.enrichMetadataWithTMDB) { - if (__DEV__) console.log('[useMetadata] enrichment disabled; skip recommendations'); + if (__DEV__) logger.log('[useMetadata] enrichment disabled; skip recommendations'); return; } if (!tmdbId) return; @@ -2236,7 +2159,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat setRecommendations(formattedRecommendations); } catch (error) { - if (__DEV__) console.error('Failed to load recommendations:', error); + if (__DEV__) logger.error('Failed to load recommendations:', error); setRecommendations([]); } finally { setLoadingRecommendations(false); @@ -2253,7 +2176,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat // For anime IDs we always try to resolve tmdbId and imdbId regardless of enrichment setting, // because they're needed for Trakt scrobbling even when TMDB enrichment is disabled. if (!settings.enrichMetadataWithTMDB && !isAnimeId) { - if (__DEV__) console.log('[useMetadata] enrichment disabled; skip TMDB id extraction (extract path)'); + if (__DEV__) logger.log('[useMetadata] enrichment disabled; skip TMDB id extraction (extract path)'); return; } @@ -2262,7 +2185,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const tmdbSvc = TMDBService.getInstance(); const fetchedTmdbId = await tmdbSvc.extractTMDBIdFromStremioId(id); if (fetchedTmdbId) { - if (__DEV__) console.log('[useMetadata] extracted TMDB id from content id', { id, fetchedTmdbId }); + if (__DEV__) logger.log('[useMetadata] extracted TMDB id from content id', { id, fetchedTmdbId }); setTmdbId(fetchedTmdbId); // For anime IDs, also resolve the IMDb ID from TMDB external IDs so Trakt can scrobble @@ -2270,11 +2193,11 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat try { const externalIds = await tmdbSvc.getShowExternalIds(fetchedTmdbId); if (externalIds?.imdb_id) { - if (__DEV__) console.log('[useMetadata] resolved imdbId for anime via TMDB', { id, imdbId: externalIds.imdb_id }); + if (__DEV__) logger.log('[useMetadata] resolved imdbId for anime via TMDB', { id, imdbId: externalIds.imdb_id }); setImdbId(externalIds.imdb_id); } } catch (e) { - if (__DEV__) console.warn('[useMetadata] could not resolve imdbId from TMDB for anime ID', { id }); + if (__DEV__) logger.warn('[useMetadata] could not resolve imdbId from TMDB for anime ID', { id }); } } @@ -2289,24 +2212,24 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat if (settings.tmdbEnrichCertification) { const certification = await tmdbSvc.getCertification(normalizedType, fetchedTmdbId); if (certification) { - if (__DEV__) console.log('[useMetadata] fetched certification via TMDB id (extract path)', { type, fetchedTmdbId, certification }); + if (__DEV__) logger.log('[useMetadata] fetched certification via TMDB id (extract path)', { type, fetchedTmdbId, certification }); setMetadata(prev => prev ? { ...prev, tmdbId: fetchedTmdbId, certification } : null); } else { - if (__DEV__) console.warn('[useMetadata] certification not returned from TMDB (extract path)', { type, fetchedTmdbId }); + if (__DEV__) logger.warn('[useMetadata] certification not returned from TMDB (extract path)', { type, fetchedTmdbId }); } } else { // Just set the TMDB ID without certification setMetadata(prev => prev ? { ...prev, tmdbId: fetchedTmdbId } : null); } } else { - if (__DEV__) console.warn('[useMetadata] Could not determine TMDB ID for recommendations / certification', { id }); + if (__DEV__) logger.warn('[useMetadata] Could not determine TMDB ID for recommendations / certification', { id }); } } catch (error) { - if (__DEV__) console.error('[useMetadata] Error fetching TMDB ID (extract path):', error); + if (__DEV__) logger.error('[useMetadata] Error fetching TMDB ID (extract path):', error); } } }; @@ -2318,7 +2241,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat if (tmdbId) { // Check both master switch AND granular recommendations setting if (settings.enrichMetadataWithTMDB && settings.tmdbEnrichRecommendations) { - if (__DEV__) console.log('[useMetadata] tmdbId available; loading recommendations', { tmdbId }); + if (__DEV__) logger.log('[useMetadata] tmdbId available; loading recommendations', { tmdbId }); loadRecommendations(); } // Reset recommendations when tmdbId changes @@ -2343,32 +2266,32 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const maybeAttachCertification = async () => { // Check both master switch AND granular certification setting if (!settings.enrichMetadataWithTMDB || !settings.tmdbEnrichCertification) { - if (__DEV__) console.log('[useMetadata] certification enrichment disabled; skip (attach path)'); + if (__DEV__) logger.log('[useMetadata] certification enrichment disabled; skip (attach path)'); return; } try { if (!metadata) { - if (__DEV__) console.warn('[useMetadata] skip certification attach: metadata not ready'); + if (__DEV__) logger.warn('[useMetadata] skip certification attach: metadata not ready'); return; } if (!tmdbId) { - if (__DEV__) console.warn('[useMetadata] skip certification attach: tmdbId not available yet'); + if (__DEV__) logger.warn('[useMetadata] skip certification attach: tmdbId not available yet'); return; } if ((metadata as any).certification) { - if (__DEV__) console.log('[useMetadata] certification already present on metadata; skipping fetch'); + if (__DEV__) logger.log('[useMetadata] certification already present on metadata; skipping fetch'); return; } const tmdbSvc = TMDBService.getInstance(); const cert = await tmdbSvc.getCertification(normalizedType, tmdbId); if (cert) { - if (__DEV__) console.log('[useMetadata] fetched certification (attach path)', { type, tmdbId, cert }); + if (__DEV__) logger.log('[useMetadata] fetched certification (attach path)', { type, tmdbId, cert }); setMetadata(prev => prev ? { ...prev, tmdbId, certification: cert } : prev); } else { - if (__DEV__) console.warn('[useMetadata] TMDB returned no certification (attach path)', { type, tmdbId }); + if (__DEV__) logger.warn('[useMetadata] TMDB returned no certification (attach path)', { type, tmdbId }); } } catch (err) { - if (__DEV__) console.error('[useMetadata] error attaching certification', err); + if (__DEV__) logger.error('[useMetadata] error attaching certification', err); } }; maybeAttachCertification(); @@ -2405,7 +2328,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const tmdbService = TMDBService.getInstance(); let productionInfo: any[] = []; - if (__DEV__) console.log('[useMetadata] fetchProductionInfo starting', { + if (__DEV__) logger.log('[useMetadata] fetchProductionInfo starting', { contentKey, type, tmdbId, @@ -2423,7 +2346,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const lang = settings.useTmdbLocalizedMetadata ? (settings.tmdbLanguagePreference || 'en') : 'en'; const showDetails = await tmdbService.getTVShowDetails(tmdbId, lang); if (showDetails) { - if (__DEV__) console.log('[useMetadata] fetchProductionInfo got showDetails', { + if (__DEV__) logger.log('[useMetadata] fetchProductionInfo got showDetails', { hasNetworks: !!showDetails.networks, networksCount: showDetails.networks?.length || 0 }); @@ -2472,7 +2395,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat const lang = settings.useTmdbLocalizedMetadata ? (settings.tmdbLanguagePreference || 'en') : 'en'; const movieDetails = await tmdbService.getMovieDetails(String(tmdbId), lang); if (movieDetails) { - if (__DEV__) console.log('[useMetadata] fetchProductionInfo got movieDetails', { + if (__DEV__) logger.log('[useMetadata] fetchProductionInfo got movieDetails', { hasProductionCompanies: !!movieDetails.production_companies, productionCompaniesCount: movieDetails.production_companies?.length || 0 }); @@ -2557,7 +2480,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat } } } catch (error) { - if (__DEV__) console.warn('[useMetadata] Failed to fetch movie images for:', part.id, error); + if (__DEV__) logger.warn('[useMetadata] Failed to fetch movie images for:', part.id, error); } return { @@ -2592,7 +2515,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat })); } } catch (error) { - if (__DEV__) console.error('[useMetadata] Error fetching collection:', error); + if (__DEV__) logger.error('[useMetadata] Error fetching collection:', error); } finally { setLoadingCollection(false); } @@ -2604,7 +2527,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat setMetadata((prev: any) => ({ ...prev, networks: productionInfo })); } } catch (error) { - if (__DEV__) console.error('[useMetadata] Failed to fetch production info:', error); + if (__DEV__) logger.error('[useMetadata] Failed to fetch production info:', error); } }; @@ -2641,7 +2564,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat // Reset production info fetch tracking productionInfoFetchedRef.current = null; - if (__DEV__) console.log('[useMetadata] Component unmounted, memory cleaned up'); + if (__DEV__) logger.log('[useMetadata] Component unmounted, memory cleaned up'); }; }, [cleanupStreams]); diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx index 39597426..b789cbed 100644 --- a/src/navigation/AppNavigator.tsx +++ b/src/navigation/AppNavigator.tsx @@ -1941,10 +1941,8 @@ const ConditionalPostHogProvider: React.FC<{ children: React.ReactNode }> = ({ c if (posthogRef.current) { if (settings.analyticsEnabled) { posthogRef.current.optIn(); - console.log('[Telemetry] PostHog opted in'); } else { posthogRef.current.optOut(); - console.log('[Telemetry] PostHog opted out'); } } } @@ -1996,10 +1994,8 @@ const PostHogOptController: React.FC<{ onPostHogReady(posthog); if (enabled) { posthog.optIn(); - console.log('[Telemetry] PostHog opted in'); } else { posthog.optOut(); - console.log('[Telemetry] PostHog opted out'); } } }, [enabled, posthog, onPostHogReady]); diff --git a/src/screens/MDBListSettingsScreen.tsx b/src/screens/MDBListSettingsScreen.tsx index 93e9391a..9a433f70 100644 --- a/src/screens/MDBListSettingsScreen.tsx +++ b/src/screens/MDBListSettingsScreen.tsx @@ -26,39 +26,19 @@ import { useTheme } from '../contexts/ThemeContext'; import { logger } from '../utils/logger'; import { RATING_PROVIDERS } from '../components/metadata/RatingsSection'; import CustomAlert from '../components/CustomAlert'; // Moved CustomAlert import here +import { + MDBLIST_API_KEY_STORAGE_KEY, + MDBLIST_ENABLED_STORAGE_KEY, + RATING_PROVIDERS_STORAGE_KEY, + isMDBListEnabled, + getMDBListAPIKey, +} from '../services/mdblistConstants'; + +// Re-export for backwards compatibility +export { MDBLIST_API_KEY_STORAGE_KEY, RATING_PROVIDERS_STORAGE_KEY, MDBLIST_ENABLED_STORAGE_KEY, isMDBListEnabled, getMDBListAPIKey }; -export const MDBLIST_API_KEY_STORAGE_KEY = 'mdblist_api_key'; -export const RATING_PROVIDERS_STORAGE_KEY = 'rating_providers_config'; -export const MDBLIST_ENABLED_STORAGE_KEY = 'mdblist_enabled'; const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0; -// Function to check if MDBList is enabled -export const isMDBListEnabled = async (): Promise => { - try { - const enabledSetting = await mmkvStorage.getItem(MDBLIST_ENABLED_STORAGE_KEY); - return enabledSetting === 'true'; - } catch (error) { - logger.error('[MDBList] Error checking if MDBList is enabled:', error); - return false; // Default to disabled if there's an error - } -}; - -// Function to get MDBList API key if enabled -export const getMDBListAPIKey = async (): Promise => { - try { - const isEnabled = await isMDBListEnabled(); - if (!isEnabled) { - logger.log('[MDBList] MDBList is disabled, not retrieving API key'); - return null; - } - - return await mmkvStorage.getItem(MDBLIST_API_KEY_STORAGE_KEY); - } catch (error) { - logger.error('[MDBList] Error retrieving API key:', error); - return null; - } -}; - // Create a styles creator function that accepts the theme colors const createStyles = (colors: any) => StyleSheet.create({ container: { diff --git a/src/screens/MetadataScreen.tsx b/src/screens/MetadataScreen.tsx index c2538a04..f4a1f581 100644 --- a/src/screens/MetadataScreen.tsx +++ b/src/screens/MetadataScreen.tsx @@ -84,11 +84,19 @@ const BREAKPOINTS = { const MemoizedRatingsSection = memo(RatingsSection); const MemoizedCommentsSection = memo(CommentsSection); const MemoizedCastDetailsModal = memo(CastDetailsModal); +const noop = (..._args: unknown[]) => {}; +const logger = { + log: noop, + error: noop, + warn: noop, + info: noop, + debug: noop, +}; // ... other imports const MetadataScreen: React.FC = () => { - useEffect(() => { console.log('✅ MetadataScreen MOUNTED'); }, []); + useEffect(() => { logger.log('✅ MetadataScreen MOUNTED'); }, []); const navigation = useNavigation>(); const route = useRoute>(); const { id, type, episodeId, addonId } = route.params; @@ -184,16 +192,16 @@ const MetadataScreen: React.FC = () => { // Debug state changes React.useEffect(() => { - console.log('MetadataScreen: commentBottomSheetVisible changed to:', commentBottomSheetVisible); + logger.log('MetadataScreen: commentBottomSheetVisible changed to:', commentBottomSheetVisible); }, [commentBottomSheetVisible]); React.useEffect(() => { - console.log('MetadataScreen: selectedComment changed to:', selectedComment?.id); + logger.log('MetadataScreen: selectedComment changed to:', selectedComment?.id); }, [selectedComment]); // Log useMetadata hook state changes for debugging React.useEffect(() => { - console.log('🔍 [MetadataScreen] useMetadata state:', { + logger.log('🔍 [MetadataScreen] useMetadata state:', { loading, hasMetadata: !!metadata, metadataId: metadata?.id, @@ -357,7 +365,7 @@ const MetadataScreen: React.FC = () => { // Debug logging for color extraction timing useEffect(() => { if (__DEV__ && heroImageUri && dominantColor) { - if (__DEV__) console.log('[MetadataScreen] Dynamic background color:', { + if (__DEV__) logger.log('[MetadataScreen] Dynamic background color:', { dominantColor, fallback: currentTheme.colors.darkBackground, finalColor: dynamicBackgroundColor, @@ -422,7 +430,7 @@ const MetadataScreen: React.FC = () => { const isAuthenticated = await traktService.isAuthenticated(); if (!isAuthenticated) { - if (__DEV__) console.log(`[MetadataScreen] Not authenticated with Trakt`); + if (__DEV__) logger.log(`[MetadataScreen] Not authenticated with Trakt`); return; } @@ -449,7 +457,7 @@ const MetadataScreen: React.FC = () => { if (relevantProgress.length === 0) return; // Log only essential progress information for performance - if (__DEV__) console.log(`[MetadataScreen] Found ${relevantProgress.length} Trakt progress items for ${type}`); + if (__DEV__) logger.log(`[MetadataScreen] Found ${relevantProgress.length} Trakt progress items for ${type}`); // Find most recent progress if multiple episodes if (Object.keys(groupedEpisodes).length > 0 && relevantProgress.length > 1) { @@ -458,12 +466,12 @@ const MetadataScreen: React.FC = () => { )[0]; if (mostRecent.episode && mostRecent.show) { - if (__DEV__) console.log(`[MetadataScreen] Most recent: S${mostRecent.episode.season}E${mostRecent.episode.number} - ${mostRecent.progress.toFixed(1)}%`); + if (__DEV__) logger.log(`[MetadataScreen] Most recent: S${mostRecent.episode.season}E${mostRecent.episode.number} - ${mostRecent.progress.toFixed(1)}%`); } } } catch (error) { - if (__DEV__) console.error(`[MetadataScreen] Failed to fetch Trakt progress:`, error); + if (__DEV__) logger.error(`[MetadataScreen] Failed to fetch Trakt progress:`, error); } }, [shouldLoadSecondaryData, metadata, id, type]); @@ -495,7 +503,7 @@ const MetadataScreen: React.FC = () => { const timer = setTimeout(() => { const renderTime = Date.now() - startTime; if (renderTime > 100) { - if (__DEV__) console.warn(`[MetadataScreen] Slow render detected: ${renderTime}ms for ${metadata.name}`); + if (__DEV__) logger.warn(`[MetadataScreen] Slow render detected: ${renderTime}ms for ${metadata.name}`); } }, 0); return () => clearTimeout(timer); @@ -513,11 +521,11 @@ const MetadataScreen: React.FC = () => { const totalMB = Math.round(memory.totalJSHeapSize / 1048576); const limitMB = Math.round(memory.jsHeapSizeLimit / 1048576); - if (__DEV__) console.log(`[MetadataScreen] Memory usage: ${usedMB}MB / ${totalMB}MB (limit: ${limitMB}MB)`); + if (__DEV__) logger.log(`[MetadataScreen] Memory usage: ${usedMB}MB / ${totalMB}MB (limit: ${limitMB}MB)`); // Trigger cleanup if memory usage is high if (usedMB > limitMB * 0.8) { - if (__DEV__) console.warn(`[MetadataScreen] High memory usage detected (${usedMB}MB), triggering cleanup`); + if (__DEV__) logger.warn(`[MetadataScreen] High memory usage detected (${usedMB}MB), triggering cleanup`); // Force garbage collection if available if (global.gc) { global.gc(); @@ -536,16 +544,7 @@ const MetadataScreen: React.FC = () => { // Memoized derived values for performance const isReady = useMemo(() => !loading && metadata && !metadataError, [loading, metadata, metadataError]); - // Log readiness state for debugging - React.useEffect(() => { - console.log('🔍 [MetadataScreen] Readiness state:', { - isReady, - loading, - hasMetadata: !!metadata, - hasError: !!metadataError, - errorMessage: metadataError - }); - }, [isReady, loading, metadata, metadataError]); + // Optimized content ready state management useEffect(() => { @@ -627,13 +626,13 @@ const MetadataScreen: React.FC = () => { const nextEpisodeId = isImdb ? `${id}:${currentSeason || episodes[0]?.season_number || 1}:${currentEpisode + 1}` : `${id}:${currentEpisode + 1}`; - if (__DEV__) console.log(`[MetadataScreen] Created next episode ID: ${nextEpisodeId}`); + if (__DEV__) logger.log(`[MetadataScreen] Created next episode ID: ${nextEpisodeId}`); const nextEpisodeExists = episodes.some(ep => ep.episode_number === (currentEpisode + 1)); if (nextEpisodeExists) { - if (__DEV__) console.log(`[MetadataScreen] Verified next episode exists`); + if (__DEV__) logger.log(`[MetadataScreen] Verified next episode exists`); } else { - if (__DEV__) console.log(`[MetadataScreen] Warning: Next episode not found`); + if (__DEV__) logger.log(`[MetadataScreen] Warning: Next episode not found`); } targetEpisodeId = nextEpisodeId; @@ -643,7 +642,7 @@ const MetadataScreen: React.FC = () => { // Fallback logic: if not finished or nextEp not found if (!targetEpisodeId) { targetEpisodeId = watchProgress?.episodeId || episodeId || (episodes.length > 0 ? buildEpisodeId(episodes[0]) : undefined); - if (__DEV__) console.log(`[MetadataScreen] Using fallback episode ID: ${targetEpisodeId}`); + if (__DEV__) logger.log(`[MetadataScreen] Using fallback episode ID: ${targetEpisodeId}`); } if (targetEpisodeId) { @@ -657,7 +656,7 @@ const MetadataScreen: React.FC = () => { else if (epParts.length === 2 && isImdb) { normalizedEpisodeId = `${id}:${epParts[0]}:${epParts[1]}`; } - if (__DEV__) console.log(`[MetadataScreen] Navigating to streams with episodeId: ${normalizedEpisodeId}`); + if (__DEV__) logger.log(`[MetadataScreen] Navigating to streams with episodeId: ${normalizedEpisodeId}`); navigation.navigate('Streams', { id, type, episodeId: normalizedEpisodeId }); return; } @@ -671,14 +670,14 @@ const MetadataScreen: React.FC = () => { fallbackEpisodeId = isImdb ? `${id}:${p[0]}:${p[1]}` : `${id}:${p[1]}`; } } - if (__DEV__) console.log(`[MetadataScreen] Navigating with fallback episodeId: ${fallbackEpisodeId}`); + if (__DEV__) logger.log(`[MetadataScreen] Navigating with fallback episodeId: ${fallbackEpisodeId}`); navigation.navigate('Streams', { id, type, episodeId: fallbackEpisodeId }); }, [navigation, id, type, episodes, episodeId, watchProgressData.watchProgress]); const handleEpisodeSelect = useCallback((episode: Episode) => { if (!isScreenFocused) return; - if (__DEV__) console.log('[MetadataScreen] Selected Episode:', episode.episode_number, episode.season_number); + if (__DEV__) logger.log('[MetadataScreen] Selected Episode:', episode.episode_number, episode.season_number); let episodeId: string; if (episode.stremioId) { @@ -716,15 +715,11 @@ const MetadataScreen: React.FC = () => { }, [isScreenFocused]); const handleCommentPress = useCallback((comment: any) => { - console.log('MetadataScreen: handleCommentPress called with comment:', comment?.id); if (!isScreenFocused) { - console.log('MetadataScreen: Screen not focused, ignoring'); return; } - console.log('MetadataScreen: Setting selected comment and opening bottomsheet'); setSelectedComment(comment); setCommentBottomSheetVisible(true); - console.log('MetadataScreen: State should be updated now'); }, [isScreenFocused]); const handleCommentBottomSheetClose = useCallback(() => { @@ -774,7 +769,6 @@ const MetadataScreen: React.FC = () => { // Parse error to extract code and user-friendly message const parseError = (error: string) => { - console.log('🔍 Parsing error in MetadataScreen:', error); // Check for HTTP status codes - handle multiple formats // Match patterns like: "status code 500", "status": 500, "Request failed with status code 500" @@ -785,7 +779,6 @@ const MetadataScreen: React.FC = () => { if (statusCodeMatch) { const code = parseInt(statusCodeMatch[1]); - console.log('✅ Found status code:', code); switch (code) { case 404: return { code: '404', message: t('metadata.content_not_found'), userMessage: t('metadata.content_not_found_desc') }; @@ -893,13 +886,11 @@ const MetadataScreen: React.FC = () => { // Show error if exists if (metadataError || (!loading && !metadata)) { - console.log('❌ MetadataScreen ERROR state:', { metadataError, loading, hasMetadata: !!metadata }); return ErrorComponent; } // Show loading screen if metadata is not yet available or exit animation hasn't completed if (loading || !isContentReady || !loadingScreenExited) { - console.log('âŗ MetadataScreen LOADING state:', { loading, isContentReady, loadingScreenExited, hasMetadata: !!metadata }); return ( 0 && (now - this.lastFetch) < this.CACHE_TTL) { - console.log('[CampaignService] Using cached campaigns'); return this.getNextValidCampaign(); } const platform = Platform.OS; const url = `${CAMPAIGN_API_URL}/api/campaigns/queue?platform=${platform}`; - console.log('[CampaignService] Fetching from:', url); const response = await fetch( `${CAMPAIGN_API_URL}/api/campaigns/queue?platform=${platform}`, { @@ -100,14 +96,11 @@ class CampaignService { } }); - console.log('[CampaignService] Fetched campaigns:', campaigns.length, 'CAMPAIGN_API_URL:', CAMPAIGN_API_URL); - this.campaignQueue = campaigns; this.currentIndex = 0; this.lastFetch = now; const result = this.getNextValidCampaign(); - console.log('[CampaignService] Next valid campaign:', result?.id, result?.type); return result; } catch (error) { console.warn('[CampaignService] Error fetching campaigns:', error); diff --git a/src/services/catalog/content-details.ts b/src/services/catalog/content-details.ts index bfec521a..c30fb6e7 100644 --- a/src/services/catalog/content-details.ts +++ b/src/services/catalog/content-details.ts @@ -31,32 +31,19 @@ export async function getContentDetails( id: string, preferredAddonId?: string ): Promise { - console.log('🔍 [CatalogService] getContentDetails called:', { type, id, preferredAddonId }); - try { let meta = null; let lastError = null; for (let attempt = 0; attempt < 2; attempt += 1) { try { - console.log(`🔍 [CatalogService] Attempt ${attempt + 1}/2 for getContentDetails:`, { type, id, preferredAddonId }); const isValidId = await stremioService.isValidContentId(type, id); - console.log('🔍 [CatalogService] Content ID validation:', { type, id, isValidId }); if (!isValidId) { - console.log('🔍 [CatalogService] Invalid content ID, breaking retry loop'); break; } - - console.log('🔍 [CatalogService] Calling stremioService.getMetaDetails:', { type, id, preferredAddonId }); meta = await stremioService.getMetaDetails(type, id, preferredAddonId); - console.log('🔍 [CatalogService] stremioService.getMetaDetails result:', { - hasMeta: !!meta, - metaId: meta?.id, - metaName: meta?.name, - metaType: meta?.type, - }); if (meta) { break; @@ -65,61 +52,24 @@ export async function getContentDetails( await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt))); } catch (error) { lastError = error; - console.log(`🔍 [CatalogService] Attempt ${attempt + 1} failed:`, { - errorMessage: error instanceof Error ? error.message : String(error), - isAxiosError: (error as any)?.isAxiosError, - responseStatus: (error as any)?.response?.status, - responseData: (error as any)?.response?.data, - }); logger.error(`Attempt ${attempt + 1} failed to get content details for ${type}:${id}:`, error); await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt))); } } if (meta) { - console.log('🔍 [CatalogService] Meta found, converting to StreamingContent:', { - metaId: meta.id, - metaName: meta.name, - metaType: meta.type, - }); - const content = convertMetaToStreamingContentEnhanced(meta, state.library); addToRecentContent(state, content); content.inLibrary = state.library[createLibraryKey(type, id)] !== undefined; - console.log('🔍 [CatalogService] Successfully converted meta to StreamingContent:', { - contentId: content.id, - contentName: content.name, - contentType: content.type, - inLibrary: content.inLibrary, - }); - return content; } - console.log('🔍 [CatalogService] No meta found, checking lastError:', { - hasLastError: !!lastError, - lastErrorMessage: lastError instanceof Error ? lastError.message : String(lastError), - }); - if (lastError) { - console.log('🔍 [CatalogService] Throwing lastError:', { - errorMessage: lastError instanceof Error ? lastError.message : String(lastError), - isAxiosError: (lastError as any)?.isAxiosError, - responseStatus: (lastError as any)?.response?.status, - }); throw lastError; } - - console.log('🔍 [CatalogService] No meta and no error, returning null'); return null; } catch (error) { - console.log('🔍 [CatalogService] getContentDetails caught error:', { - errorMessage: error instanceof Error ? error.message : String(error), - isAxiosError: (error as any)?.isAxiosError, - responseStatus: (error as any)?.response?.status, - responseData: (error as any)?.response?.data, - }); logger.error(`Failed to get content details for ${type}:${id}:`, error); return null; } @@ -131,25 +81,11 @@ export async function getEnhancedContentDetails( id: string, preferredAddonId?: string ): Promise { - console.log('🔍 [CatalogService] getEnhancedContentDetails called:', { type, id, preferredAddonId }); - logger.log(`🔍 [MetadataScreen] Fetching enhanced metadata for ${type}:${id} ${preferredAddonId ? `from addon ${preferredAddonId}` : ''}`); try { const result = await getContentDetails(state, type, id, preferredAddonId); - console.log('🔍 [CatalogService] getEnhancedContentDetails result:', { - hasResult: !!result, - resultId: result?.id, - resultName: result?.name, - resultType: result?.type, - }); return result; } catch (error) { - console.log('🔍 [CatalogService] getEnhancedContentDetails error:', { - errorMessage: error instanceof Error ? error.message : String(error), - isAxiosError: (error as any)?.isAxiosError, - responseStatus: (error as any)?.response?.status, - responseData: (error as any)?.response?.data, - }); throw error; } } @@ -201,81 +137,29 @@ export async function getBasicContentDetails( } export async function getStremioId(type: string, tmdbId: string): Promise { - if (__DEV__) { - console.log('=== CatalogService.getStremioId ==='); - console.log('Input type:', type); - console.log('Input tmdbId:', tmdbId); - } - try { if (type === 'movie') { - if (__DEV__) { - console.log('Processing movie - fetching TMDB details...'); - } - const movieDetails = await TMDBService.getInstance().getMovieDetails(tmdbId); - if (__DEV__) { - console.log('Movie details result:', { - id: movieDetails?.id, - title: movieDetails?.title, - imdb_id: movieDetails?.imdb_id, - hasImdbId: !!movieDetails?.imdb_id, - }); - } - if (movieDetails?.imdb_id) { - if (__DEV__) { - console.log('Successfully found IMDb ID:', movieDetails.imdb_id); - } return movieDetails.imdb_id; } - - console.warn('No IMDb ID found for movie:', tmdbId); return null; } if (type === 'tv' || type === 'series') { - if (__DEV__) { - console.log('Processing TV show - fetching TMDB details for IMDb ID...'); - } - const externalIds = await TMDBService.getInstance().getShowExternalIds(parseInt(tmdbId, 10)); - if (__DEV__) { - console.log('TV show external IDs result:', { - tmdbId, - imdb_id: externalIds?.imdb_id, - hasImdbId: !!externalIds?.imdb_id, - }); - } - if (externalIds?.imdb_id) { - if (__DEV__) { - console.log('Successfully found IMDb ID for TV show:', externalIds.imdb_id); - } return externalIds.imdb_id; } - console.warn('No IMDb ID found for TV show, falling back to kitsu format:', tmdbId); const fallbackId = `kitsu:${tmdbId}`; - if (__DEV__) { - console.log('Generated fallback Stremio ID for TV:', fallbackId); - } return fallbackId; } - console.warn('Unknown type provided:', type); return null; } catch (error: any) { - if (__DEV__) { - console.error('=== Error in getStremioId ==='); - console.error('Type:', type); - console.error('TMDB ID:', tmdbId); - console.error('Error details:', error); - console.error('Error message:', error.message); - } - logger.error('Error getting Stremio ID:', error); return null; } diff --git a/src/services/catalog/library.ts b/src/services/catalog/library.ts index 2751b396..fe99eb3e 100644 --- a/src/services/catalog/library.ts +++ b/src/services/catalog/library.ts @@ -1,9 +1,13 @@ -import { notificationService } from '../notificationService'; import { mmkvStorage } from '../mmkvStorage'; import { logger } from '../../utils/logger'; import type { StreamingContent } from './types'; +// Lazy import to break require cycle: +// catalogService -> content-details -> content-mappers -> library -> notificationService -> catalogService +const getNotificationService = () => + require('../notificationService').notificationService; + export interface CatalogLibraryState { LEGACY_LIBRARY_KEY: string; RECENT_CONTENT_KEY: string; @@ -259,10 +263,9 @@ export async function addToLibrary(state: CatalogLibraryState, content: Streamin if (content.type === 'series') { try { - await notificationService.updateNotificationsForSeries(content.id); - console.log(`[CatalogService] Auto-setup notifications for series: ${content.name}`); + await getNotificationService().updateNotificationsForSeries(content.id); } catch (error) { - console.error(`[CatalogService] Failed to setup notifications for ${content.name}:`, error); + logger.error(`[CatalogService] Failed to setup notifications for ${content.name}:`, error); } } } @@ -299,16 +302,14 @@ export async function removeFromLibrary( if (type === 'series') { try { - const scheduledNotifications = notificationService.getScheduledNotifications(); - const seriesToCancel = scheduledNotifications.filter(notification => notification.seriesId === id); + const scheduledNotifications = getNotificationService().getScheduledNotifications(); + const seriesToCancel = scheduledNotifications.filter((notification: any) => notification.seriesId === id); for (const notification of seriesToCancel) { - await notificationService.cancelNotification(notification.id); + await getNotificationService().cancelNotification(notification.id); } - - console.log(`[CatalogService] Cancelled ${seriesToCancel.length} notifications for removed series: ${id}`); } catch (error) { - console.error(`[CatalogService] Failed to cancel notifications for removed series ${id}:`, error); + logger.error(`[CatalogService] Failed to cancel notifications for removed series ${id}:`, error); } } } diff --git a/src/services/mdblistConstants.ts b/src/services/mdblistConstants.ts new file mode 100644 index 00000000..94949a5d --- /dev/null +++ b/src/services/mdblistConstants.ts @@ -0,0 +1,31 @@ +import { mmkvStorage } from './mmkvStorage'; +import { logger } from '../utils/logger'; + +export const MDBLIST_API_KEY_STORAGE_KEY = 'mdblist_api_key'; +export const MDBLIST_ENABLED_STORAGE_KEY = 'mdblist_enabled'; +export const RATING_PROVIDERS_STORAGE_KEY = 'rating_providers_config'; + +// Function to check if MDBList is enabled +export const isMDBListEnabled = async (): Promise => { + try { + const enabledSetting = await mmkvStorage.getItem(MDBLIST_ENABLED_STORAGE_KEY); + return enabledSetting === 'true'; + } catch (error) { + logger.error('[MDBList] Error checking if MDBList is enabled:', error); + return false; + } +}; + +// Function to get MDBList API key if enabled +export const getMDBListAPIKey = async (): Promise => { + try { + const isEnabled = await isMDBListEnabled(); + if (!isEnabled) { + return null; + } + return await mmkvStorage.getItem(MDBLIST_API_KEY_STORAGE_KEY); + } catch (error) { + logger.error('[MDBList] Error getting API key:', error); + return null; + } +}; diff --git a/src/services/mdblistService.ts b/src/services/mdblistService.ts index e6959e38..9b867bbe 100644 --- a/src/services/mdblistService.ts +++ b/src/services/mdblistService.ts @@ -3,8 +3,7 @@ import { logger } from '../utils/logger'; import { MDBLIST_API_KEY_STORAGE_KEY, MDBLIST_ENABLED_STORAGE_KEY, - isMDBListEnabled -} from '../screens/MDBListSettingsScreen'; +} from './mdblistConstants'; export interface MDBListRatings { trakt?: number; diff --git a/src/services/telemetryService.ts b/src/services/telemetryService.ts index d29844bf..20ac59d7 100644 --- a/src/services/telemetryService.ts +++ b/src/services/telemetryService.ts @@ -148,7 +148,6 @@ class TelemetryService { } this.initialized = true; - console.log('[TelemetryService] Initialized with settings:', this.settings); } catch (error) { console.error('[TelemetryService] Error initializing:', error); // Use defaults on error diff --git a/src/utils/logger.ts b/src/utils/logger.ts index f5952ede..445592f9 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -3,7 +3,7 @@ class Logger { constructor() { // __DEV__ is a global variable in React Native - this.isEnabled = __DEV__; + this.isEnabled = false; } log(...args: any[]) { @@ -37,4 +37,4 @@ class Logger { } } -export const logger = new Logger(); \ No newline at end of file +export const logger = new Logger();