package com.hexated import com.fasterxml.jackson.annotation.JsonProperty import com.hexated.SubsExtractors.invokeOpenSubs import com.hexated.SubsExtractors.invokeWatchsomuch import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addActors import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbId import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson class StremioC : MainAPI() { override var mainUrl = "https://stremio.github.io/stremio-static-addon-example" override var name = "StremioC" override val supportedTypes = setOf(TvType.Others) override val hasMainPage = true companion object { private const val cinemataUrl = "https://v3-cinemeta.strem.io" private const val TRACKER_LIST_URL = "https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt" } override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { mainUrl = mainUrl.fixSourceUrl() val res = app.get("${mainUrl}/manifest.json").parsedSafe() val lists = mutableListOf() res?.catalogs?.apmap { catalog -> catalog.toHomePageList(this).let { if (it.list.isNotEmpty()) lists.add(it) } } return HomePageResponse( lists, false ) } override suspend fun search(query: String): List { mainUrl = mainUrl.fixSourceUrl() val res = app.get("${mainUrl}/manifest.json").parsedSafe() val list = mutableListOf() res?.catalogs?.apmap { catalog -> list.addAll(catalog.search(query, this)) } return list.distinct() } override suspend fun load(url: String): LoadResponse { val res = parseJson(url) mainUrl = if ((res.type == "movie" || res.type == "series") && isImdborTmdb(res.id)) cinemataUrl else mainUrl val json = app.get("${mainUrl}/meta/${res.type}/${res.id}.json") .parsedSafe()?.meta ?: throw RuntimeException(url) return json.toLoadResponse(this, res.id) } override suspend fun loadLinks( data: String, isCasting: Boolean, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ): Boolean { val loadData = parseJson(data) val request = app.get( "${mainUrl}/stream/${loadData.type}/${loadData.id}.json", timeout = 120L ) if (request.isSuccessful) { val res = request.parsedSafe() res?.streams?.forEach { stream -> stream.runCallback(subtitleCallback, callback) } } else { argamap( { invokeStremioX(loadData.type, loadData.id, subtitleCallback, callback) }, { invokeWatchsomuch( loadData.imdbId, loadData.season, loadData.episode, subtitleCallback ) }, { invokeOpenSubs( loadData.imdbId, loadData.season, loadData.episode, subtitleCallback ) }, ) } return true } private suspend fun invokeStremioX( type: String?, id: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val sites = AcraApplication.getKey>(USER_PROVIDER_API)?.toMutableList() ?: mutableListOf() sites.filter { it.parentJavaClass == "StremioX" }.apmap { site -> val res = app.get( "${site.url.fixSourceUrl()}/stream/${type}/${id}.json", timeout = 120L ).parsedSafe() res?.streams?.forEach { stream -> stream.runCallback(subtitleCallback, callback) } } } data class LoadData( val type: String? = null, val id: String? = null, val season: Int? = null, val episode: Int? = null, val imdbId: String? = null, ) data class CustomSite( @JsonProperty("parentJavaClass") val parentJavaClass: String, @JsonProperty("name") val name: String, @JsonProperty("url") val url: String, @JsonProperty("lang") val lang: String, ) // check if id is imdb/tmdb cause stremio addons like torrentio works base on imdbId private fun isImdborTmdb(url: String?): Boolean { return imdbUrlToIdNullable(url) != null || url?.startsWith("tmdb:") == 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: StremioC): List { val entries = mutableListOf() types.forEach { type -> val res = app.get( "${provider.mainUrl}/catalog/${type}/${id}/search=${query}.json", timeout = 120L ).parsedSafe() res?.metas?.forEach { entry -> entries.add(entry.toSearchResponse(provider)) } } return entries } suspend fun toHomePageList(provider: StremioC): HomePageList { val entries = mutableListOf() types.forEach { type -> val res = app.get( "${provider.mainUrl}/catalog/${type}/${id}.json", timeout = 120L ).parsedSafe() res?.metas?.forEach { entry -> entries.add(entry.toSearchResponse(provider)) } } return HomePageList( "$type - ${name ?: id}", entries ) } } private data class CatalogResponse(val metas: List?, val meta: CatalogEntry?) private data class Trailer( val source: String?, val type: String? ) private data class CatalogEntry( @JsonProperty("name") val name: String, @JsonProperty("id") val id: String, @JsonProperty("poster") val poster: String?, @JsonProperty("background") val background: String?, @JsonProperty("description") val description: String?, @JsonProperty("imdbRating") val imdbRating: String?, @JsonProperty("type") val type: String?, @JsonProperty("videos") val videos: List