NuvioStreaming/src/services/robustCalendarCache.ts
2025-09-09 00:33:30 +05:30

102 lines
No EOL
4.1 KiB
TypeScript

import AsyncStorage from '@react-native-async-storage/async-storage';
import { logger } from '../utils/logger';
// Define the structure of cached data
interface CachedData<T> {
timestamp: number;
hash: string;
data: T;
}
// Define the structure for Trakt collections
interface TraktCollections {
watchlist: any[];
continueWatching: any[];
watched?: any[];
}
const THIS_WEEK_CACHE_KEY = 'this_week_episodes_cache';
const CALENDAR_CACHE_KEY = 'calendar_data_cache';
const CACHE_DURATION_MS = 30 * 60 * 1000; // 30 minutes (increased to reduce API calls)
const ERROR_CACHE_DURATION_MS = 5 * 60 * 1000; // 5 minutes for error recovery
class RobustCalendarCache {
private generateHash(libraryItems: any[], traktCollections: TraktCollections): string {
const libraryIds = libraryItems.map(item => item.id).sort().join('|');
const watchlistIds = (traktCollections.watchlist || []).map(item => item.show?.ids?.imdb || '').filter(Boolean).sort().join('|');
const continueWatchingIds = (traktCollections.continueWatching || []).map(item => item.show?.ids?.imdb || '').filter(Boolean).sort().join('|');
const watchedIds = (traktCollections.watched || []).map(item => item.show?.ids?.imdb || '').filter(Boolean).sort().join('|');
return `${libraryIds}:${watchlistIds}:${continueWatchingIds}:${watchedIds}`;
}
private async getCachedData<T>(key: string, libraryItems: any[], traktCollections: TraktCollections): Promise<T | null> {
try {
const storedCache = await AsyncStorage.getItem(key);
if (!storedCache) return null;
const cache: CachedData<T> = JSON.parse(storedCache);
const currentHash = this.generateHash(libraryItems, traktCollections);
if (cache.hash !== currentHash) {
logger.log(`[Cache] Hash mismatch for key ${key}, cache invalidated`);
return null;
}
const isCacheExpired = Date.now() - cache.timestamp > CACHE_DURATION_MS;
if (isCacheExpired) {
logger.log(`[Cache] Cache expired for key ${key}`);
return null;
}
logger.log(`[Cache] Valid cache found for key ${key}`);
return cache.data;
} catch (error) {
logger.error(`[Cache] Error getting cached data for key ${key}:`, error);
return null;
}
}
private async setCachedData<T>(key: string, data: T, libraryItems: any[], traktCollections: TraktCollections, isErrorRecovery = false): Promise<void> {
try {
const hash = this.generateHash(libraryItems, traktCollections);
const cache: CachedData<T> = {
timestamp: Date.now(),
hash,
data,
};
if (isErrorRecovery) {
// Use a shorter cache duration for error states
cache.timestamp = Date.now() - CACHE_DURATION_MS + ERROR_CACHE_DURATION_MS;
logger.log(`[Cache] Saving error recovery cache for key ${key}`);
} else {
logger.log(`[Cache] Saving successful data to cache for key ${key}`);
}
await AsyncStorage.setItem(key, JSON.stringify(cache));
} catch (error) {
logger.error(`[Cache] Error setting cached data for key ${key}:`, error);
}
}
// Methods for This Week section
public async getCachedThisWeekData(libraryItems: any[], traktCollections: TraktCollections): Promise<any[] | null> {
return this.getCachedData<any[]>(THIS_WEEK_CACHE_KEY, libraryItems, traktCollections);
}
public async setCachedThisWeekData(data: any[], libraryItems: any[], traktCollections: TraktCollections, isErrorRecovery = false): Promise<void> {
await this.setCachedData<any[]>(THIS_WEEK_CACHE_KEY, data, libraryItems, traktCollections, isErrorRecovery);
}
// Methods for Calendar screen
public async getCachedCalendarData(libraryItems: any[], traktCollections: TraktCollections): Promise<any[] | null> {
return this.getCachedData<any[]>(CALENDAR_CACHE_KEY, libraryItems, traktCollections);
}
public async setCachedCalendarData(data: any[], libraryItems: any[], traktCollections: TraktCollections, isErrorRecovery = false): Promise<void> {
await this.setCachedData<any[]>(CALENDAR_CACHE_KEY, data, libraryItems, traktCollections, isErrorRecovery);
}
}
export const robustCalendarCache = new RobustCalendarCache();