diff --git a/StremioProvider/build.gradle.kts b/StremioProvider/build.gradle.kts
new file mode 100644
index 0000000..a810295
--- /dev/null
+++ b/StremioProvider/build.gradle.kts
@@ -0,0 +1,24 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ language = "en"
+ // All of these properties are optional, you can safely remove them
+ description = "Allows you to use stremio addons. Requires setup. (Torrents and old api does not work)"
+
+ // description = "Lorem Ipsum"
+ authors = listOf("Cloudburst")
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ * */
+ status = 1 // will be 3 if unspecified
+ tvTypes = listOf("Others")
+
+ iconUrl = "https://www.google.com/s2/favicons?domain=www.stremio.com&sz=%size%"
+}
\ No newline at end of file
diff --git a/StremioProvider/src/main/AndroidManifest.xml b/StremioProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/StremioProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/StremioProvider/src/main/kotlin/com/lagradost/StremioProvider.kt b/StremioProvider/src/main/kotlin/com/lagradost/StremioProvider.kt
new file mode 100644
index 0000000..a72e1ef
--- /dev/null
+++ b/StremioProvider/src/main/kotlin/com/lagradost/StremioProvider.kt
@@ -0,0 +1,178 @@
+package com.lagradost
+
+import android.util.Log
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.utils.AppUtils.toJson
+
+import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.Qualities
+import com.lagradost.cloudstream3.utils.loadExtractor
+import org.json.JSONObject
+
+class StremioProvider : MainAPI() {
+ override var mainUrl = "https://stremio.github.io/stremio-static-addon-example"
+ override var name = "Stremio example"
+ 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 load(url: String): LoadResponse? {
+ val res = tryParseJson(url) ?: throw RuntimeException(url)
+ return res.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(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 toHomePageList(provider: StremioProvider): HomePageList? {
+ val entries = mutableListOf()
+ types.forEach { type ->
+ val res = tryParseJson(app.get("${provider.mainUrl}/catalog/$type/$id.json").text) ?: return@forEach
+ res.metas.forEach { entry ->
+ entries.add(entry.toSearchResponse(provider))
+ }
+ }
+ return HomePageList(
+ name ?: id,
+ entries
+ )
+ }
+ }
+
+ private data class CatalogResponse(val metas: List)
+ private data class CatalogEntry(
+ val name: String,
+ val id: String,
+ val poster: String?,
+ val description: String?,
+ val type: String?
+ ) {
+ fun toSearchResponse(provider: StremioProvider): SearchResponse {
+ return provider.newMovieSearchResponse(
+ name,
+ this.toJson(),
+ type?.let { getType(it) } ?: TvType.Others
+ ) {
+ posterUrl = poster
+ }
+ }
+ suspend fun toLoadResponse(provider: StremioProvider): LoadResponse {
+ return provider.newMovieLoadResponse(
+ name,
+ "${provider.mainUrl}/meta/$type/$id.json",
+ getType(type),
+ "${provider.mainUrl}/stream/$type/$id.json"
+ ) {
+ posterUrl = poster
+ plot = description
+ }
+ }
+ }
+
+ private data class StreamsResponse(val streams: List)
+ private data class Stream(
+ val name: String?,
+ val title: String?,
+ val url: String?,
+ val ytId: String?,
+ val externalUrl: String?,
+ val behaviorHints: JSONObject?
+ ) {
+ suspend fun runCallback(subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {
+ if (url != null) {
+ var referer: String? = null
+ try {
+ val headers = ((behaviorHints?.get("proxyHeaders") as? JSONObject)
+ ?.get("request") as? JSONObject)
+ referer = headers?.get("referer") as? String ?: headers?.get("origin") as? String
+ } catch (ex: Throwable) {
+ Log.e("Stremio", Log.getStackTraceString(ex))
+ }
+
+ if (url.endsWith(".m3u8")) {
+ callback.invoke(
+ ExtractorLink(
+ name ?: "",
+ title ?: name ?: "",
+ url,
+ referer ?: "",
+ Qualities.Unknown.value,
+ isM3u8 = true
+ ))
+ } else {
+ callback.invoke(
+ ExtractorLink(
+ name ?: "",
+ title ?: name ?: "",
+ url,
+ referer ?: "",
+ Qualities.Unknown.value,
+ isM3u8 = false
+ ))
+ }
+ }
+ if (ytId != null) {
+ loadExtractor("https://www.youtube.com/watch?v=$ytId", subtitleCallback, callback)
+ }
+ if (externalUrl != null) {
+ loadExtractor(externalUrl, subtitleCallback, callback)
+ }
+ }
+ }
+
+ companion object {
+ private val typeAliases = hashMapOf(
+ "tv" to TvType.TvSeries,
+ "series" to TvType.TvSeries,
+ "channel" to TvType.Live,
+ "adult" to TvType.NSFW
+ )
+
+ fun getType(t_str: String?): TvType {
+ if (t_str == null) return TvType.Others
+ typeAliases[t_str.lowercase()]?.let {
+ return it
+ }
+ for (t_enum in TvType.values()) {
+ if (t_enum.toString().lowercase() == t_str.lowercase())
+ return t_enum
+ }
+ return TvType.Others
+ }
+ }
+}
diff --git a/StremioProvider/src/main/kotlin/com/lagradost/StremioProviderPlugin.kt b/StremioProvider/src/main/kotlin/com/lagradost/StremioProviderPlugin.kt
new file mode 100644
index 0000000..60732f5
--- /dev/null
+++ b/StremioProvider/src/main/kotlin/com/lagradost/StremioProviderPlugin.kt
@@ -0,0 +1,14 @@
+
+package com.lagradost
+
+import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
+import com.lagradost.cloudstream3.plugins.Plugin
+import android.content.Context
+
+@CloudstreamPlugin
+class StremioProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(StremioProvider())
+ }
+}
\ No newline at end of file