From 6e883c730b953abe672fadd98f5174c60cffc862 Mon Sep 17 00:00:00 2001 From: nandhanay Date: Sun, 9 Aug 2026 23:53:02 +0530 Subject: [PATCH] fix: add GitHub raw fallback & reduced timeout for Pastebin manifest --- .../tv/data/repository/MediaRepository.kt | 3 +- .../tv/data/repository/StreamRepository.kt | 55 +++++++++++++------ .../tv/ui/screens/home/HomeViewModel.kt | 2 +- .../repository/StreamAddonFallbackTest.kt | 19 +++++++ config/streaming_addon.txt | 1 + 5 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 app/src/test/kotlin/com/arflix/tv/data/repository/StreamAddonFallbackTest.kt create mode 100644 config/streaming_addon.txt diff --git a/app/src/main/kotlin/com/arflix/tv/data/repository/MediaRepository.kt b/app/src/main/kotlin/com/arflix/tv/data/repository/MediaRepository.kt index 36d8bbc81..359a1f4d6 100644 --- a/app/src/main/kotlin/com/arflix/tv/data/repository/MediaRepository.kt +++ b/app/src/main/kotlin/com/arflix/tv/data/repository/MediaRepository.kt @@ -573,7 +573,8 @@ class MediaRepository @Inject constructor( fun getDefaultCatalogConfigs(): List = buildPreinstalledDefaults() companion object { - const val STREAMING_COLLECTION_ADDON_URL = "https://pastebin.com/raw/P4gfd98n" + const val STREAMING_COLLECTION_ADDON_URL = "https://raw.githubusercontent.com/ProdigyV21/ARVIO/main/config/streaming_addon.txt" + const val PASTEBIN_STREAMING_ADDON_URL = "https://pastebin.com/raw/P4gfd98n" private val UPLOADED_COVER_BASE = "https://" + "nu" + "vioapp.space/uploads/covers/" /** diff --git a/app/src/main/kotlin/com/arflix/tv/data/repository/StreamRepository.kt b/app/src/main/kotlin/com/arflix/tv/data/repository/StreamRepository.kt index 1ca3b8ef4..5937493ad 100644 --- a/app/src/main/kotlin/com/arflix/tv/data/repository/StreamRepository.kt +++ b/app/src/main/kotlin/com/arflix/tv/data/repository/StreamRepository.kt @@ -1268,24 +1268,47 @@ class StreamRepository @Inject constructor( private suspend fun resolveAddonInstallUrl(rawUrl: String): String { val normalized = normalizeAddonInputUrl(rawUrl) - if (!normalized.contains("pastebin.com/raw/", ignoreCase = true)) { + val isRawTextManifest = normalized.contains("pastebin.com/raw/", ignoreCase = true) || + normalized.contains("raw.githubusercontent.com/", ignoreCase = true) || + normalized.endsWith(".txt", ignoreCase = true) + if (!isRawTextManifest) { return normalized } - val request = Request.Builder().url(normalized).build() - val body = runCatching { - okHttpClient.newCall(request).execute().use { response -> - if (!response.isSuccessful) return normalized - response.body?.string().orEmpty() - } - }.getOrDefault("") - val link = body.lineSequence() - .map { it.trim() } - .firstOrNull { line -> - line.startsWith("stremio://", ignoreCase = true) || - line.startsWith("https://", ignoreCase = true) || - line.startsWith("http://", ignoreCase = true) - } - return if (link.isNullOrBlank()) normalized else normalizeAddonInputUrl(link) + + val fastClient = okHttpClient.newBuilder() + .connectTimeout(3500, java.util.concurrent.TimeUnit.MILLISECONDS) + .readTimeout(3500, java.util.concurrent.TimeUnit.MILLISECONDS) + .build() + + fun fetchManifestUrl(targetUrl: String): String? { + val request = Request.Builder().url(targetUrl).build() + val body = runCatching { + fastClient.newCall(request).execute().use { response -> + if (!response.isSuccessful) return null + response.body?.string().orEmpty() + } + }.getOrNull() ?: return null + + val link = body.lineSequence() + .map { it.trim() } + .firstOrNull { line -> + line.startsWith("stremio://", ignoreCase = true) || + line.startsWith("https://", ignoreCase = true) || + line.startsWith("http://", ignoreCase = true) + } + return link?.takeIf { it.isNotBlank() }?.let { normalizeAddonInputUrl(it) } + } + + val primaryResult = fetchManifestUrl(normalized) + if (primaryResult != null) return primaryResult + + val fallbackUrl = if (normalized.contains("pastebin.com", ignoreCase = true)) { + MediaRepository.STREAMING_COLLECTION_ADDON_URL + } else { + MediaRepository.PASTEBIN_STREAMING_ADDON_URL + } + val fallbackResult = fetchManifestUrl(fallbackUrl) + return fallbackResult ?: normalized } suspend fun getAddonCatalogPage( diff --git a/app/src/main/kotlin/com/arflix/tv/ui/screens/home/HomeViewModel.kt b/app/src/main/kotlin/com/arflix/tv/ui/screens/home/HomeViewModel.kt index 24a41338d..06e60c4f4 100644 --- a/app/src/main/kotlin/com/arflix/tv/ui/screens/home/HomeViewModel.kt +++ b/app/src/main/kotlin/com/arflix/tv/ui/screens/home/HomeViewModel.kt @@ -2071,7 +2071,7 @@ class HomeViewModel @Inject constructor( runCatching { streamRepository.removeCustomAddonsByUrl( CollectionTemplateManifest.autoInstalledAddonUrls() + - listOf(MediaRepository.STREAMING_COLLECTION_ADDON_URL) + listOf(MediaRepository.STREAMING_COLLECTION_ADDON_URL, MediaRepository.PASTEBIN_STREAMING_ADDON_URL) ) val addons = streamRepository.installedAddons.first() catalogRepository.syncAddonCatalogs(addons) diff --git a/app/src/test/kotlin/com/arflix/tv/data/repository/StreamAddonFallbackTest.kt b/app/src/test/kotlin/com/arflix/tv/data/repository/StreamAddonFallbackTest.kt new file mode 100644 index 000000000..6337fddea --- /dev/null +++ b/app/src/test/kotlin/com/arflix/tv/data/repository/StreamAddonFallbackTest.kt @@ -0,0 +1,19 @@ +package com.arflix.tv.data.repository + +import org.junit.Assert.assertEquals +import org.junit.Test + +class StreamAddonFallbackTest { + + @Test + fun constants_verifyPrimaryAndFallbackUrlsAreConfigured() { + assertEquals( + "https://raw.githubusercontent.com/ProdigyV21/ARVIO/main/config/streaming_addon.txt", + MediaRepository.STREAMING_COLLECTION_ADDON_URL + ) + assertEquals( + "https://pastebin.com/raw/P4gfd98n", + MediaRepository.PASTEBIN_STREAMING_ADDON_URL + ) + } +} diff --git a/config/streaming_addon.txt b/config/streaming_addon.txt new file mode 100644 index 000000000..0e9fdbf64 --- /dev/null +++ b/config/streaming_addon.txt @@ -0,0 +1 @@ +https://7a82163c306e-stremio-netflix-catalog-addon.baby-beamup.club/bmZ4LGRucCxhbXAsYXRwLGhibSxwbXAscGNwLGhsdTo6OjE3NzU5MzEzMzkxNzU6MDowOg%3D%3D/manifest.json