diff --git a/StremioX/build.gradle.kts b/StremioX/build.gradle.kts index be955f6a..0cd84a14 100644 --- a/StremioX/build.gradle.kts +++ b/StremioX/build.gradle.kts @@ -6,7 +6,7 @@ cloudstream { language = "en" // All of these properties are optional, you can safely remove them - description = "Allow you to use Stremio addons as sources such as torrentio. (!) Requires setup" + description = "- Stremiox allows you to use stream addons \n- Stremio allows you to use catalog addons \n Requires Setup" authors = listOf("Hexated") /** diff --git a/StremioX/src/main/kotlin/com/hexated/Stremio.kt b/StremioX/src/main/kotlin/com/hexated/Stremio.kt new file mode 100644 index 00000000..b5c08f57 --- /dev/null +++ b/StremioX/src/main/kotlin/com/hexated/Stremio.kt @@ -0,0 +1,259 @@ +package com.hexated + +import android.util.Log +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.AppUtils.toJson +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import org.json.JSONObject +import java.net.URI + +private const val TRACKER_LIST_URL = + "https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt" + +class Stremio : MainAPI() { + override var mainUrl = "https://stremio.github.io/stremio-static-addon-example" + override var name = "Stremio" + override val supportedTypes = setOf(TvType.Others) + override val hasMainPage = true + + override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse? { + val res = tryParseJson(app.get("${mainUrl}/manifest.json").text) ?: return null + val lists = mutableListOf() + res.catalogs.forEach { catalog -> + catalog.toHomePageList(this)?.let { + lists.add(it) + } + } + return HomePageResponse( + lists, + false + ) + } + + override suspend fun search(query: String): List? { + val res = tryParseJson(app.get("${mainUrl}/manifest.json").text) ?: return null + val list = mutableListOf() + res.catalogs.forEach { catalog -> + list.addAll(catalog.search(query, this)) + } + return list + } + + override suspend fun load(url: String): LoadResponse? { + val res = parseJson(url) + val json = app.get("${mainUrl}/meta/${res.type}/${res.id}.json") + .parsedSafe()?.meta ?: throw RuntimeException(url) + return json.toLoadResponse(this) + } + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + val res = tryParseJson(app.get(data).text) ?: return false + res.streams.forEach { stream -> + stream.runCallback(this, subtitleCallback, callback) + } + + return true + } + + private data class Manifest(val catalogs: List) + private data class Catalog( + var name: String?, + val id: String, + val type: String?, + val types: MutableList = mutableListOf() + ) { + init { + if (type != null) types.add(type) + } + + suspend fun search(query: String, provider: Stremio): List { + val entries = mutableListOf() + types.forEach { type -> + val json = + app.get("${provider.mainUrl}/catalog/${type}/${id}/search=${query}.json").text + val res = + tryParseJson(json) + ?: return@forEach + res.metas?.forEach { entry -> + entries.add(entry.toSearchResponse(provider)) + } + } + return entries + } + + suspend fun toHomePageList(provider: Stremio): HomePageList? { + val entries = mutableListOf() + types.forEach { type -> + val json = app.get("${provider.mainUrl}/catalog/${type}/${id}.json").text + val res = + tryParseJson(json) + ?: return@forEach + res.metas?.forEach { entry -> + entries.add(entry.toSearchResponse(provider)) + } + } + return HomePageList( + name ?: id, + entries + ) + } + } + + private data class CatalogResponse(val metas: List?, val meta: CatalogEntry?) + private data class CatalogEntry( + val name: String, + val id: String, + val poster: String?, + val description: String?, + val type: String?, + val videos: List