diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 4e710706..65eb0491 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -244,7 +244,34 @@ const HomeScreen = () => { for (const addon of addons) { if (addon.catalogs) { for (const catalog of addon.catalogs) { - // Check if this catalog is enabled (default to true if no setting exists) + // ── Manifest-level hard gates (cannot be overridden by user settings) ── + + // 1. Never show search catalogs (search.movie, search.series, etc.) + if ( + (catalog.id && catalog.id.startsWith('search.')) || + (catalog.type && catalog.type.startsWith('search')) + ) { + continue; + } + + // 2. Never show catalogs that have any required extra + // (e.g. required genre, calendarVideosIds — these need params to load) + const requiredExtras = (catalog.extra || []) + .filter((e: any) => e.isRequired) + .map((e: any) => e.name); + if (requiredExtras.length > 0) { + continue; + } + + // 3. Respect showInHome flag — if the addon uses it on any catalog, + // only catalogs with showInHome:true are eligible for home. + const addonUsesShowInHome = addon.catalogs.some((c: any) => c.showInHome === true); + if (addonUsesShowInHome && !(catalog as any).showInHome) { + continue; + } + + // ── User toggle (mmkv) — applied on top of manifest gates ── + // Default is true unless the manifest gates above have already filtered it out. const settingKey = `${addon.id}:${catalog.type}:${catalog.id}`; const isEnabled = catalogSettings[settingKey] ?? true; diff --git a/src/services/catalogService.ts b/src/services/catalogService.ts index 71eb680d..50dfd938 100644 --- a/src/services/catalogService.ts +++ b/src/services/catalogService.ts @@ -363,12 +363,53 @@ class CatalogService { } private canBrowseCatalog(catalog: StreamingCatalog): boolean { - // Exclude non-standard types like anime.series, anime.movie from discover browsing - if (catalog.type && catalog.type.includes('.')) return false; + // Exclude search-only catalogs from discover browsing + if ( + (catalog.id && catalog.id.startsWith('search.')) || + (catalog.type && catalog.type.startsWith('search')) + ) { + return false; + } const requiredExtras = this.getRequiredCatalogExtras(catalog); return requiredExtras.every(extraName => extraName === 'genre'); } + /** + * Whether a catalog should appear on the home screen, based purely on the + * addon manifest — no user settings / mmkv involved. + * + * Rules (in order): + * 1. Search catalogs (id/type starts with "search") → never on home + * 2. Catalogs with any required extra (including required genre) → never on home + * 3. Addon uses showInHome flag on at least one catalog: + * → only catalogs with showInHome:true appear on home + * 4. No showInHome flag on any catalog → all browseable catalogs appear on home + */ + private isVisibleOnHome(catalog: StreamingCatalog, addonCatalogs: StreamingCatalog[]): boolean { + // Rule 1: never show search catalogs + if ( + (catalog.id && catalog.id.startsWith('search.')) || + (catalog.type && catalog.type.startsWith('search')) + ) { + return false; + } + + // Rule 2: never show catalogs with any required extra (e.g. required genre, calendarVideosIds) + const requiredExtras = this.getRequiredCatalogExtras(catalog); + if (requiredExtras.length > 0) { + return false; + } + + // Rule 3: respect showInHome if the addon uses it on any catalog + const addonUsesShowInHome = addonCatalogs.some((c: any) => c.showInHome === true); + if (addonUsesShowInHome) { + return (catalog as any).showInHome === true; + } + + // Rule 4: no showInHome flag used — show all browseable catalogs + return true; + } + private canSearchCatalog(catalog: StreamingCatalog): boolean { if (!this.catalogSupportsExtra(catalog, 'search')) { return false; @@ -381,24 +422,13 @@ class CatalogService { async resolveHomeCatalogsToFetch(limitIds?: string[]): Promise<{ addon: StreamingAddon; catalog: any }[]> { const addons = await this.getAllAddons(); - // Load enabled/disabled settings - const catalogSettingsJson = await mmkvStorage.getItem(CATALOG_SETTINGS_KEY); - const catalogSettings = catalogSettingsJson ? JSON.parse(catalogSettingsJson) : {}; - - // Collect all potential catalogs first + // Collect catalogs visible on home using manifest-only rules (no mmkv/user settings) const potentialCatalogs: { addon: StreamingAddon; catalog: any }[] = []; for (const addon of addons) { if (addon.catalogs) { for (const catalog of addon.catalogs) { - if (!this.canBrowseCatalog(catalog)) { - continue; - } - - const settingKey = `${addon.id}:${catalog.type}:${catalog.id}`; - const isEnabled = catalogSettings[settingKey] ?? true; - - if (isEnabled) { + if (this.isVisibleOnHome(catalog, addon.catalogs)) { potentialCatalogs.push({ addon, catalog }); } } @@ -512,7 +542,9 @@ class CatalogService { const catalogPromises: Promise[] = []; for (const addon of typeAddons) { - const typeCatalogs = addon.catalogs.filter(catalog => catalog.type === type); + const typeCatalogs = addon.catalogs.filter((catalog: StreamingCatalog) => + catalog.type === type && this.isVisibleOnHome(catalog, addon.catalogs) + ); for (const catalog of typeCatalogs) { const catalogPromise = (async () => {