From d4947325537a32737f41f1ead562afc199cd2f89 Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Tue, 17 Mar 2026 06:34:13 +0530 Subject: [PATCH] added catalog load timeout --- src/screens/HomeScreen.tsx | 59 +++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 65eb0491..b7baa4c0 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -76,6 +76,26 @@ import { useScrollToTop } from '../contexts/ScrollToTopContext'; const CATALOG_SETTINGS_KEY = 'catalog_settings'; const MAX_CONCURRENT_CATALOG_REQUESTS = 4; const HOME_LOADING_SCREEN_TIMEOUT_MS = 5000; +const HOME_CATALOG_REQUEST_TIMEOUT_MS = 20000; + +const withTimeout = async (promise: Promise, timeoutMs: number): Promise => { + return new Promise((resolve, reject) => { + const timeoutId = setTimeout(() => { + reject(new Error(`Request timed out after ${timeoutMs}ms`)); + }, timeoutMs); + + promise.then( + (result) => { + clearTimeout(timeoutId); + resolve(result); + }, + (error) => { + clearTimeout(timeoutId); + reject(error); + } + ); + }); +}; // In-memory cache for catalog settings to avoid repeated MMKV reads let cachedCatalogSettings: Record | null = null; @@ -134,6 +154,7 @@ const HomeScreen = () => { const [catalogs, setCatalogs] = useState<(CatalogContent | null)[]>([]); const [catalogsLoading, setCatalogsLoading] = useState(true); const [loadedCatalogCount, setLoadedCatalogCount] = useState(0); + const [pendingCatalogIndexes, setPendingCatalogIndexes] = useState>({}); const [hasAddons, setHasAddons] = useState(null); const [hintVisible, setHintVisible] = useState(false); const [loadingScreenTimedOut, setLoadingScreenTimedOut] = useState(false); @@ -192,6 +213,7 @@ const HomeScreen = () => { setCatalogsLoading(true); setCatalogs([]); setLoadedCatalogCount(0); + setPendingCatalogIndexes({}); try { // Check cache first @@ -279,13 +301,17 @@ const HomeScreen = () => { if (isEnabled) { const currentIndex = catalogIndex; - const catalogLoader = async () => { - try { - const manifest = manifestByAddonId.get(addon.id); - if (!manifest) return; + const catalogLoader = async () => { + try { + const manifest = manifestByAddonId.get(addon.id); + if (!manifest) return; - const metas = await stremioService.getCatalog(manifest, catalog.type, catalog.id, 1); - if (metas && metas.length > 0) { + const metas = await withTimeout( + stremioService.getCatalog(manifest, catalog.type, catalog.id, 1), + HOME_CATALOG_REQUEST_TIMEOUT_MS + ); + + if (metas && metas.length > 0) { // Aggressively limit items per catalog on Android to reduce memory usage const limit = Platform.OS === 'android' ? 18 : 30; const limitedMetas = metas.slice(0, limit); @@ -344,6 +370,15 @@ const HomeScreen = () => { } catch (error) { if (__DEV__) console.error(`[HomeScreen] Failed to load ${catalog.name} from ${addon.name}:`, error); } finally { + setPendingCatalogIndexes((prev) => { + if (!prev[currentIndex]) { + return prev; + } + const next = { ...prev }; + delete next[currentIndex]; + return next; + }); + // Update loading count - ensure on main thread InteractionManager.runAfterInteractions(() => { setLoadedCatalogCount(prev => { @@ -362,8 +397,12 @@ const HomeScreen = () => { } }; - catalogQueue.push(catalogLoader); - catalogIndex++; + catalogQueue.push(catalogLoader); + setPendingCatalogIndexes((prev) => ({ + ...prev, + [currentIndex]: true, + })); + catalogIndex++; } } } @@ -722,7 +761,7 @@ const HomeScreen = () => { catalogsToShow.forEach((catalog, index) => { if (catalog) { data.push({ type: 'catalog', catalog, key: `${catalog.addon}-${catalog.id}-${index}` }); - } else { + } else if (catalogsLoading && pendingCatalogIndexes[index]) { // Add a key for placeholders data.push({ type: 'placeholder', key: `placeholder-${index}` }); } @@ -734,7 +773,7 @@ const HomeScreen = () => { } return data; - }, [hasAddons, catalogs, visibleCatalogCount, settings.showThisWeekSection]); + }, [hasAddons, catalogs, catalogsLoading, pendingCatalogIndexes, visibleCatalogCount, settings.showThisWeekSection]); const handleLoadMoreCatalogs = useCallback(() => { setVisibleCatalogCount(prev => Math.min(prev + 3, catalogs.length));