diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index 630e03f6..e7adfb7b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -97,6 +97,7 @@ object APIHolder { RebahinProvider(), LayarKacaProvider(), HDTodayProvider(), + OpenVidsProvider(), // Metadata providers //TmdbProvider(), diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AniflixProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AniflixProvider.kt index 4a33fa52..27ab873c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AniflixProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AniflixProvider.kt @@ -3,13 +3,15 @@ package com.lagradost.cloudstream3.animeproviders import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId +import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.getQualityFromName +import java.net.URLDecoder class AniflixProvider : MainAPI() { override var mainUrl = "https://aniflix.pro" override var name = "Aniflix" - override val hasMainPage = false + override val hasMainPage = true override val supportedTypes = setOf( TvType.AnimeMovie, @@ -42,6 +44,33 @@ class AniflixProvider : MainAPI() { } } + + override suspend fun getMainPage(): HomePageResponse { + val items = ArrayList() + val soup = app.get(mainUrl).document + val elements = listOf( + Pair("Trending Now", "div:nth-child(3) > div a"), + Pair("Popular", "div:nth-child(4) > div a"), + Pair("Top Rated", "div:nth-child(5) > div a"), + ) + + elements.map { (name, element) -> + val home = soup.select(element).map { + val href = it.attr("href") + val title = it.selectFirst("p.mt-2")!!.text() + val image = it.selectFirst("img.rounded-md[sizes]")!!.attr("src").replace("/_next/image?url=","") + .replace(Regex("\\&.*\$"),"") + val realposter = URLDecoder.decode(image, "UTF-8") + newAnimeSearchResponse(title, fixUrl(href)) { + this.posterUrl = realposter + } + } + items.add(HomePageList(name, home)) + } + + return HomePageResponse(items) + } + override suspend fun search(query: String): List? { val token = getToken() val url = "$mainUrl/_next/data/$token/search.json?keyword=$query" @@ -57,6 +86,7 @@ class AniflixProvider : MainAPI() { override suspend fun load(url: String): LoadResponse { val token = getToken() + val id = Regex("$mainUrl/anime/([0-9]*)").find(url)?.groupValues?.getOrNull(1) ?: throw ErrorLoadingException("Error parsing link for id") diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/OpenVidsProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/OpenVidsProvider.kt new file mode 100644 index 00000000..49e63f72 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/OpenVidsProvider.kt @@ -0,0 +1,134 @@ +package com.lagradost.cloudstream3.movieproviders + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.animeproviders.GogoanimeProvider +import com.lagradost.cloudstream3.animeproviders.GogoanimeProvider.Companion.extractVidstream +import com.lagradost.cloudstream3.metaproviders.TmdbLink +import com.lagradost.cloudstream3.metaproviders.TmdbProvider +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.loadExtractor +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter + +class OpenVidsProvider:TmdbProvider() { + override val apiName = "OpenVids" + override var name = "OpenVids" + override var mainUrl = "https://openvids.io" + override val useMetaLoadResponse = true + override val instantLinkLoading = false + override val supportedTypes = setOf( + TvType.Movie, + TvType.TvSeries, + ) + + data class OpenvidsMain( + @JsonProperty("ok" ) val ok : Boolean? = null, + @JsonProperty("servers" ) val servers : OpenvidServers? = OpenvidServers() + ) + + data class OpenvidServers ( + @JsonProperty("streamsb" ) val streamsb : OpenvidServersData? = OpenvidServersData(), + @JsonProperty("voxzer" ) val voxzer : OpenvidServersData? = OpenvidServersData(), + @JsonProperty("mixdrop" ) val mixdrop : OpenvidServersData? = OpenvidServersData(), + @JsonProperty("doodstream" ) val doodstream : OpenvidServersData? = OpenvidServersData(), + @JsonProperty("voe" ) val voe : OpenvidServersData? = OpenvidServersData(), + @JsonProperty("vidcloud" ) val vidcloud : OpenvidServersData? = OpenvidServersData() + ) + data class OpenvidServersData ( + @JsonProperty("code" ) val code : String? = null, + @JsonProperty("updatedAt" ) val updatedAt : String? = null, + @JsonProperty("encoded" ) val encoded : Boolean? = null + ) + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + val mappedData = parseJson(data) + val (id, site) = if (mappedData.imdbID != null) listOf( + mappedData.imdbID, + "imdb" + ) else listOf(mappedData.tmdbID.toString(), "tmdb") + val isMovie = mappedData.episode == null && mappedData.season == null + val embedUrl = if (isMovie) { + if(site == "imdb") "$mainUrl/movie/$id" else + "$mainUrl/tmdb/movie/$id" + } else { + val suffix = "$id-${mappedData.season ?: 1}-${mappedData.episode ?: 1}" + if (site == "imdb") "$mainUrl/episode/$suffix" else + "$mainUrl/tmdb/episode/$suffix" + } + val zonedatetime = ZonedDateTime.now() + val timeformated = DateTimeFormatter.ISO_INSTANT.format(zonedatetime) + val headers = if (isMovie) { + mapOf( + "Host" to "openvids.io", + "User-Agent" to USER_AGENT, + "Accept" to "*/*", + "Accept-Language" to "en-US,en;q=0.5", + "Referer" to embedUrl, + "updatedAt" to timeformated, + "title" to "${mappedData.movieName}", + "year" to "2016", + "DNT" to "1", + "Alt-Used" to "openvids.io", + "Connection" to "keep-alive", + "Sec-Fetch-Dest" to "empty", + "Sec-Fetch-Mode" to "cors", + "Sec-Fetch-Site" to "same-origin", + ) + } else { + mapOf( + "Host" to "openvids.io", + "User-Agent" to USER_AGENT, + "Accept" to "*/*", + "Accept-Language" to "en-US,en;q=0.5", + "Referer" to embedUrl, + "updatedAt" to timeformated, + "title" to "${mappedData.movieName} - season 1", + "year" to "2021", + "e" to "${mappedData.episode}", + "s" to "${mappedData.season}", + "DNT" to "1", + "Alt-Used" to "openvids.io", + "Connection" to "keep-alive", + "Sec-Fetch-Dest" to "empty", + "Sec-Fetch-Mode" to "cors", + "Sec-Fetch-Site" to "same-origin", + ) + } + val json = app.get("$mainUrl/api/servers.json?imdb=${mappedData.imdbID}", headers = headers).parsedSafe() + + val listservers = listOf( + "https://streamsb.net/e/" to json?.servers?.streamsb?.code, + "https://player.voxzer.org/view/" to json?.servers?.voxzer?.code, + "https://mixdrop.co/e/" to json?.servers?.mixdrop?.code, + "https://dood.pm/e/" to json?.servers?.doodstream?.code, + "https://voe.sx/e/" to json?.servers?.voe?.code, + "https://membed.net/streaming.php?id=" to json?.servers?.vidcloud?.code + ).mapNotNull { (url, id) -> if(id==null) return@mapNotNull null else "$url$id" } + + if (json?.ok != true) return false + listservers.apmap { links -> + if (links.contains("membed")) { + val membed = VidEmbedProvider() + extractVidstream( + links, + this.name, + callback, + membed.iv, + membed.secretKey, + membed.secretDecryptKey, + membed.isUsingAdaptiveKeys, + membed.isUsingAdaptiveData) + } else + loadExtractor(links, data, callback) + } + return true + } + +} \ No newline at end of file diff --git a/docs/providers.json b/docs/providers.json index 2b7c0c99..611c1c2d 100644 --- a/docs/providers.json +++ b/docs/providers.json @@ -74,7 +74,7 @@ "ApiMDBProvider": { "language": "en", "name": "ApiMDB", - "status": 1, + "status": 0, "url": "https://v2.apimdb.net" }, "AsiaFlixProvider": {