From dd6b0ffb46a9e0412797c813d87d4152ccd1dfb9 Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Fri, 13 Mar 2026 10:29:29 +0530 Subject: [PATCH] update nuvio-soruce.json --- android/app/build.gradle | 27 ---- android/build.gradle | 1 - ios/Nuvio.xcodeproj/project.pbxproj | 30 ++-- ios/Nuvio/Info.plist | 226 ++++++++++++++-------------- nuvio-source.json | 8 + src/services/catalogService.ts | 110 ++++++++++---- 6 files changed, 212 insertions(+), 190 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index c490dc33..48382527 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,7 +1,6 @@ apply plugin: "com.android.application" apply plugin: "org.jetbrains.kotlin.android" apply plugin: "com.facebook.react" -apply plugin: "io.sentry.android.gradle" def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath() @@ -82,8 +81,6 @@ def enableMinifyInReleaseBuilds = (findProperty('android.enableMinifyInReleaseBu */ def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+' -apply from: new File(["node", "--print", "require('path').dirname(require.resolve('@sentry/react-native/package.json'))"].execute().text.trim(), "sentry.gradle") - android { ndkVersion rootProject.ext.ndkVersion @@ -185,30 +182,6 @@ android { } } -sentry { - // Enables or disables the automatic configuration of Native Symbols - // for Sentry. This executes sentry-cli automatically so - // you don't need to do it manually. - // Default is disabled. - uploadNativeSymbols = true - - // Enables or disables the automatic upload of the app's native source code to Sentry. - // This executes sentry-cli with the --include-sources param automatically so - // you don't need to do it manually. - // This option has an effect only when [uploadNativeSymbols] is enabled. - // Default is disabled. - includeNativeSources = true - - // `@sentry/react-native` ships with compatible `sentry-android` - // This option would install the latest version that ships with the SDK or SAGP (Sentry Android Gradle Plugin) - // which might be incompatible with the React Native SDK - // Enable auto-installation of Sentry components (sentry-android SDK and okhttp, timber and fragment integrations). - // Default is enabled. - autoInstallation { - enabled = false - } -} - configurations.all { exclude group: 'com.caverock', module: 'androidsvg' } diff --git a/android/build.gradle b/android/build.gradle index 3cc4c5b8..5a3dbd7d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -17,7 +17,6 @@ buildscript { classpath('com.android.tools.build:gradle') classpath('com.facebook.react:react-native-gradle-plugin') classpath('org.jetbrains.kotlin:kotlin-gradle-plugin') - classpath("io.sentry:sentry-android-gradle-plugin:5.12.2") } } diff --git a/ios/Nuvio.xcodeproj/project.pbxproj b/ios/Nuvio.xcodeproj/project.pbxproj index 4bb3fc7f..e8df1a9e 100644 --- a/ios/Nuvio.xcodeproj/project.pbxproj +++ b/ios/Nuvio.xcodeproj/project.pbxproj @@ -56,34 +56,34 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0E5AC167979645D9ADB47923 /* LiveActivity.entitlements */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = LiveActivity.entitlements; path = LiveActivity.entitlements; sourceTree = ""; }; + 0E5AC167979645D9ADB47923 /* LiveActivity.entitlements */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; path = LiveActivity.entitlements; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* Nuvio.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Nuvio.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Nuvio/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Nuvio/Info.plist; sourceTree = ""; }; - 1B775F1944CB4E2EB043DB23 /* LiveActivityWidgetBundle.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = LiveActivityWidgetBundle.swift; path = LiveActivityWidgetBundle.swift; sourceTree = ""; }; - 3182DD61A7C04BD383DBB4B0 /* LiveActivityView.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = LiveActivityView.swift; path = LiveActivityView.swift; sourceTree = ""; }; - 348452A2DFC344C2BC70A974 /* Assets.xcassets */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Assets.xcassets; sourceTree = ""; }; - 37E2BF6107484CD098F81560 /* LiveActivity.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = undefined; name = LiveActivity.appex; path = LiveActivity.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - 3A20BAB83F6E40D880665E14 /* Date+toTimerInterval.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "Date+toTimerInterval.swift"; path = "Date+toTimerInterval.swift"; sourceTree = ""; }; + 1B775F1944CB4E2EB043DB23 /* LiveActivityWidgetBundle.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; path = LiveActivityWidgetBundle.swift; sourceTree = ""; }; + 3182DD61A7C04BD383DBB4B0 /* LiveActivityView.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; path = LiveActivityView.swift; sourceTree = ""; }; + 348452A2DFC344C2BC70A974 /* Assets.xcassets */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 37E2BF6107484CD098F81560 /* LiveActivity.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; fileEncoding = 9; includeInIndex = 0; path = LiveActivity.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 3A20BAB83F6E40D880665E14 /* Date+toTimerInterval.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; path = "Date+toTimerInterval.swift"; sourceTree = ""; }; 44393AD0ABDBAED5B40D2E49 /* Pods-Nuvio.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nuvio.release.xcconfig"; path = "Target Support Files/Pods-Nuvio/Pods-Nuvio.release.xcconfig"; sourceTree = ""; }; - 495FF0F91AFAF8A860B9D485 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = Nuvio/PrivacyInfo.xcprivacy; sourceTree = ""; }; - 65BDE00720574797863FA748 /* View+applyIfPresent.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "View+applyIfPresent.swift"; path = "View+applyIfPresent.swift"; sourceTree = ""; }; + 495FF0F91AFAF8A860B9D485 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = Nuvio/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 65BDE00720574797863FA748 /* View+applyIfPresent.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; path = "View+applyIfPresent.swift"; sourceTree = ""; }; 7206543A5AAE2788326BFBC7 /* libPods-Nuvio.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Nuvio.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 7EC866223BB0FA7280D468BF /* Pods-Nuvio.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nuvio.debug.xcconfig"; path = "Target Support Files/Pods-Nuvio/Pods-Nuvio.debug.xcconfig"; sourceTree = ""; }; - 9C77B925A48A4711B3B59C6A /* LiveActivityWidget.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = LiveActivityWidget.swift; path = LiveActivityWidget.swift; sourceTree = ""; }; + 9C77B925A48A4711B3B59C6A /* LiveActivityWidget.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; path = LiveActivityWidget.swift; sourceTree = ""; }; 9FBA88F02E86ECD700892850 /* ../KSPlayer/RNBridge/KSPlayerManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ../KSPlayer/RNBridge/KSPlayerManager.m; sourceTree = ""; }; 9FBA88F12E86ECD700892850 /* ../KSPlayer/RNBridge/KSPlayerModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ../KSPlayer/RNBridge/KSPlayerModule.swift; sourceTree = ""; }; 9FBA88F22E86ECD700892850 /* ../KSPlayer/RNBridge/KSPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ../KSPlayer/RNBridge/KSPlayerView.swift; sourceTree = ""; }; 9FBA88F32E86ECD700892850 /* ../KSPlayer/RNBridge/KSPlayerViewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ../KSPlayer/RNBridge/KSPlayerViewManager.swift; sourceTree = ""; }; - A0AC8A8984F4495492E13EFD /* View+applyWidgetURL.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "View+applyWidgetURL.swift"; path = "View+applyWidgetURL.swift"; sourceTree = ""; }; + A0AC8A8984F4495492E13EFD /* View+applyWidgetURL.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; path = "View+applyWidgetURL.swift"; sourceTree = ""; }; AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = Nuvio/SplashScreen.storyboard; sourceTree = ""; }; - B36264437D84461BBC2BB706 /* Color+hex.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "Color+hex.swift"; path = "Color+hex.swift"; sourceTree = ""; }; + B36264437D84461BBC2BB706 /* Color+hex.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; path = "Color+hex.swift"; sourceTree = ""; }; B9B2F28305B8518622853186 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-Nuvio/ExpoModulesProvider.swift"; sourceTree = ""; }; BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = ""; }; - D296491CC4F4406182E2A2BC /* ViewHelpers.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = ViewHelpers.swift; path = ViewHelpers.swift; sourceTree = ""; }; - E93B94AE2F7240878D655B2F /* Info.plist */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = text.plist.xml; name = Info.plist; path = Info.plist; sourceTree = ""; }; + D296491CC4F4406182E2A2BC /* ViewHelpers.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; path = ViewHelpers.swift; sourceTree = ""; }; + E93B94AE2F7240878D655B2F /* Info.plist */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; - F03926C841844CC38C468345 /* Image+dynamic.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "Image+dynamic.swift"; path = "Image+dynamic.swift"; sourceTree = ""; }; + F03926C841844CC38C468345 /* Image+dynamic.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; path = "Image+dynamic.swift"; sourceTree = ""; }; F11748412D0307B40044C1D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Nuvio/AppDelegate.swift; sourceTree = ""; }; F11748442D0722820044C1D9 /* Nuvio-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Nuvio-Bridging-Header.h"; path = "Nuvio/Nuvio-Bridging-Header.h"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -150,7 +150,6 @@ 348452A2DFC344C2BC70A974 /* Assets.xcassets */, 0E5AC167979645D9ADB47923 /* LiveActivity.entitlements */, ); - name = LiveActivity; path = LiveActivity; sourceTree = ""; }; @@ -192,7 +191,6 @@ 7EC866223BB0FA7280D468BF /* Pods-Nuvio.debug.xcconfig */, 44393AD0ABDBAED5B40D2E49 /* Pods-Nuvio.release.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; diff --git a/ios/Nuvio/Info.plist b/ios/Nuvio/Info.plist index 24d1caaa..52462dd9 100644 --- a/ios/Nuvio/Info.plist +++ b/ios/Nuvio/Info.plist @@ -1,116 +1,116 @@ - - CADisableMinimumFrameDurationOnPhone - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Nuvio - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.4.2 - CFBundleSignature - ???? - CFBundleURLTypes - - - CFBundleURLSchemes - - nuvio - com.nuvio.hub - - - - CFBundleURLSchemes - - exp+nuvio - - - - CFBundleVersion - 38 - LSApplicationQueriesSchemes - - vlc - vlc-x-callback - infuse - outplayer - open-vidhub - livecontainer - - LSMinimumSystemVersion - 12.0 - LSRequiresIPhoneOS - - LSSupportsOpeningDocumentsInPlace - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - - NSBonjourServices - - _http._tcp - _googlecast._tcp - _CC1AD845._googlecast._tcp - - NSLocalNetworkUsageDescription - Nuvio uses the local network to discover Cast-enabled devices on your WiFi network and to connect to local media servers. - NSMicrophoneUsageDescription - This app does not require microphone access. - NSSupportsLiveActivities - - NSSupportsLiveActivitiesFrequentUpdates - - RCTNewArchEnabled - - RCTRootViewBackgroundColor - 4278322180 - UIBackgroundModes - - audio - - UIFileSharingEnabled - - UILaunchStoryboardName - SplashScreen - UIRequiredDeviceCapabilities - - arm64 - - UIRequiresFullScreen - - UIStatusBarStyle - UIStatusBarStyleDefault - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIUserInterfaceStyle - Dark - UIViewControllerBasedStatusBarAppearance - - - \ No newline at end of file + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Nuvio + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.4.2 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleURLSchemes + + nuvio + com.nuvio.hub + + + + CFBundleURLSchemes + + exp+nuvio + + + + CFBundleVersion + 38 + LSApplicationQueriesSchemes + + vlc + vlc-x-callback + infuse + outplayer + open-vidhub + livecontainer + + LSMinimumSystemVersion + 12.0 + LSRequiresIPhoneOS + + LSSupportsOpeningDocumentsInPlace + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSBonjourServices + + _http._tcp + _googlecast._tcp + _CC1AD845._googlecast._tcp + + NSLocalNetworkUsageDescription + Nuvio uses the local network to discover Cast-enabled devices on your WiFi network and to connect to local media servers. + NSMicrophoneUsageDescription + This app does not require microphone access. + NSSupportsLiveActivities + + NSSupportsLiveActivitiesFrequentUpdates + + RCTNewArchEnabled + + RCTRootViewBackgroundColor + 4278322180 + UIBackgroundModes + + audio + + UIFileSharingEnabled + + UILaunchStoryboardName + SplashScreen + UIRequiredDeviceCapabilities + + arm64 + + UIRequiresFullScreen + + UIStatusBarStyle + UIStatusBarStyleDefault + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIUserInterfaceStyle + Dark + UIViewControllerBasedStatusBarAppearance + + + diff --git a/nuvio-source.json b/nuvio-source.json index 0ac08b83..08f8a02c 100644 --- a/nuvio-source.json +++ b/nuvio-source.json @@ -30,6 +30,14 @@ "https://github.com/tapframe/NuvioStreaming/blob/main/screenshots/search-portrait.png?raw=true" ], "versions": [ + { + "version": "1.4.2", + "buildVersion": "38", + "date": "2026-03-13", + "localizedDescription": "## Update Notes\n\n- Added **MyAnimeList (MAL) integration** with authentication, library sync, rewatch support, and profile dashboard\n- Improved **MAL mapping and sync performance**\n- Updated **authentication logic and UI**\n- Updated **trailer extraction logic**\n- Dependency updates and internal improvements\n\n### Contributors\n- **@paregi12**\n- **@saimuelbr**\n- **@vhtuan288**", + "downloadURL": "https://github.com/tapframe/NuvioStreaming/releases/download/1.4.2/Stable_1-4-2.ipa", + "size": 25700000 + }, { "version": "1.4.1", "buildVersion": "37", diff --git a/src/services/catalogService.ts b/src/services/catalogService.ts index c5924650..cce738c8 100644 --- a/src/services/catalogService.ts +++ b/src/services/catalogService.ts @@ -16,19 +16,28 @@ export enum DataSource { TMDB = 'tmdb', } +interface StreamingCatalogExtra { + name: string; + isRequired?: boolean; + options?: string[]; + optionsLimit?: number; +} + +interface StreamingCatalog { + type: string; + id: string; + name: string; + extraSupported?: string[]; + extra?: StreamingCatalogExtra[]; +} + export interface StreamingAddon { id: string; name: string; version: string; description: string; types: string[]; - catalogs: { - type: string; - id: string; - name: string; - extraSupported?: string[]; - extra?: Array<{ name: string; options?: string[] }>; - }[]; + catalogs: StreamingCatalog[]; resources: { name: string; types: string[]; @@ -324,7 +333,16 @@ class CatalogService { version: manifest.version, description: manifest.description, types: manifest.types || [], - catalogs: manifest.catalogs || [], + catalogs: (manifest.catalogs || []).map(catalog => ({ + ...catalog, + extraSupported: catalog.extraSupported || [], + extra: (catalog.extra || []).map(extra => ({ + name: extra.name, + isRequired: extra.isRequired, + options: extra.options, + optionsLimit: extra.optionsLimit, + })), + })), resources: manifest.resources || [], url: (manifest.url || manifest.originalUrl) as any, originalUrl: (manifest.originalUrl || manifest.url) as any, @@ -333,6 +351,31 @@ class CatalogService { }; } + private catalogSupportsExtra(catalog: StreamingCatalog, extraName: string): boolean { + return (catalog.extraSupported || []).includes(extraName) || + (catalog.extra || []).some(extra => extra.name === extraName); + } + + private getRequiredCatalogExtras(catalog: StreamingCatalog): string[] { + return (catalog.extra || []) + .filter(extra => extra.isRequired) + .map(extra => extra.name); + } + + private canBrowseCatalog(catalog: StreamingCatalog): boolean { + const requiredExtras = this.getRequiredCatalogExtras(catalog); + return requiredExtras.every(extraName => extraName === 'genre'); + } + + private canSearchCatalog(catalog: StreamingCatalog): boolean { + if (!this.catalogSupportsExtra(catalog, 'search')) { + return false; + } + + const requiredExtras = this.getRequiredCatalogExtras(catalog); + return requiredExtras.every(extraName => extraName === 'search'); + } + async resolveHomeCatalogsToFetch(limitIds?: string[]): Promise<{ addon: StreamingAddon; catalog: any }[]> { const addons = await this.getAllAddons(); @@ -346,6 +389,10 @@ class CatalogService { 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; @@ -1080,6 +1127,10 @@ class CatalogService { if (!addon.catalogs) continue; for (const catalog of addon.catalogs) { + if (!this.canBrowseCatalog(catalog)) { + continue; + } + // Track content types if (catalog.type) { allTypes.add(catalog.type); @@ -1145,7 +1196,9 @@ class CatalogService { if (!addon.catalogs) continue; // Find catalogs matching the type - const matchingCatalogs = addon.catalogs.filter(catalog => catalog.type === type); + const matchingCatalogs = addon.catalogs.filter(catalog => + catalog.type === type && this.canBrowseCatalog(catalog) + ); for (const catalog of matchingCatalogs) { // Check if this catalog supports the genre filter @@ -1234,6 +1287,12 @@ class CatalogService { return []; } + const catalog = (manifest.catalogs || []).find(item => item.type === type && item.id === catalogId); + if (!catalog || !this.canBrowseCatalog(catalog)) { + logger.warn(`Catalog ${catalogId} in addon ${addonId} is not browseable`); + return []; + } + const filters = genre ? [{ title: 'genre', value: genre }] : []; const metas = await stremioService.getCatalog(manifest, type, catalogId, page, filters); @@ -1263,6 +1322,10 @@ class CatalogService { for (const addon of addons) { if (addon.catalogs && addon.catalogs.length > 0) { for (const catalog of addon.catalogs) { + if (!this.canSearchCatalog(catalog)) { + continue; + } + const addonManifest = await stremioService.getInstalledAddonsAsync(); const manifest = addonManifest.find(a => a.id === addon.id); if (!manifest) continue; @@ -1327,15 +1390,7 @@ class CatalogService { const searchableAddons = addons.filter(addon => { if (!addon.catalogs) return false; - // Check if any catalog supports search - return addon.catalogs.some(catalog => { - const extraSupported = catalog.extraSupported || []; - const extra = catalog.extra || []; - - // Check if 'search' is in extraSupported or extra - return extraSupported.includes('search') || - extra.some((e: any) => e.name === 'search'); - }); + return addon.catalogs.some(catalog => this.canSearchCatalog(catalog)); }); logger.log(`Found ${searchableAddons.length} searchable addons:`, searchableAddons.map(a => a.name).join(', ')); @@ -1349,12 +1404,7 @@ class CatalogService { continue; } - const searchableCatalogs = (addon.catalogs || []).filter(catalog => { - const extraSupported = catalog.extraSupported || []; - const extra = catalog.extra || []; - return extraSupported.includes('search') || - extra.some((e: any) => e.name === 'search'); - }); + const searchableCatalogs = (addon.catalogs || []).filter(catalog => this.canSearchCatalog(catalog)); // Search all catalogs for this addon in parallel const catalogPromises = searchableCatalogs.map(catalog => @@ -1436,10 +1486,7 @@ class CatalogService { // Determine searchable addons const searchableAddons = addons.filter(addon => - (addon.catalogs || []).some(c => - (c.extraSupported && c.extraSupported.includes('search')) || - (c.extra && c.extra.some(e => e.name === 'search')) - ) + (addon.catalogs || []).some(catalog => this.canSearchCatalog(catalog)) ); logger.log(`Found ${searchableAddons.length} searchable addons:`, searchableAddons.map(a => `${a.name} (${a.id})`).join(', ')); @@ -1463,10 +1510,7 @@ class CatalogService { return; } - const searchableCatalogs = (addon.catalogs || []).filter(c => - (c.extraSupported && c.extraSupported.includes('search')) || - (c.extra && c.extra.some(e => e.name === 'search')) - ); + const searchableCatalogs = (addon.catalogs || []).filter(catalog => this.canSearchCatalog(catalog)); logger.log(`Searching ${addon.name} (${addon.id}) with ${searchableCatalogs.length} searchable catalogs`); @@ -1675,4 +1719,4 @@ class CatalogService { } export const catalogService = CatalogService.getInstance(); -export default catalogService; \ No newline at end of file +export default catalogService;