From 8e34fbb12469c729a71bdec868abf6b505890d49 Mon Sep 17 00:00:00 2001 From: tapframe Date: Mon, 3 Nov 2025 15:36:26 +0530 Subject: [PATCH] crash fix --- .env.example | 6 + .gitignore | 1 + src/components/metadata/SeriesContent.tsx | 15 +- src/screens/.ShowRatingsScreen.tsx.swp | Bin 16384 -> 0 bytes src/services/tmdbService.ts | 188 +++++++++++++++------- 5 files changed, 147 insertions(+), 63 deletions(-) delete mode 100644 src/screens/.ShowRatingsScreen.tsx.swp diff --git a/.env.example b/.env.example index baa65525..c088715d 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,12 @@ EXPO_PUBLIC_SUPABASE_URL=your_supabase_project_url EXPO_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key +# Remote cache for TMDB (optional) +# Set to true to use local/remote cache server, and provide URL +EXPO_PUBLIC_USE_REMOTE_CACHE=false +EXPO_PUBLIC_CACHE_SERVER_URL=http://localhost:5173 +EXPO_PUBLIC_DISABLE_LOCAL_CACHE=false + # MovieBox (MoviesMod) Keys EXPO_PUBLIC_MOVIEBOX_PRIMARY_KEY=your_moviebox_primary_key EXPO_PUBLIC_MOVIEBOX_TMDB_API_KEY=your_tmdb_api_key_for_moviebox diff --git a/.gitignore b/.gitignore index 1ce445fb..91b38442 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ bottomnav.md mmkv.md src/services/tmdbService.ts fix-android-scroll-lag-summary.md +server/cache-server \ No newline at end of file diff --git a/src/components/metadata/SeriesContent.tsx b/src/components/metadata/SeriesContent.tsx index 3a6b3e42..2b266b9b 100644 --- a/src/components/metadata/SeriesContent.tsx +++ b/src/components/metadata/SeriesContent.tsx @@ -499,6 +499,13 @@ export const SeriesContent: React.FC = ({ + // Helper function to get IMDb rating for an episode - O(1) lookup using map + const getIMDbRating = useCallback((seasonNumber: number, episodeNumber: number): number | null => { + const key = `${seasonNumber}:${episodeNumber}`; + const rating = imdbRatingsMap[key]; + return rating ?? null; + }, [imdbRatingsMap]); + if (loadingSeasons) { return ( @@ -717,13 +724,6 @@ export const SeriesContent: React.FC = ({ ); }; - // Helper function to get IMDb rating for an episode - O(1) lookup using map - const getIMDbRating = useCallback((seasonNumber: number, episodeNumber: number): number | null => { - const key = `${seasonNumber}:${episodeNumber}`; - const rating = imdbRatingsMap[key]; - return rating ?? null; - }, [imdbRatingsMap]); - // Vertical layout episode card (traditional) const renderVerticalEpisodeCard = (episode: Episode) => { // Resolve episode image with addon-first logic @@ -1579,6 +1579,7 @@ const styles = StyleSheet.create({ flexDirection: 'row', alignItems: 'center', // chip background removed + minWidth: 52, // reserve space so following items (rating) don't shift }, runtimeText: { fontSize: 13, diff --git a/src/screens/.ShowRatingsScreen.tsx.swp b/src/screens/.ShowRatingsScreen.tsx.swp deleted file mode 100644 index 66357af5455c32c989b52965c0288105ba6160a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 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 diff --git a/src/services/tmdbService.ts b/src/services/tmdbService.ts index 3940cb9e..99ba7033 100644 --- a/src/services/tmdbService.ts +++ b/src/services/tmdbService.ts @@ -7,6 +7,12 @@ const DEFAULT_API_KEY = 'd131017ccc6e5462a81c9304d21476de'; const BASE_URL = 'https://api.themoviedb.org/3'; const TMDB_API_KEY_STORAGE_KEY = 'tmdb_api_key'; const USE_CUSTOM_TMDB_API_KEY = 'use_custom_tmdb_api_key'; +// Remote cache configuration +const REMOTE_CACHE_URL = process.env.EXPO_PUBLIC_CACHE_SERVER_URL; +const USE_REMOTE_CACHE = process.env.EXPO_PUBLIC_USE_REMOTE_CACHE === 'true'; +const REMOTE_CACHE_NAMESPACE = 'tmdb'; +// Allow temporarily disabling local MMKV cache (read/write) +const DISABLE_LOCAL_CACHE = process.env.EXPO_PUBLIC_DISABLE_LOCAL_CACHE === 'true'; // Cache configuration const TMDB_CACHE_PREFIX = 'tmdb_cache_'; @@ -134,6 +140,52 @@ export class TMDBService { this.loadApiKey(); } + /** + * Remote cache helpers + */ + private async remoteGetCachedData(key: string): Promise { + if (!USE_REMOTE_CACHE || !REMOTE_CACHE_URL) return null; + try { + const url = `${REMOTE_CACHE_URL}/cache/${REMOTE_CACHE_NAMESPACE}/${encodeURIComponent(key)}`; + const response = await axios.get(url, { headers: { 'Content-Type': 'application/json' } }); + const payload = response.data; + if (payload && Object.prototype.hasOwnProperty.call(payload, 'data')) { + // Warm local cache for faster subsequent reads (skip if disabled) + if (!DISABLE_LOCAL_CACHE) { + this.setCachedData(key, payload.data); + } + logger.log(`[TMDB Remote Cache] ✅ HIT: ${key}`); + return payload.data as T; + } + return null; + } catch (_) { + logger.log(`[TMDB Remote Cache] ❌ MISS: ${key}`); + return null; + } + } + + private async remoteSetCachedData(key: string, data: any): Promise { + if (!USE_REMOTE_CACHE || !REMOTE_CACHE_URL) return; + try { + const url = `${REMOTE_CACHE_URL}/cache/${REMOTE_CACHE_NAMESPACE}/${encodeURIComponent(key)}`; + await axios.put(url, { data, ttlMs: CACHE_TTL_MS }, { headers: { 'Content-Type': 'application/json' } }); + logger.log(`[TMDB Remote Cache] 💾 STORED: ${key}`); + } catch (_) { + // best-effort only + } + } + + private async remoteClearAllCache(): Promise { + if (!USE_REMOTE_CACHE || !REMOTE_CACHE_URL) return; + try { + const url = `${REMOTE_CACHE_URL}/cache/${REMOTE_CACHE_NAMESPACE}/clear`; + await axios.post(url, {}, { headers: { 'Content-Type': 'application/json' } }); + logger.log(`[TMDB Remote Cache] 🗑️ CLEARED namespace ${REMOTE_CACHE_NAMESPACE}`); + } catch (_) { + // ignore + } + } + /** * Generate a unique cache key from endpoint and parameters */ @@ -154,6 +206,10 @@ export class TMDBService { * Retrieve cached data if not expired */ private getCachedData(key: string): T | null { + if (DISABLE_LOCAL_CACHE) { + logger.log(`[TMDB Cache] 🚫 LOCAL DISABLED: ${key}`); + return null; + } try { const cachedStr = mmkvStorage.getString(key); if (!cachedStr) { @@ -180,6 +236,19 @@ export class TMDBService { } } + private async getFromCacheOrRemote(key: string): Promise { + // Local-first: serve from MMKV if present; else try remote and warm local + if (!DISABLE_LOCAL_CACHE) { + const local = this.getCachedData(key); + if (local !== null) return local; + } + if (USE_REMOTE_CACHE && REMOTE_CACHE_URL) { + const remote = await this.remoteGetCachedData(key); + if (remote !== null) return remote; + } + return null; + } + /** * Store data in cache with timestamp * Only called after successful API responses - never caches error responses @@ -193,12 +262,19 @@ export class TMDBService { } try { + if (!DISABLE_LOCAL_CACHE) { const cacheEntry = { data, timestamp: Date.now() }; mmkvStorage.setString(key, JSON.stringify(cacheEntry)); logger.log(`[TMDB Cache] 💾 STORED: ${key}`); + } else { + logger.log(`[TMDB Cache] ⛔ LOCAL WRITE SKIPPED: ${key}`); + } + // Best-effort remote write + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this.remoteSetCachedData(key, data); } catch (error) { // Ignore cache errors } @@ -285,8 +361,8 @@ export class TMDBService { async searchTVShow(query: string): Promise { const cacheKey = this.generateCacheKey('search_tv', { query }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; logger.log(`[TMDB API] 🌐 FETCHING: searchTVShow("${query}")`); @@ -314,8 +390,8 @@ export class TMDBService { async getTVShowDetails(tmdbId: number, language: string = 'en'): Promise { const cacheKey = this.generateCacheKey(`tv_${tmdbId}`, { language }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -344,8 +420,8 @@ export class TMDBService { ): Promise<{ imdb_id: string | null } | null> { const cacheKey = this.generateCacheKey(`tv_${tmdbId}_season_${seasonNumber}_episode_${episodeNumber}_external_ids`); - // Check cache - const cached = this.getCachedData<{ imdb_id: string | null }>(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote<{ imdb_id: string | null }>(cacheKey); if (cached !== null) return cached; try { @@ -416,8 +492,8 @@ export class TMDBService { const cacheKey = this.generateCacheKey(`imdb_ratings_${tmdbId}`); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; const apiUrl = `${IMDB_RATINGS_API_BASE_URL}/api/shows/${tmdbId}/season-ratings`; @@ -450,8 +526,8 @@ export class TMDBService { async getSeasonDetails(tmdbId: number, seasonNumber: number, showName?: string, language: string = 'en-US'): Promise { const cacheKey = this.generateCacheKey(`tv_${tmdbId}_season_${seasonNumber}`, { language, showName }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -481,8 +557,8 @@ export class TMDBService { ): Promise { const cacheKey = this.generateCacheKey(`tv_${tmdbId}_season_${seasonNumber}_episode_${episodeNumber}`, { language }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -528,8 +604,8 @@ export class TMDBService { async findTMDBIdByIMDB(imdbId: string): Promise { const cacheKey = this.generateCacheKey('find_imdb', { imdbId }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -654,8 +730,8 @@ export class TMDBService { async getCredits(tmdbId: number, type: string) { const cacheKey = this.generateCacheKey(`${type}_${tmdbId}_credits`); - // Check cache - const cached = this.getCachedData<{ cast: any[]; crew: any[] }>(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote<{ cast: any[]; crew: any[] }>(cacheKey); if (cached !== null) return cached; try { @@ -679,8 +755,8 @@ export class TMDBService { async getPersonDetails(personId: number) { const cacheKey = this.generateCacheKey(`person_${personId}`); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -704,8 +780,8 @@ export class TMDBService { async getPersonMovieCredits(personId: number) { const cacheKey = this.generateCacheKey(`person_${personId}_movie_credits`); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -729,8 +805,8 @@ export class TMDBService { async getPersonTvCredits(personId: number) { const cacheKey = this.generateCacheKey(`person_${personId}_tv_credits`); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -754,8 +830,8 @@ export class TMDBService { async getPersonCombinedCredits(personId: number) { const cacheKey = this.generateCacheKey(`person_${personId}_combined_credits`); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -779,8 +855,8 @@ export class TMDBService { async getShowExternalIds(tmdbId: number): Promise<{ imdb_id: string | null } | null> { const cacheKey = this.generateCacheKey(`tv_${tmdbId}_external_ids`); - // Check cache - const cached = this.getCachedData<{ imdb_id: string | null }>(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote<{ imdb_id: string | null }>(cacheKey); if (cached !== null) return cached; try { @@ -806,8 +882,8 @@ export class TMDBService { const cacheKey = this.generateCacheKey(`${type}_${tmdbId}_recommendations`, { language }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -826,8 +902,8 @@ export class TMDBService { async searchMulti(query: string): Promise { const cacheKey = this.generateCacheKey('search_multi', { query }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -854,8 +930,8 @@ export class TMDBService { async getMovieDetails(movieId: string, language: string = 'en'): Promise { const cacheKey = this.generateCacheKey(`movie_${movieId}`, { language }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -880,8 +956,8 @@ export class TMDBService { async getCollectionDetails(collectionId: number, language: string = 'en'): Promise { const cacheKey = this.generateCacheKey(`collection_${collectionId}`, { language }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -905,8 +981,8 @@ export class TMDBService { async getCollectionImages(collectionId: number, language: string = 'en'): Promise { const cacheKey = this.generateCacheKey(`collection_${collectionId}_images`, { language }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -931,8 +1007,8 @@ export class TMDBService { async getMovieImagesFull(movieId: number | string, language: string = 'en'): Promise { const cacheKey = this.generateCacheKey(`movie_${movieId}_images_full`, { language }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) { return cached; } @@ -1086,8 +1162,8 @@ export class TMDBService { async getTvShowImagesFull(showId: number | string, language: string = 'en'): Promise { const cacheKey = this.generateCacheKey(`tv_${showId}_images_full`, { language }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -1112,8 +1188,8 @@ export class TMDBService { async getTvShowImages(showId: number | string, preferredLanguage: string = 'en'): Promise { const cacheKey = this.generateCacheKey(`tv_${showId}_logo`, { preferredLanguage }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -1330,8 +1406,8 @@ export class TMDBService { async getTrending(type: 'movie' | 'tv', timeWindow: 'day' | 'week'): Promise { const cacheKey = this.generateCacheKey(`trending_${type}_${timeWindow}`); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -1379,8 +1455,8 @@ export class TMDBService { async getPopular(type: 'movie' | 'tv', page: number = 1): Promise { const cacheKey = this.generateCacheKey(`popular_${type}`, { page }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -1429,8 +1505,8 @@ export class TMDBService { async getUpcoming(type: 'movie' | 'tv', page: number = 1): Promise { const cacheKey = this.generateCacheKey(`upcoming_${type}`, { page }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -1482,8 +1558,8 @@ export class TMDBService { async getNowPlaying(page: number = 1, region: string = 'US'): Promise { const cacheKey = this.generateCacheKey('now_playing', { page, region }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try { @@ -1531,8 +1607,8 @@ export class TMDBService { async getMovieGenres(): Promise<{ id: number; name: string }[]> { const cacheKey = this.generateCacheKey('genres_movie'); - // Check cache - const cached = this.getCachedData<{ id: number; name: string }[]>(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote<{ id: number; name: string }[]>(cacheKey); if (cached !== null) return cached; try { @@ -1556,8 +1632,8 @@ export class TMDBService { async getTvGenres(): Promise<{ id: number; name: string }[]> { const cacheKey = this.generateCacheKey('genres_tv'); - // Check cache - const cached = this.getCachedData<{ id: number; name: string }[]>(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote<{ id: number; name: string }[]>(cacheKey); if (cached !== null) return cached; try { @@ -1584,8 +1660,8 @@ export class TMDBService { async discoverByGenre(type: 'movie' | 'tv', genreName: string, page: number = 1): Promise { const cacheKey = this.generateCacheKey(`discover_${type}`, { genreName, page }); - // Check cache - const cached = this.getCachedData(cacheKey); + // Check cache (local or remote) + const cached = await this.getFromCacheOrRemote(cacheKey); if (cached !== null) return cached; try {