diff --git a/ExampleProvider/build.gradle.kts b/AkwamProvider/build.gradle.kts
similarity index 84%
rename from ExampleProvider/build.gradle.kts
rename to AkwamProvider/build.gradle.kts
index 62ee453..e7d2158 100644
--- a/ExampleProvider/build.gradle.kts
+++ b/AkwamProvider/build.gradle.kts
@@ -5,8 +5,8 @@ version = 1
cloudstream {
// All of these properties are optional, you can safely remove them
- description = "Lorem Ipsum"
- authors = listOf("Cloudburst")
+ // description = "Lorem Ipsum"
+ // authors = listOf("Cloudburst")
/**
* Status int as the following:
diff --git a/ExampleProvider/src/main/AndroidManifest.xml b/AkwamProvider/src/main/AndroidManifest.xml
similarity index 52%
rename from ExampleProvider/src/main/AndroidManifest.xml
rename to AkwamProvider/src/main/AndroidManifest.xml
index 1863f02..29aec9d 100644
--- a/ExampleProvider/src/main/AndroidManifest.xml
+++ b/AkwamProvider/src/main/AndroidManifest.xml
@@ -1,2 +1,2 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/AkwamProvider/src/main/kotlin/com/lagradost/AkwamProvider.kt b/AkwamProvider/src/main/kotlin/com/lagradost/AkwamProvider.kt
new file mode 100644
index 0000000..b262f3a
--- /dev/null
+++ b/AkwamProvider/src/main/kotlin/com/lagradost/AkwamProvider.kt
@@ -0,0 +1,224 @@
+package com.lagradost
+
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.Qualities
+import org.jsoup.nodes.Element
+
+class AkwamProvider : MainAPI() {
+ override var lang = "ar"
+ override var mainUrl = "https://akwam.to"
+ override var name = "Akwam"
+ override val usesWebView = false
+ override val hasMainPage = true
+ override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime, TvType.Cartoon)
+
+ private fun Element.toSearchResponse(): SearchResponse? {
+ val url = select("a.box").attr("href") ?: return null
+ if (url.contains("/games/") || url.contains("/programs/")) return null
+ val poster = select("picture > img")
+ val title = poster.attr("alt")
+ val posterUrl = poster.attr("data-src")
+ val year = select(".badge-secondary").text().toIntOrNull()
+
+ // If you need to differentiate use the url.
+ return MovieSearchResponse(
+ title,
+ url,
+ this@AkwamProvider.name,
+ TvType.TvSeries,
+ posterUrl,
+ year,
+ null,
+ )
+ }
+
+ override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
+ // Title, Url
+ val moviesUrl = listOf(
+ "Movies" to "$mainUrl/movies",
+ "Series" to "$mainUrl/series",
+ "Shows" to "$mainUrl/shows"
+ )
+ val pages = moviesUrl.apmap {
+ val doc = app.get(it.second).document
+ val list = doc.select("div.col-lg-auto.col-md-4.col-6.mb-12").mapNotNull { element ->
+ element.toSearchResponse()
+ }
+ HomePageList(it.first, list)
+ }.sortedBy { it.name }
+ return HomePageResponse(pages)
+ }
+
+ override suspend fun search(query: String): List {
+ val url = "$mainUrl/search?q=$query"
+ val doc = app.get(url).document
+ return doc.select("div.col-lg-auto").mapNotNull {
+ it.toSearchResponse()
+ }
+ }
+
+ private fun String.getIntFromText(): Int? {
+ return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
+ }
+
+ private fun Element.toEpisode(): Episode {
+ val a = select("a.text-white")
+ val url = a.attr("href")
+ val title = a.text()
+ val thumbUrl = select("picture > img").attr("src")
+ val date = select("p.entry-date").text()
+ return newEpisode(url) {
+ name = title
+ episode = title.getIntFromText()
+ posterUrl = thumbUrl
+ addDate(date)
+ }
+ }
+
+
+ override suspend fun load(url: String): LoadResponse {
+ val doc = app.get(url).document
+ val isMovie = url.contains("/movie/")
+ val title = doc.select("h1.entry-title").text()
+ val posterUrl = doc.select("picture > img").attr("src")
+
+ val year =
+ doc.select("div.font-size-16.text-white.mt-2").firstOrNull {
+ it.text().contains("السنة")
+ }?.text()?.getIntFromText()
+
+ // A bit iffy to parse twice like this, but it'll do.
+ val duration =
+ doc.select("div.font-size-16.text-white.mt-2").firstOrNull {
+ it.text().contains("مدة الفيلم")
+ }?.text()?.getIntFromText()
+
+ val synopsis = doc.select("div.widget-body p:first-child").text()
+
+ val rating = doc.select("span.mx-2").text().split("/").lastOrNull()?.toRatingInt()
+
+ val tags = doc.select("div.font-size-16.d-flex.align-items-center.mt-3 > a").map {
+ it.text()
+ }
+
+ val actors = doc.select("div.widget-body > div > div.entry-box > a").mapNotNull {
+ val name = it?.selectFirst("div > .entry-title")?.text() ?: return@mapNotNull null
+ val image = it.selectFirst("div > img")?.attr("src") ?: return@mapNotNull null
+ Actor(name, image)
+ }
+
+ val recommendations =
+ doc.select("div > div.widget-body > div.row > div > div.entry-box").mapNotNull {
+ val recTitle = it?.selectFirst("div.entry-body > .entry-title > .text-white")
+ ?: return@mapNotNull null
+ val href = recTitle.attr("href") ?: return@mapNotNull null
+ val name = recTitle.text() ?: return@mapNotNull null
+ val poster = it.selectFirst(".entry-image > a > picture > img")?.attr("data-src")
+ ?: return@mapNotNull null
+ MovieSearchResponse(name, href, this.name, TvType.Movie, fixUrl(poster))
+ }
+
+ return if (isMovie) {
+ newMovieLoadResponse(
+ title,
+ url,
+ TvType.Movie,
+ url
+ ) {
+ this.posterUrl = posterUrl
+ this.year = year
+ this.plot = synopsis
+ this.rating = rating
+ this.tags = tags
+ this.duration = duration
+ this.recommendations = recommendations
+ addActors(actors)
+ }
+ } else {
+ val episodes = doc.select("div.bg-primary2.p-4.col-lg-4.col-md-6.col-12").map {
+ it.toEpisode()
+ }.let {
+ val isReversed = (it.lastOrNull()?.episode ?: 1) < (it.firstOrNull()?.episode ?: 0)
+ if (isReversed)
+ it.reversed()
+ else it
+ }
+
+ newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
+ this.duration = duration
+ this.posterUrl = posterUrl
+ this.tags = tags.filterNotNull()
+ this.rating = rating
+ this.year = year
+ this.plot = synopsis
+ this.recommendations = recommendations
+ addActors(actors)
+ }
+ }
+ }
+
+
+// // Maybe possible to not use the url shortener but cba investigating that.
+// private suspend fun skipUrlShortener(url: String): AppResponse {
+// return app.get(app.get(url).document.select("a.download-link").attr("href"))
+// }
+
+ private fun getQualityFromId(id: Int?): Qualities {
+ return when (id) {
+ 2 -> Qualities.P360 // Extrapolated
+ 3 -> Qualities.P480
+ 4 -> Qualities.P720
+ 5 -> Qualities.P1080
+ else -> Qualities.Unknown
+ }
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ val doc = app.get(data).document
+
+ val links = doc.select("div.tab-content.quality").map { element ->
+ val quality = getQualityFromId(element.attr("id").getIntFromText())
+ element.select(".col-lg-6 > a:contains(تحميل)").map { linkElement ->
+ if (linkElement.attr("href").contains("/download/")) {
+ Pair(
+ linkElement.attr("href"),
+ quality,
+ )
+ } else {
+ val url = "$mainUrl/download${
+ linkElement.attr("href").split("/link")[1]
+ }${data.split("/movie|/episode|/show/episode".toRegex())[1]}"
+ Pair(
+ url,
+ quality,
+ )
+ // just in case if they add the shorts urls again
+ }
+ }
+ }.flatten()
+
+ links.map {
+ val linkDoc = app.get(it.first).document
+ val button = linkDoc.select("div.btn-loader > a")
+ val url = button.attr("href")
+
+ callback.invoke(
+ ExtractorLink(
+ this.name,
+ this.name,
+ url,
+ this.mainUrl,
+ it.second.value
+ )
+ )
+ }
+ return true
+ }
+}
diff --git a/AkwamProvider/src/main/kotlin/com/lagradost/AkwamProviderPlugin.kt b/AkwamProvider/src/main/kotlin/com/lagradost/AkwamProviderPlugin.kt
new file mode 100644
index 0000000..9f65a9c
--- /dev/null
+++ b/AkwamProvider/src/main/kotlin/com/lagradost/AkwamProviderPlugin.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 AkwamProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(AkwamProvider())
+ }
+}
\ No newline at end of file
diff --git a/AllMoviesForYouProvider/build.gradle.kts b/AllMoviesForYouProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/AllMoviesForYouProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/AllMoviesForYouProvider/src/main/AndroidManifest.xml b/AllMoviesForYouProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/AllMoviesForYouProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/AllMoviesForYouProvider/src/main/kotlin/com/lagradost/AllMoviesForYouProvider.kt b/AllMoviesForYouProvider/src/main/kotlin/com/lagradost/AllMoviesForYouProvider.kt
new file mode 100644
index 0000000..5cda4d2
--- /dev/null
+++ b/AllMoviesForYouProvider/src/main/kotlin/com/lagradost/AllMoviesForYouProvider.kt
@@ -0,0 +1,206 @@
+package com.lagradost
+
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.LoadResponse.Companion.addDuration
+import com.lagradost.cloudstream3.mvvm.logError
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.loadExtractor
+import org.jsoup.Jsoup
+
+class AllMoviesForYouProvider : MainAPI() {
+ companion object {
+ fun getType(t: String): TvType {
+ return when {
+ t.contains("series") -> TvType.TvSeries
+ t.contains("movies") -> TvType.Movie
+ else -> TvType.Movie
+ }
+ }
+ }
+
+ // Fetching movies will not work if this link is outdated.
+ override var mainUrl = "https://allmoviesforyou.net"
+ override var name = "AllMoviesForYou"
+ override val hasMainPage = true
+ override val supportedTypes = setOf(
+ TvType.Movie,
+ TvType.TvSeries
+ )
+
+ override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
+ val items = ArrayList()
+ val soup = app.get(mainUrl).document
+ val urls = listOf(
+ Pair("Movies", "section[data-id=movies] article.TPost.B"),
+ Pair("TV Series", "section[data-id=series] article.TPost.B"),
+ )
+ for ((name, element) in urls) {
+ try {
+ val home = soup.select(element).map {
+ val title = it.selectFirst("h2.title")!!.text()
+ val link = it.selectFirst("a")!!.attr("href")
+ TvSeriesSearchResponse(
+ title,
+ link,
+ this.name,
+ TvType.Movie,
+ fixUrl(it.selectFirst("figure img")!!.attr("data-src")),
+ null,
+ null,
+ )
+ }
+
+ items.add(HomePageList(name, home))
+ } catch (e: Exception) {
+ logError(e)
+ }
+ }
+ if (items.size <= 0) throw ErrorLoadingException()
+ return HomePageResponse(items)
+ }
+
+ override suspend fun search(query: String): List {
+ val url = "$mainUrl/?s=$query"
+ val document = app.get(url).document
+
+ val items = document.select("ul.MovieList > li > article > a")
+ return items.map { item ->
+ val href = item.attr("href")
+ val title = item.selectFirst("> h2.Title")!!.text()
+ val img = fixUrl(item.selectFirst("> div.Image > figure > img")!!.attr("data-src"))
+ val type = getType(href)
+ if (type == TvType.Movie) {
+ MovieSearchResponse(title, href, this.name, type, img, null)
+ } else {
+ TvSeriesSearchResponse(
+ title,
+ href,
+ this.name,
+ type,
+ img,
+ null,
+ null
+ )
+ }
+ }
+ }
+
+// private fun getLink(document: Document): List? {
+// val list = ArrayList()
+// Regex("iframe src=\"(.*?)\"").find(document.html())?.groupValues?.get(1)?.let {
+// list.add(it)
+// }
+// document.select("div.OptionBx")?.forEach { element ->
+// val baseElement = element.selectFirst("> a.Button")
+// val elementText = element.selectFirst("> p.AAIco-dns")?.text()
+// if (elementText == "Streamhub" || elementText == "Dood") {
+// baseElement?.attr("href")?.let { href ->
+// list.add(href)
+// }
+// }
+// }
+//
+// return if (list.isEmpty()) null else list
+// }
+
+ override suspend fun load(url: String): LoadResponse {
+ val type = getType(url)
+
+ val document = app.get(url).document
+
+ val title = document.selectFirst("h1.Title")!!.text()
+ val descipt = document.selectFirst("div.Description > p")!!.text()
+ val rating =
+ document.selectFirst("div.Vote > div.post-ratings > span")?.text()?.toRatingInt()
+ val year = document.selectFirst("span.Date")?.text()
+ val duration = document.selectFirst("span.Time")!!.text()
+ val backgroundPoster =
+ fixUrlNull(document.selectFirst("div.Image > figure > img")?.attr("data-src"))
+
+ if (type == TvType.TvSeries) {
+ val list = ArrayList>()
+
+ document.select("main > section.SeasonBx > div > div.Title > a").forEach { element ->
+ val season = element.selectFirst("> span")?.text()?.toIntOrNull()
+ val href = element.attr("href")
+ if (season != null && season > 0 && !href.isNullOrBlank()) {
+ list.add(Pair(season, fixUrl(href)))
+ }
+ }
+ if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found")
+
+ val episodeList = ArrayList()
+
+ for (season in list) {
+ val seasonResponse = app.get(season.second).text
+ val seasonDocument = Jsoup.parse(seasonResponse)
+ val episodes = seasonDocument.select("table > tbody > tr")
+ if (episodes.isNotEmpty()) {
+ episodes.forEach { episode ->
+ val epNum = episode.selectFirst("> td > span.Num")?.text()?.toIntOrNull()
+ val poster = episode.selectFirst("> td.MvTbImg > a > img")?.attr("data-src")
+ val aName = episode.selectFirst("> td.MvTbTtl > a")
+ val name = aName!!.text()
+ val href = aName.attr("href")
+ val date = episode.selectFirst("> td.MvTbTtl > span")?.text()
+
+ episodeList.add(
+ newEpisode(href) {
+ this.name = name
+ this.season = season.first
+ this.episode = epNum
+ this.posterUrl = fixUrlNull(poster)
+ addDate(date)
+ }
+ )
+ }
+ }
+ }
+ return TvSeriesLoadResponse(
+ title,
+ url,
+ this.name,
+ type,
+ episodeList,
+ backgroundPoster,
+ year?.toIntOrNull(),
+ descipt,
+ null,
+ rating
+ )
+ } else {
+ return newMovieLoadResponse(
+ title,
+ url,
+ type,
+ fixUrl(url)
+ ) {
+ posterUrl = backgroundPoster
+ this.year = year?.toIntOrNull()
+ this.plot = descipt
+ this.rating = rating
+ addDuration(duration)
+ }
+ }
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ val doc = app.get(data).document
+ val iframe = doc.select("body iframe").map { fixUrl(it.attr("src")) }
+ iframe.apmap { id ->
+ if (id.contains("trembed")) {
+ val soup = app.get(id).document
+ soup.select("body iframe").map {
+ val link = fixUrl(it.attr("src").replace("streamhub.to/d/", "streamhub.to/e/"))
+ loadExtractor(link, data, subtitleCallback, callback)
+ }
+ } else loadExtractor(id, data, subtitleCallback, callback)
+ }
+ return true
+ }
+}
diff --git a/AllMoviesForYouProvider/src/main/kotlin/com/lagradost/AllMoviesForYouProviderPlugin.kt b/AllMoviesForYouProvider/src/main/kotlin/com/lagradost/AllMoviesForYouProviderPlugin.kt
new file mode 100644
index 0000000..bc59d5f
--- /dev/null
+++ b/AllMoviesForYouProvider/src/main/kotlin/com/lagradost/AllMoviesForYouProviderPlugin.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 AllMoviesForYouProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(AllMoviesForYouProvider())
+ }
+}
\ No newline at end of file
diff --git a/AltadefinizioneProvider/build.gradle.kts b/AltadefinizioneProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/AltadefinizioneProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/AltadefinizioneProvider/src/main/AndroidManifest.xml b/AltadefinizioneProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/AltadefinizioneProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProvider.kt b/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProvider.kt
new file mode 100644
index 0000000..1a3fa77
--- /dev/null
+++ b/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProvider.kt
@@ -0,0 +1,160 @@
+package com.lagradost
+
+//import androidx.core.text.parseAsHtml
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.loadExtractor
+import com.lagradost.cloudstream3.utils.AppUtils.html
+
+
+class AltadefinizioneProvider : MainAPI() {
+ override var lang = "it"
+ override var mainUrl = "https://altadefinizione.tienda"
+ override var name = "Altadefinizione"
+ override val hasMainPage = true
+ override val hasChromecastSupport = true
+ override val supportedTypes = setOf(
+ TvType.Movie
+ )
+
+ override val mainPage = mainPageOf(
+ Pair("$mainUrl/cerca/anno/2022/page/", "Ultimi Film"),
+ Pair("$mainUrl/cerca/openload-quality/HD/page/", "Film in HD"),
+ Pair("$mainUrl/cinema/page/", "Ora al cinema")
+ )
+
+ override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
+ val url = request.data + page
+
+ val soup = app.get(url).document
+ val home = soup.select("div.box").map {
+ val title = it.selectFirst("img")!!.attr("alt")
+ val link = it.selectFirst("a")!!.attr("href")
+ val image = mainUrl + it.selectFirst("img")!!.attr("src")
+ val quality = getQualityFromString(it.selectFirst("span")!!.text())
+
+ MovieSearchResponse(
+ title,
+ link,
+ this.name,
+ TvType.Movie,
+ image,
+ null,
+ null,
+ quality,
+ )
+ }
+ return newHomePageResponse(request.name, home)
+ }
+
+ override suspend fun search(query: String): List {
+ val doc = app.post(
+ "$mainUrl/index.php", data = mapOf(
+ "do" to "search",
+ "subaction" to "search",
+ "story" to query,
+ "sortby" to "news_read"
+ )
+ ).document
+ return doc.select("div.box").map {
+ val title = it.selectFirst("img")!!.attr("alt")
+ val link = it.selectFirst("a")!!.attr("href")
+ val image = mainUrl + it.selectFirst("img")!!.attr("src")
+ val quality = getQualityFromString(it.selectFirst("span")!!.text())
+
+ MovieSearchResponse(
+ title,
+ link,
+ this.name,
+ TvType.Movie,
+ image,
+ null,
+ null,
+ quality,
+ )
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse {
+ val page = app.get(url)
+ val document = page.document
+ val title = document.selectFirst(" h1 > a")!!.text().replace("streaming", "")
+ val description = document.select("#sfull").toString().substringAfter("altadefinizione")
+ .substringBeforeLast("fonte trama").html().toString()
+ val rating = null
+
+ val year = document.selectFirst("#details > li:nth-child(2)")!!.childNode(2).toString()
+ .filter { it.isDigit() }.toInt()
+
+ val poster = fixUrl(document.selectFirst("div.thumbphoto > img")!!.attr("src"))
+
+ val recomm = document.select("ul.related-list > li").map {
+ val href = it.selectFirst("a")!!.attr("href")
+ val posterUrl = mainUrl + it.selectFirst("img")!!.attr("src")
+ val name = it.selectFirst("img")!!.attr("alt")
+ MovieSearchResponse(
+ name,
+ href,
+ this.name,
+ TvType.Movie,
+ posterUrl,
+ null
+ )
+
+ }
+
+
+ val actors: List =
+ document.select("#staring > a").map {
+ ActorData(actor = Actor(it.text()))
+ }
+
+ val tags: List = document.select("#details > li:nth-child(1) > a").map { it.text() }
+
+ val trailerurl = document.selectFirst("#showtrailer > div > div > iframe")?.attr("src")
+
+ return newMovieLoadResponse(
+ title,
+ url,
+ TvType.Movie,
+ url
+ ) {
+ posterUrl = fixUrlNull(poster)
+ this.year = year
+ this.plot = description
+ this.rating = rating
+ this.recommendations = recomm
+ this.duration = null
+ this.actors = actors
+ this.tags = tags
+ addTrailer(trailerurl)
+ }
+ }
+
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ val doc = app.get(data).document
+ if (doc.select("div.guardahd-player").isNullOrEmpty()) {
+ val videoUrl =
+ doc.select("input").last { it.hasAttr("data-mirror") }.attr("value")
+ loadExtractor(videoUrl, data, subtitleCallback, callback)
+ doc.select("#mirrors > li > a").forEach {
+ loadExtractor(fixUrl(it.attr("data-target")), data, subtitleCallback, callback)
+ }
+ } else {
+ val pagelinks = doc.select("div.guardahd-player").select("iframe").attr("src")
+ val docLinks = app.get(pagelinks).document
+ docLinks.select("body > div > ul > li").forEach {
+ loadExtractor(fixUrl(it.attr("data-link")), data, subtitleCallback, callback)
+ }
+ }
+
+ return true
+ }
+}
\ No newline at end of file
diff --git a/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProviderPlugin.kt b/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProviderPlugin.kt
new file mode 100644
index 0000000..1e9a49b
--- /dev/null
+++ b/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProviderPlugin.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 AltadefinizioneProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(AltadefinizioneProvider())
+ }
+}
\ No newline at end of file
diff --git a/AsiaFlixProvider/build.gradle.kts b/AsiaFlixProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/AsiaFlixProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/AsiaFlixProvider/src/main/AndroidManifest.xml b/AsiaFlixProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/AsiaFlixProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/AsiaFlixProvider/src/main/kotlin/com/lagradost/AsiaFlixProvider.kt b/AsiaFlixProvider/src/main/kotlin/com/lagradost/AsiaFlixProvider.kt
new file mode 100644
index 0000000..cc8d3ad
--- /dev/null
+++ b/AsiaFlixProvider/src/main/kotlin/com/lagradost/AsiaFlixProvider.kt
@@ -0,0 +1,198 @@
+package com.lagradost
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.fasterxml.jackson.core.JsonParser
+import com.fasterxml.jackson.module.kotlin.readValue
+import com.lagradost.cloudstream3.*
+//import com.lagradost.cloudstream3.animeproviders.GogoanimeProvider.Companion.getStatus
+import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.getQualityFromName
+import java.net.URI
+
+class AsiaFlixProvider : MainAPI() {
+ companion object {
+ fun getType(t: String): TvType {
+ return if (t.contains("OVA") || t.contains("Special")) TvType.OVA
+ else if (t.contains("Movie")) TvType.AnimeMovie
+ else TvType.Anime
+ }
+
+ fun getStatus(t: String): ShowStatus {
+ return when (t) {
+ "Completed" -> ShowStatus.Completed
+ "Ongoing" -> ShowStatus.Ongoing
+ else -> ShowStatus.Completed
+ }
+ }
+ }
+
+ override var mainUrl = "https://asiaflix.app"
+ override var name = "AsiaFlix"
+ override val hasQuickSearch = false
+ override val hasMainPage = true
+ override val hasChromecastSupport = false
+ override val supportedTypes = setOf(TvType.AsianDrama)
+
+ private val apiUrl = "https://api.asiaflix.app/api/v2"
+
+ data class DashBoardObject(
+ @JsonProperty("sectionName") val sectionName: String,
+ @JsonProperty("type") val type: String?,
+ @JsonProperty("data") val data: List?
+ )
+
+ data class Episodes(
+ @JsonProperty("_id") val _id: String,
+ @JsonProperty("epUrl") val epUrl: String?,
+ @JsonProperty("number") val number: Int?,
+ @JsonProperty("type") val type: String?,
+ @JsonProperty("extracted") val extracted: String?,
+ @JsonProperty("videoUrl") val videoUrl: String?
+ )
+
+
+ data class Data(
+ @JsonProperty("_id") val _id: String,
+ @JsonProperty("name") val name: String,
+ @JsonProperty("altNames") val altNames: String?,
+ @JsonProperty("image") val image: String?,
+ @JsonProperty("tvStatus") val tvStatus: String?,
+ @JsonProperty("genre") val genre: String?,
+ @JsonProperty("releaseYear") val releaseYear: Int?,
+ @JsonProperty("createdAt") val createdAt: Long?,
+ @JsonProperty("episodes") val episodes: List?,
+ @JsonProperty("views") val views: Int?
+ )
+
+
+ data class DramaPage(
+ @JsonProperty("_id") val _id: String,
+ @JsonProperty("name") val name: String,
+ @JsonProperty("altNames") val altNames: String?,
+ @JsonProperty("synopsis") val synopsis: String?,
+ @JsonProperty("image") val image: String?,
+ @JsonProperty("language") val language: String?,
+ @JsonProperty("dramaUrl") val dramaUrl: String?,
+ @JsonProperty("published") val published: Boolean?,
+ @JsonProperty("tvStatus") val tvStatus: String?,
+ @JsonProperty("firstAirDate") val firstAirDate: String?,
+ @JsonProperty("genre") val genre: String?,
+ @JsonProperty("releaseYear") val releaseYear: Int?,
+ @JsonProperty("createdAt") val createdAt: Long?,
+ @JsonProperty("modifiedAt") val modifiedAt: Long?,
+ @JsonProperty("episodes") val episodes: List,
+ @JsonProperty("__v") val __v: Int?,
+ @JsonProperty("cdnImage") val cdnImage: String?,
+ @JsonProperty("views") val views: Int?
+ )
+
+ private fun Data.toSearchResponse(): TvSeriesSearchResponse {
+ return TvSeriesSearchResponse(
+ name,
+ _id,
+ this@AsiaFlixProvider.name,
+ TvType.AsianDrama,
+ image,
+ releaseYear,
+ episodes?.size,
+ )
+ }
+
+ private fun Episodes.toEpisode(): Episode? {
+ if (videoUrl != null && videoUrl.contains("watch/null") || number == null) return null
+ return videoUrl?.let {
+ Episode(
+ it,
+ null,
+ number,
+ )
+ }
+ }
+
+ private fun DramaPage.toLoadResponse(): TvSeriesLoadResponse {
+ return TvSeriesLoadResponse(
+ name,
+ "$mainUrl$dramaUrl/$_id".replace("drama-detail", "show-details"),
+ this@AsiaFlixProvider.name,
+ TvType.AsianDrama,
+ episodes.mapNotNull { it.toEpisode() }.sortedBy { it.episode },
+ image,
+ releaseYear,
+ synopsis,
+ getStatus(tvStatus ?: ""),
+ null,
+ genre?.split(",")?.map { it.trim() }
+ )
+ }
+
+ override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
+ val headers = mapOf("X-Requested-By" to "asiaflix-web")
+ val response = app.get("$apiUrl/dashboard", headers = headers).text
+
+ val customMapper =
+ mapper.copy().configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
+ // Hack, because it can either be object or a list
+ val cleanedResponse = Regex(""""data":(\{.*?),\{"sectionName"""").replace(response) {
+ """"data":null},{"sectionName""""
+ }
+
+ val dashBoard = customMapper.readValue?>(cleanedResponse)
+
+ val listItems = dashBoard?.mapNotNull {
+ it.data?.map { data ->
+ data.toSearchResponse()
+ }?.let { searchResponse ->
+ HomePageList(it.sectionName, searchResponse)
+ }
+ }
+ return HomePageResponse(listItems ?: listOf())
+ }
+
+ data class Link(
+ @JsonProperty("url") val url: String?,
+ )
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ if (isCasting) return false
+ val headers = mapOf("X-Requested-By" to "asiaflix-web")
+ app.get(
+ "$apiUrl/utility/get-stream-links?url=$data",
+ headers = headers
+ ).text.toKotlinObject().url?.let {
+// val fixedUrl = "https://api.asiaflix.app/api/v2/utility/cors-proxy/playlist/${URLEncoder.encode(it, StandardCharsets.UTF_8.toString())}"
+ callback.invoke(
+ ExtractorLink(
+ name,
+ name,
+ it,
+ "https://asianload1.com/",
+ /** <------ This provider should be added instead */
+ getQualityFromName(it),
+ URI(it).path.endsWith(".m3u8")
+ )
+ )
+ }
+ return true
+ }
+
+ override suspend fun search(query: String): List? {
+ val headers = mapOf("X-Requested-By" to "asiaflix-web")
+ val url = "$apiUrl/drama/search?q=$query"
+ val response = app.get(url, headers = headers).text
+ return mapper.readValue?>(response)?.map { it.toSearchResponse() }
+ }
+
+ override suspend fun load(url: String): LoadResponse {
+ val headers = mapOf("X-Requested-By" to "asiaflix-web")
+ val requestUrl = "$apiUrl/drama?id=${url.split("/").lastOrNull()}"
+ val response = app.get(requestUrl, headers = headers).text
+ val dramaPage = response.toKotlinObject()
+ return dramaPage.toLoadResponse()
+ }
+}
diff --git a/AsiaFlixProvider/src/main/kotlin/com/lagradost/AsiaFlixProviderPlugin.kt b/AsiaFlixProvider/src/main/kotlin/com/lagradost/AsiaFlixProviderPlugin.kt
new file mode 100644
index 0000000..f6656e4
--- /dev/null
+++ b/AsiaFlixProvider/src/main/kotlin/com/lagradost/AsiaFlixProviderPlugin.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 AsiaFlixProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(AsiaFlixProvider())
+ }
+}
\ No newline at end of file
diff --git a/AsianLoadProvider/build.gradle.kts b/AsianLoadProvider/build.gradle.kts
new file mode 100644
index 0000000..df3927d
--- /dev/null
+++ b/AsianLoadProvider/build.gradle.kts
@@ -0,0 +1,25 @@
+dependencies {
+ implementation(project(mapOf("path" to ":VidstreamProviderTemplate")))
+}
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/AsianLoadProvider/src/main/AndroidManifest.xml b/AsianLoadProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/AsianLoadProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/AsianLoadProvider/src/main/kotlin/com/lagradost/AsianLoadProvider.kt b/AsianLoadProvider/src/main/kotlin/com/lagradost/AsianLoadProvider.kt
new file mode 100644
index 0000000..58bafdf
--- /dev/null
+++ b/AsianLoadProvider/src/main/kotlin/com/lagradost/AsianLoadProvider.kt
@@ -0,0 +1,25 @@
+package com.lagradost
+
+import com.lagradost.cloudstream3.TvType
+
+/** Needs to inherit from MainAPI() to
+ * make the app know what functions to call
+ */
+class AsianLoadProvider : VidstreamProviderTemplate() {
+ override var name = "AsianLoad"
+ override var mainUrl = "https://asianembed.io"
+ override val homePageUrlList = listOf(
+ mainUrl,
+ "$mainUrl/recently-added-raw",
+ "$mainUrl/movies",
+ "$mainUrl/kshow",
+ "$mainUrl/popular",
+ "$mainUrl/ongoing-series"
+ )
+
+ override val iv = "9262859232435825"
+ override val secretKey = "93422192433952489752342908585752"
+ override val secretDecryptKey = secretKey
+
+ override val supportedTypes = setOf(TvType.AsianDrama)
+}
diff --git a/AsianLoadProvider/src/main/kotlin/com/lagradost/AsianLoadProviderPlugin.kt b/AsianLoadProvider/src/main/kotlin/com/lagradost/AsianLoadProviderPlugin.kt
new file mode 100644
index 0000000..09cfea2
--- /dev/null
+++ b/AsianLoadProvider/src/main/kotlin/com/lagradost/AsianLoadProviderPlugin.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 AsianLoadProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(AsianLoadProvider())
+ }
+}
\ No newline at end of file
diff --git a/BflixProvider/build.gradle.kts b/BflixProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/BflixProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/BflixProvider/src/main/AndroidManifest.xml b/BflixProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/BflixProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/BflixProvider/src/main/kotlin/com/lagradost/BflixProvider.kt b/BflixProvider/src/main/kotlin/com/lagradost/BflixProvider.kt
new file mode 100644
index 0000000..1129895
--- /dev/null
+++ b/BflixProvider/src/main/kotlin/com/lagradost/BflixProvider.kt
@@ -0,0 +1,300 @@
+package com.lagradost
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider.Companion.decodeVrf
+import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider.Companion.encode
+import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider.Companion.encodeVrf
+import com.lagradost.cloudstream3.utils.AppUtils.parseJson
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.loadExtractor
+import org.jsoup.Jsoup
+
+open class BflixProvider : MainAPI() {
+ override var mainUrl = "https://bflix.ru"
+ override var name = "Bflix"
+ override val hasMainPage = true
+ override val hasChromecastSupport = true
+ override val hasDownloadSupport = true
+ override val supportedTypes = setOf(
+ TvType.Movie,
+ TvType.TvSeries,
+ )
+
+ //override val uniqueId: Int by lazy { "BflixProvider".hashCode() }
+
+ override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
+ val items = ArrayList()
+ val soup = app.get("$mainUrl/home").document
+ val testa = listOf(
+ Pair("Movies", "div.tab-content[data-name=movies] div.filmlist div.item"),
+ Pair("Shows", "div.tab-content[data-name=shows] div.filmlist div.item"),
+ Pair("Trending", "div.tab-content[data-name=trending] div.filmlist div.item"),
+ Pair(
+ "Latest Movies",
+ "div.container section.bl:contains(Latest Movies) div.filmlist div.item"
+ ),
+ Pair(
+ "Latest TV-Series",
+ "div.container section.bl:contains(Latest TV-Series) div.filmlist div.item"
+ ),
+ )
+ for ((name, element) in testa) try {
+ val test = soup.select(element).map {
+ val title = it.selectFirst("h3 a")!!.text()
+ val link = fixUrl(it.selectFirst("a")!!.attr("href"))
+ val qualityInfo = it.selectFirst("div.quality")!!.text()
+ val quality = getQualityFromString(qualityInfo)
+ TvSeriesSearchResponse(
+ title,
+ link,
+ this.name,
+ if (link.contains("/movie/")) TvType.Movie else TvType.TvSeries,
+ it.selectFirst("a.poster img")!!.attr("src"),
+ null,
+ null,
+ quality = quality
+ )
+ }
+ items.add(HomePageList(name, test))
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+
+ if (items.size <= 0) throw ErrorLoadingException()
+ return HomePageResponse(items)
+ }
+
+ override suspend fun search(query: String): List? {
+ val encodedquery = encodeVrf(query, mainKey)
+ val url = "$mainUrl/search?keyword=$query&vrf=$encodedquery"
+ val html = app.get(url).text
+ val document = Jsoup.parse(html)
+
+ return document.select(".filmlist div.item").map {
+ val title = it.selectFirst("h3 a")!!.text()
+ val href = fixUrl(it.selectFirst("a")!!.attr("href"))
+ val image = it.selectFirst("a.poster img")!!.attr("src")
+ val isMovie = href.contains("/movie/")
+ val qualityInfo = it.selectFirst("div.quality")!!.text()
+ val quality = getQualityFromString(qualityInfo)
+
+ if (isMovie) {
+ MovieSearchResponse(
+ title,
+ href,
+ this.name,
+ TvType.Movie,
+ image,
+ null,
+ quality = quality
+ )
+ } else {
+ TvSeriesSearchResponse(
+ title,
+ href,
+ this.name,
+ TvType.TvSeries,
+ image,
+ null,
+ null,
+ quality = quality
+ )
+ }
+ }
+ }
+
+ data class Response(
+ @JsonProperty("html") val html: String
+ )
+
+ companion object {
+ val mainKey = "OrAimkpzm6phmN3j"
+ }
+
+ override suspend fun load(url: String): LoadResponse? {
+ val soup = app.get(url).document
+ val movieid = soup.selectFirst("div#watch")!!.attr("data-id")
+ val movieidencoded = encodeVrf(movieid, mainKey)
+ val title = soup.selectFirst("div.info h1")!!.text()
+ val description = soup.selectFirst(".info .desc")?.text()?.trim()
+ val poster: String? = try {
+ soup.selectFirst("img.poster")!!.attr("src")
+ } catch (e: Exception) {
+ soup.selectFirst(".info .poster img")!!.attr("src")
+ }
+
+ val tags = soup.select("div.info .meta div:contains(Genre) a").map { it.text() }
+ val vrfUrl = "$mainUrl/ajax/film/servers?id=$movieid&vrf=$movieidencoded"
+ println("VRF___ $vrfUrl")
+ val episodes = Jsoup.parse(
+ app.get(
+ vrfUrl
+ ).parsed().html
+ ).select("div.episode").map {
+ val a = it.selectFirst("a")
+ val href = fixUrl(a!!.attr("href"))
+ val extraData = a.attr("data-kname").let { str ->
+ str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() }
+ }
+ val isValid = extraData.size == 2
+ val episode = if (isValid) extraData.getOrNull(1) else null
+ val season = if (isValid) extraData.getOrNull(0) else null
+
+ val eptitle = it.selectFirst(".episode a span.name")!!.text()
+ val secondtitle = it.selectFirst(".episode a span")!!.text()
+ .replace(Regex("(Episode (\\d+):|Episode (\\d+)-|Episode (\\d+))"), "") ?: ""
+ Episode(
+ href,
+ secondtitle + eptitle,
+ season,
+ episode,
+ )
+ }
+ val tvType =
+ if (url.contains("/movie/") && episodes.size == 1) TvType.Movie else TvType.TvSeries
+ val recommendations =
+ soup.select("div.bl-2 section.bl div.content div.filmlist div.item")
+ .mapNotNull { element ->
+ val recTitle = element.select("h3 a").text() ?: return@mapNotNull null
+ val image = element.select("a.poster img")?.attr("src")
+ val recUrl = fixUrl(element.select("a").attr("href"))
+ MovieSearchResponse(
+ recTitle,
+ recUrl,
+ this.name,
+ if (recUrl.contains("/movie/")) TvType.Movie else TvType.TvSeries,
+ image,
+ year = null
+ )
+ }
+ val rating = soup.selectFirst(".info span.imdb")?.text()?.toRatingInt()
+ val durationdoc = soup.selectFirst("div.info div.meta").toString()
+ val durationregex = Regex("((\\d+) min)")
+ val yearegex = Regex("(\\d+)")
+ val duration = if (durationdoc.contains("na min")) null
+ else durationregex.find(durationdoc)?.destructured?.component1()?.replace(" min", "")
+ ?.toIntOrNull()
+ val year = if (mainUrl == "https://bflix.ru") {
+ yearegex.find(durationdoc)?.destructured?.component1()
+ ?.replace(Regex("|"), "")
+ } else null
+ return when (tvType) {
+ TvType.TvSeries -> {
+ TvSeriesLoadResponse(
+ title,
+ url,
+ this.name,
+ tvType,
+ episodes,
+ poster,
+ year?.toIntOrNull(),
+ description,
+ null,
+ rating,
+ tags,
+ recommendations = recommendations,
+ duration = duration,
+ )
+ }
+ TvType.Movie -> {
+ MovieLoadResponse(
+ title,
+ url,
+ this.name,
+ tvType,
+ url,
+ poster,
+ year?.toIntOrNull(),
+ description,
+ rating,
+ tags,
+ recommendations = recommendations,
+ duration = duration
+ )
+ }
+ else -> null
+ }
+ }
+
+
+ data class Subtitles(
+ @JsonProperty("file") val file: String,
+ @JsonProperty("label") val label: String,
+ @JsonProperty("kind") val kind: String
+ )
+
+ data class Links(
+ @JsonProperty("url") val url: String
+ )
+
+ data class Servers(
+ @JsonProperty("28") val mcloud: String?,
+ @JsonProperty("35") val mp4upload: String?,
+ @JsonProperty("40") val streamtape: String?,
+ @JsonProperty("41") val vidstream: String?,
+ @JsonProperty("43") val videovard: String?
+ )
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ val soup = app.get(data).document
+
+ val movieid = encode(soup.selectFirst("div#watch")?.attr("data-id") ?: return false)
+ val movieidencoded = encodeVrf(movieid, mainKey)
+ Jsoup.parse(
+ parseJson(
+ app.get(
+ "$mainUrl/ajax/film/servers?id=$movieid&vrf=$movieidencoded"
+ ).text
+ ).html
+ )
+ .select("html body #episodes").map {
+ val cleandata = data.replace(mainUrl, "")
+ val a = it.select("a").map {
+ it.attr("data-kname")
+ }
+ val tvType =
+ if (data.contains("movie/") && a.size == 1) TvType.Movie else TvType.TvSeries
+ val servers = if (tvType == TvType.Movie) it.select(".episode a").attr("data-ep")
+ else
+ it.select(".episode a[href=$cleandata]").attr("data-ep")
+ ?: it.select(".episode a[href=${cleandata.replace("/1-full", "")}]")
+ .attr("data-ep")
+ val jsonservers = parseJson(servers) ?: return@map
+ listOfNotNull(
+ jsonservers.vidstream,
+ jsonservers.mcloud,
+ jsonservers.mp4upload,
+ jsonservers.streamtape,
+ jsonservers.videovard,
+ ).mapNotNull {
+ val epserver = app.get("$mainUrl/ajax/episode/info?id=$it").text
+ (if (epserver.contains("url")) {
+ parseJson(epserver)
+ } else null)?.url?.let {
+ decodeVrf(it, mainKey)
+ }
+ }.apmap { url ->
+ loadExtractor(
+ url, data, subtitleCallback, callback
+ )
+ }
+ //Apparently any server works, I haven't found any diference
+ val sublink =
+ app.get("$mainUrl/ajax/episode/subtitles/${jsonservers.mcloud}").text
+ val jsonsub = parseJson>(sublink)
+ jsonsub.forEach { subtitle ->
+ subtitleCallback(
+ SubtitleFile(subtitle.label, subtitle.file)
+ )
+ }
+ }
+
+ return true
+ }
+}
diff --git a/BflixProvider/src/main/kotlin/com/lagradost/BflixProviderPlugin.kt b/BflixProvider/src/main/kotlin/com/lagradost/BflixProviderPlugin.kt
new file mode 100644
index 0000000..fd7de36
--- /dev/null
+++ b/BflixProvider/src/main/kotlin/com/lagradost/BflixProviderPlugin.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 BflixProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(BflixProvider())
+ }
+}
\ No newline at end of file
diff --git a/CinecalidadProvider/build.gradle.kts b/CinecalidadProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/CinecalidadProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/CinecalidadProvider/src/main/AndroidManifest.xml b/CinecalidadProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/CinecalidadProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/CinecalidadProvider/src/main/kotlin/com/lagradost/CinecalidadProvider.kt b/CinecalidadProvider/src/main/kotlin/com/lagradost/CinecalidadProvider.kt
new file mode 100644
index 0000000..fbeca40
--- /dev/null
+++ b/CinecalidadProvider/src/main/kotlin/com/lagradost/CinecalidadProvider.kt
@@ -0,0 +1,258 @@
+package com.lagradost
+
+import com.lagradost.cloudstream3.*
+// import com.lagradost.cloudstream3.extractors.Cinestart
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.loadExtractor
+
+class CinecalidadProvider : MainAPI() {
+ override var mainUrl = "https://cinecalidad.lol"
+ override var name = "Cinecalidad"
+ override var lang = "es"
+ override val hasMainPage = true
+ override val hasChromecastSupport = true
+ override val hasDownloadSupport = true
+ override val supportedTypes = setOf(
+ TvType.Movie,
+ TvType.TvSeries,
+ )
+ override val vpnStatus = VPNStatus.MightBeNeeded //Due to evoload sometimes not loading
+
+ override val mainPage = mainPageOf(
+ Pair("$mainUrl/ver-serie/page/", "Series"),
+ Pair("$mainUrl/page/", "Peliculas"),
+ Pair("$mainUrl/genero-de-la-pelicula/peliculas-en-calidad-4k/page/", "4K UHD"),
+ )
+
+ override suspend fun getMainPage(
+ page: Int,
+ request : MainPageRequest
+ ): HomePageResponse {
+ val url = request.data + page
+
+ val soup = app.get(url).document
+ val home = soup.select(".item.movies").map {
+ val title = it.selectFirst("div.in_title")!!.text()
+ val link = it.selectFirst("a")!!.attr("href")
+ TvSeriesSearchResponse(
+ title,
+ link,
+ this.name,
+ if (link.contains("/ver-pelicula/")) TvType.Movie else TvType.TvSeries,
+ it.selectFirst(".poster.custom img")!!.attr("data-src"),
+ null,
+ null,
+ )
+ }
+
+ return newHomePageResponse(request.name, home)
+ }
+
+ override suspend fun search(query: String): List {
+ val url = "$mainUrl/?s=${query}"
+ val document = app.get(url).document
+
+ return document.select("article").map {
+ val title = it.selectFirst("div.in_title")!!.text()
+ val href = it.selectFirst("a")!!.attr("href")
+ val image = it.selectFirst(".poster.custom img")!!.attr("data-src")
+ val isMovie = href.contains("/ver-pelicula/")
+
+ if (isMovie) {
+ MovieSearchResponse(
+ title,
+ href,
+ this.name,
+ TvType.Movie,
+ image,
+ null
+ )
+ } else {
+ TvSeriesSearchResponse(
+ title,
+ href,
+ this.name,
+ TvType.TvSeries,
+ image,
+ null,
+ null
+ )
+ }
+ }
+ }
+
+
+ override suspend fun load(url: String): LoadResponse? {
+ val soup = app.get(url, timeout = 120).document
+
+ val title = soup.selectFirst(".single_left h1")!!.text()
+ val description = soup.selectFirst("div.single_left table tbody tr td p")?.text()?.trim()
+ val poster: String? = soup.selectFirst(".alignnone")!!.attr("data-src")
+ val episodes = soup.select("div.se-c div.se-a ul.episodios li").map { li ->
+ val href = li.selectFirst("a")!!.attr("href")
+ val epThumb = li.selectFirst("img.lazy")!!.attr("data-src")
+ val name = li.selectFirst(".episodiotitle a")!!.text()
+ val seasonid =
+ li.selectFirst(".numerando")!!.text().replace(Regex("(S|E)"), "").let { str ->
+ str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() }
+ }
+ val isValid = seasonid.size == 2
+ val episode = if (isValid) seasonid.getOrNull(1) else null
+ val season = if (isValid) seasonid.getOrNull(0) else null
+ Episode(
+ href,
+ name,
+ season,
+ episode,
+ if (epThumb.contains("svg")) null else epThumb
+ )
+ }
+ return when (val tvType =
+ if (url.contains("/ver-pelicula/")) TvType.Movie else TvType.TvSeries) {
+ TvType.TvSeries -> {
+ TvSeriesLoadResponse(
+ title,
+ url,
+ this.name,
+ tvType,
+ episodes,
+ poster,
+ null,
+ description,
+ )
+ }
+ TvType.Movie -> {
+ MovieLoadResponse(
+ title,
+ url,
+ this.name,
+ tvType,
+ url,
+ poster,
+ null,
+ description,
+ )
+ }
+ else -> null
+ }
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+
+ val datam = app.get(data)
+ val doc = datam.document
+ val datatext = datam.text
+
+ doc.select(".dooplay_player_option").apmap {
+ val url = it.attr("data-option")
+// if (url.startsWith("https://cinestart.net")) {
+// val extractor = Cinestart()
+// extractor.getSafeUrl(url, null, subtitleCallback, callback)
+// } else {
+ loadExtractor(url, mainUrl, subtitleCallback, callback)
+// }
+ if (url.startsWith("https://cinecalidad.lol")) {
+ val cineurlregex =
+ Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
+ cineurlregex.findAll(url).map {
+ it.value.replace("/play/", "/play/r.php")
+ }.toList().apmap {
+ app.get(
+ it,
+ headers = mapOf(
+ "Host" to "cinecalidad.lol",
+ "User-Agent" to USER_AGENT,
+ "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
+ "Accept-Language" to "en-US,en;q=0.5",
+ "DNT" to "1",
+ "Connection" to "keep-alive",
+ "Referer" to data,
+ "Upgrade-Insecure-Requests" to "1",
+ "Sec-Fetch-Dest" to "iframe",
+ "Sec-Fetch-Mode" to "navigate",
+ "Sec-Fetch-Site" to "same-origin",
+ "Sec-Fetch-User" to "?1",
+ ),
+ allowRedirects = false
+ ).okhttpResponse.headers.values("location").apmap { extractedurl ->
+ if (extractedurl.contains("cinestart")) {
+ loadExtractor(extractedurl, mainUrl, subtitleCallback, callback)
+ }
+ }
+ }
+ }
+ }
+ if (datatext.contains("en castellano")) app.get("$data?ref=es").document.select(".dooplay_player_option")
+ .apmap {
+ val url = it.attr("data-option")
+// if (url.startsWith("https://cinestart.net")) {
+// val extractor = Cinestart()
+// extractor.getSafeUrl(url, null, subtitleCallback, callback)
+// } else {
+ loadExtractor(url, mainUrl, subtitleCallback, callback)
+// }
+
+ if (url.startsWith("https://cinecalidad.lol")) {
+ val cineurlregex =
+ Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
+ cineurlregex.findAll(url).map {
+ it.value.replace("/play/", "/play/r.php")
+ }.toList().apmap {
+ app.get(
+ it,
+ headers = mapOf(
+ "Host" to "cinecalidad.lol",
+ "User-Agent" to USER_AGENT,
+ "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
+ "Accept-Language" to "en-US,en;q=0.5",
+ "DNT" to "1",
+ "Connection" to "keep-alive",
+ "Referer" to data,
+ "Upgrade-Insecure-Requests" to "1",
+ "Sec-Fetch-Dest" to "iframe",
+ "Sec-Fetch-Mode" to "navigate",
+ "Sec-Fetch-Site" to "same-origin",
+ "Sec-Fetch-User" to "?1",
+ ),
+ allowRedirects = false
+ ).okhttpResponse.headers.values("location").apmap { extractedurl ->
+ if (extractedurl.contains("cinestart")) {
+ loadExtractor(extractedurl, mainUrl, subtitleCallback, callback)
+ }
+ }
+ }
+ }
+ }
+ if (datatext.contains("Subtítulo LAT") || datatext.contains("Forzados LAT")) {
+ doc.select("#panel_descarga.pane a").apmap {
+ val link =
+ if (data.contains("serie") || data.contains("episodio")) "${data}${it.attr("href")}"
+ else it.attr("href")
+ val docsub = app.get(link)
+ val linksub = docsub.document
+ val validsub = docsub.text
+ if (validsub.contains("Subtítulo") || validsub.contains("Forzados")) {
+ val langregex = Regex("(Subtítulo.*\$|Forzados.*\$)")
+ val langdoc = linksub.selectFirst("div.titulo h3")!!.text()
+ val reallang = langregex.find(langdoc)?.destructured?.component1()
+ linksub.select("a.link").apmap {
+ val sublink =
+ if (data.contains("serie") || data.contains("episodio")) "${data}${
+ it.attr("href")
+ }"
+ else it.attr("href")
+ subtitleCallback(
+ SubtitleFile(reallang!!, sublink)
+ )
+ }
+ }
+ }
+ }
+ return true
+ }
+}
diff --git a/CinecalidadProvider/src/main/kotlin/com/lagradost/CinecalidadProviderPlugin.kt b/CinecalidadProvider/src/main/kotlin/com/lagradost/CinecalidadProviderPlugin.kt
new file mode 100644
index 0000000..cf4a2ca
--- /dev/null
+++ b/CinecalidadProvider/src/main/kotlin/com/lagradost/CinecalidadProviderPlugin.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 CinecalidadProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(CinecalidadProvider())
+ }
+}
\ No newline at end of file
diff --git a/CuevanaProvider/build.gradle.kts b/CuevanaProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/CuevanaProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/CuevanaProvider/src/main/AndroidManifest.xml b/CuevanaProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/CuevanaProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/CuevanaProvider/src/main/kotlin/com/lagradost/CuevanaProvider.kt b/CuevanaProvider/src/main/kotlin/com/lagradost/CuevanaProvider.kt
new file mode 100644
index 0000000..9aab603
--- /dev/null
+++ b/CuevanaProvider/src/main/kotlin/com/lagradost/CuevanaProvider.kt
@@ -0,0 +1,324 @@
+package com.lagradost
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.mvvm.logError
+import com.lagradost.cloudstream3.utils.AppUtils.parseJson
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.loadExtractor
+
+class CuevanaProvider : MainAPI() {
+ override var mainUrl = "https://cuevana3.me"
+ override var name = "Cuevana"
+ override var lang = "es"
+ override val hasMainPage = true
+ override val hasChromecastSupport = true
+ override val hasDownloadSupport = true
+ override val supportedTypes = setOf(
+ TvType.Movie,
+ TvType.TvSeries,
+ )
+
+ override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
+ val items = ArrayList()
+ val urls = listOf(
+ Pair(mainUrl, "Recientemente actualizadas"),
+ Pair("$mainUrl/estrenos/", "Estrenos"),
+ )
+ items.add(
+ HomePageList(
+ "Series",
+ app.get("$mainUrl/serie", timeout = 120).document.select("section.home-series li")
+ .map {
+ val title = it.selectFirst("h2.Title")!!.text()
+ val poster = it.selectFirst("img.lazy")!!.attr("data-src")
+ val url = it.selectFirst("a")!!.attr("href")
+ TvSeriesSearchResponse(
+ title,
+ url,
+ this.name,
+ TvType.Anime,
+ poster,
+ null,
+ null,
+ )
+ })
+ )
+ for ((url, name) in urls) {
+ try {
+ val soup = app.get(url).document
+ val home = soup.select("section li.xxx.TPostMv").map {
+ val title = it.selectFirst("h2.Title")!!.text()
+ val link = it.selectFirst("a")!!.attr("href")
+ TvSeriesSearchResponse(
+ title,
+ link,
+ this.name,
+ if (link.contains("/pelicula/")) TvType.Movie else TvType.TvSeries,
+ it.selectFirst("img.lazy")!!.attr("data-src"),
+ null,
+ null,
+ )
+ }
+
+ items.add(HomePageList(name, home))
+ } catch (e: Exception) {
+ logError(e)
+ }
+ }
+
+ if (items.size <= 0) throw ErrorLoadingException()
+ return HomePageResponse(items)
+ }
+
+ override suspend fun search(query: String): List {
+ val url = "$mainUrl/?s=${query}"
+ val document = app.get(url).document
+
+ return document.select("li.xxx.TPostMv").map {
+ val title = it.selectFirst("h2.Title")!!.text()
+ val href = it.selectFirst("a")!!.attr("href")
+ val image = it.selectFirst("img.lazy")!!.attr("data-src")
+ val isSerie = href.contains("/serie/")
+
+ if (isSerie) {
+ TvSeriesSearchResponse(
+ title,
+ href,
+ this.name,
+ TvType.TvSeries,
+ image,
+ null,
+ null
+ )
+ } else {
+ MovieSearchResponse(
+ title,
+ href,
+ this.name,
+ TvType.Movie,
+ image,
+ null
+ )
+ }
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse? {
+ val soup = app.get(url, timeout = 120).document
+ val title = soup.selectFirst("h1.Title")!!.text()
+ val description = soup.selectFirst(".Description p")?.text()?.trim()
+ val poster: String? = soup.selectFirst(".movtv-info div.Image img")!!.attr("data-src")
+ val year1 = soup.selectFirst("footer p.meta").toString()
+ val yearRegex = Regex("(\\d+)")
+ val yearf =
+ yearRegex.find(year1)?.destructured?.component1()?.replace(Regex("|"), "")
+ val year = if (yearf.isNullOrBlank()) null else yearf.toIntOrNull()
+ val episodes = soup.select(".all-episodes li.TPostMv article").map { li ->
+ val href = li.select("a").attr("href")
+ val epThumb =
+ li.selectFirst("div.Image img")?.attr("data-src") ?: li.selectFirst("img.lazy")!!
+ .attr("data-srcc")
+ val seasonid = li.selectFirst("span.Year")!!.text().let { str ->
+ str.split("x").mapNotNull { subStr -> subStr.toIntOrNull() }
+ }
+ val isValid = seasonid.size == 2
+ val episode = if (isValid) seasonid.getOrNull(1) else null
+ val season = if (isValid) seasonid.getOrNull(0) else null
+ Episode(
+ href,
+ null,
+ season,
+ episode,
+ fixUrl(epThumb)
+ )
+ }
+ val tags = soup.select("ul.InfoList li.AAIco-adjust:contains(Genero) a").map { it.text() }
+ val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries
+ val recelement =
+ if (tvType == TvType.TvSeries) "main section div.series_listado.series div.xxx"
+ else "main section ul.MovieList li"
+ val recommendations =
+ soup.select(recelement).mapNotNull { element ->
+ val recTitle = element.select("h2.Title").text() ?: return@mapNotNull null
+ val image = element.select("figure img")?.attr("data-src")
+ val recUrl = fixUrl(element.select("a").attr("href"))
+ MovieSearchResponse(
+ recTitle,
+ recUrl,
+ this.name,
+ TvType.Movie,
+ image,
+ year = null
+ )
+ }
+
+ return when (tvType) {
+ TvType.TvSeries -> {
+ TvSeriesLoadResponse(
+ title,
+ url,
+ this.name,
+ tvType,
+ episodes,
+ poster,
+ year,
+ description,
+ tags = tags,
+ recommendations = recommendations
+ )
+ }
+ TvType.Movie -> {
+ MovieLoadResponse(
+ title,
+ url,
+ this.name,
+ tvType,
+ url,
+ poster,
+ year,
+ description,
+ tags = tags,
+ recommendations = recommendations
+ )
+ }
+ else -> null
+ }
+ }
+
+ data class Femcuevana(
+ @JsonProperty("url") val url: String,
+ )
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ app.get(data).document.select("div.TPlayer.embed_div iframe").apmap {
+ val iframe = fixUrl(it.attr("data-src"))
+ if (iframe.contains("api.cuevana3.me/fembed/")) {
+ val femregex =
+ Regex("(https.\\/\\/api\\.cuevana3\\.me\\/fembed\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
+ femregex.findAll(iframe).map { femreg ->
+ femreg.value
+ }.toList().apmap { fem ->
+ val key = fem.replace("https://api.cuevana3.me/fembed/?h=", "")
+ val url = app.post(
+ "https://api.cuevana3.me/fembed/api.php",
+ allowRedirects = false,
+ headers = mapOf(
+ "Host" to "api.cuevana3.me",
+ "User-Agent" to USER_AGENT,
+ "Accept" to "application/json, text/javascript, */*; q=0.01",
+ "Accept-Language" to "en-US,en;q=0.5",
+ "Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8",
+ "X-Requested-With" to "XMLHttpRequest",
+ "Origin" to "https://api.cuevana3.me",
+ "DNT" to "1",
+ "Connection" to "keep-alive",
+ "Sec-Fetch-Dest" to "empty",
+ "Sec-Fetch-Mode" to "cors",
+ "Sec-Fetch-Site" to "same-origin",
+ ),
+ data = mapOf(Pair("h", key))
+ ).text
+ val json = parseJson(url)
+ val link = json.url
+ if (link.contains("fembed")) {
+ loadExtractor(link, data, subtitleCallback, callback)
+ }
+ }
+ }
+ if (iframe.contains("tomatomatela")) {
+ val tomatoRegex =
+ Regex("(\\/\\/apialfa.tomatomatela.com\\/ir\\/player.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
+ tomatoRegex.findAll(iframe).map { tomreg ->
+ tomreg.value
+ }.toList().apmap { tom ->
+ val tomkey = tom.replace("//apialfa.tomatomatela.com/ir/player.php?h=", "")
+ app.post(
+ "https://apialfa.tomatomatela.com/ir/rd.php", allowRedirects = false,
+ headers = mapOf(
+ "Host" to "apialfa.tomatomatela.com",
+ "User-Agent" to USER_AGENT,
+ "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
+ "Accept-Language" to "en-US,en;q=0.5",
+ "Content-Type" to "application/x-www-form-urlencoded",
+ "Origin" to "null",
+ "DNT" to "1",
+ "Connection" to "keep-alive",
+ "Upgrade-Insecure-Requests" to "1",
+ "Sec-Fetch-Dest" to "iframe",
+ "Sec-Fetch-Mode" to "navigate",
+ "Sec-Fetch-Site" to "same-origin",
+ ),
+ data = mapOf(Pair("url", tomkey))
+ ).okhttpResponse.headers.values("location").apmap { loc ->
+ if (loc.contains("goto_ddh.php")) {
+ val gotoregex =
+ Regex("(\\/\\/api.cuevana3.me\\/ir\\/goto_ddh.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
+ gotoregex.findAll(loc).map { goreg ->
+ goreg.value.replace("//api.cuevana3.me/ir/goto_ddh.php?h=", "")
+ }.toList().apmap { gotolink ->
+ app.post(
+ "https://api.cuevana3.me/ir/redirect_ddh.php",
+ allowRedirects = false,
+ headers = mapOf(
+ "Host" to "api.cuevana3.me",
+ "User-Agent" to USER_AGENT,
+ "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
+ "Accept-Language" to "en-US,en;q=0.5",
+ "Content-Type" to "application/x-www-form-urlencoded",
+ "Origin" to "null",
+ "DNT" to "1",
+ "Connection" to "keep-alive",
+ "Upgrade-Insecure-Requests" to "1",
+ "Sec-Fetch-Dest" to "iframe",
+ "Sec-Fetch-Mode" to "navigate",
+ "Sec-Fetch-Site" to "same-origin",
+ ),
+ data = mapOf(Pair("url", gotolink))
+ ).okhttpResponse.headers.values("location").apmap { golink ->
+ loadExtractor(golink, data, subtitleCallback, callback)
+ }
+ }
+ }
+ if (loc.contains("index.php?h=")) {
+ val indexRegex =
+ Regex("(\\/\\/api.cuevana3.me\\/sc\\/index.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
+ indexRegex.findAll(loc).map { indreg ->
+ indreg.value.replace("//api.cuevana3.me/sc/index.php?h=", "")
+ }.toList().apmap { inlink ->
+ app.post(
+ "https://api.cuevana3.me/sc/r.php", allowRedirects = false,
+ headers = mapOf(
+ "Host" to "api.cuevana3.me",
+ "User-Agent" to USER_AGENT,
+ "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
+ "Accept-Language" to "en-US,en;q=0.5",
+ "Accept-Encoding" to "gzip, deflate, br",
+ "Content-Type" to "application/x-www-form-urlencoded",
+ "Origin" to "null",
+ "DNT" to "1",
+ "Connection" to "keep-alive",
+ "Upgrade-Insecure-Requests" to "1",
+ "Sec-Fetch-Dest" to "iframe",
+ "Sec-Fetch-Mode" to "navigate",
+ "Sec-Fetch-Site" to "same-origin",
+ "Sec-Fetch-User" to "?1",
+ ),
+ data = mapOf(Pair("h", inlink))
+ ).okhttpResponse.headers.values("location").apmap { link ->
+ loadExtractor(link, data, subtitleCallback, callback)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/CuevanaProvider/src/main/kotlin/com/lagradost/CuevanaProviderPlugin.kt b/CuevanaProvider/src/main/kotlin/com/lagradost/CuevanaProviderPlugin.kt
new file mode 100644
index 0000000..a126075
--- /dev/null
+++ b/CuevanaProvider/src/main/kotlin/com/lagradost/CuevanaProviderPlugin.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 CuevanaProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(CuevanaProvider())
+ }
+}
\ No newline at end of file
diff --git a/DopeboxProvider/build.gradle.kts b/DopeboxProvider/build.gradle.kts
new file mode 100644
index 0000000..704695e
--- /dev/null
+++ b/DopeboxProvider/build.gradle.kts
@@ -0,0 +1,25 @@
+dependencies {
+// implementation(project(mapOf("path" to ":SflixProvider")))
+}
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/DopeboxProvider/src/main/AndroidManifest.xml b/DopeboxProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/DopeboxProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/DopeboxProvider/src/main/kotlin/com/lagradost/DopeboxProvider.kt b/DopeboxProvider/src/main/kotlin/com/lagradost/DopeboxProvider.kt
new file mode 100644
index 0000000..fbcb65e
--- /dev/null
+++ b/DopeboxProvider/src/main/kotlin/com/lagradost/DopeboxProvider.kt
@@ -0,0 +1,6 @@
+package com.lagradost
+
+class DopeboxProvider : SflixProvider() {
+ override var mainUrl = "https://dopebox.to"
+ override var name = "Dopebox"
+}
\ No newline at end of file
diff --git a/DopeboxProvider/src/main/kotlin/com/lagradost/DopeboxProviderPlugin.kt b/DopeboxProvider/src/main/kotlin/com/lagradost/DopeboxProviderPlugin.kt
new file mode 100644
index 0000000..431e308
--- /dev/null
+++ b/DopeboxProvider/src/main/kotlin/com/lagradost/DopeboxProviderPlugin.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 DopeboxProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(DopeboxProvider())
+ }
+}
\ No newline at end of file
diff --git a/DoramasYTProvider/build.gradle.kts b/DoramasYTProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/DoramasYTProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/DoramasYTProvider/src/main/AndroidManifest.xml b/DoramasYTProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/DoramasYTProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/DoramasYTProvider/src/main/kotlin/com/lagradost/DoramasYTProvider.kt b/DoramasYTProvider/src/main/kotlin/com/lagradost/DoramasYTProvider.kt
new file mode 100644
index 0000000..f4d0e99
--- /dev/null
+++ b/DoramasYTProvider/src/main/kotlin/com/lagradost/DoramasYTProvider.kt
@@ -0,0 +1,155 @@
+package com.lagradost
+
+import com.lagradost.cloudstream3.*
+//import com.lagradost.cloudstream3.extractors.FEmbed
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.loadExtractor
+import java.util.*
+
+
+class DoramasYTProvider : MainAPI() {
+ companion object {
+ fun getType(t: String): TvType {
+ return if (t.contains("OVA") || t.contains("Especial")) TvType.OVA
+ else if (t.contains("Pelicula")) TvType.Movie
+ else TvType.TvSeries
+ }
+ fun getDubStatus(title: String): DubStatus {
+ return if (title.contains("Latino") || title.contains("Castellano"))
+ DubStatus.Dubbed
+ else DubStatus.Subbed
+ }
+ }
+
+ override var mainUrl = "https://doramasyt.com"
+ override var name = "DoramasYT"
+ override var lang = "es"
+ override val hasMainPage = true
+ override val hasChromecastSupport = true
+ override val hasDownloadSupport = true
+ override val supportedTypes = setOf(
+ TvType.AsianDrama,
+ )
+
+ override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
+ val urls = listOf(
+ Pair("$mainUrl/emision", "En emisión"),
+ Pair(
+ "$mainUrl/doramas?categoria=pelicula&genero=false&fecha=false&letra=false",
+ "Peliculas"
+ ),
+ Pair("$mainUrl/doramas", "Doramas"),
+ Pair(
+ "$mainUrl/doramas?categoria=live-action&genero=false&fecha=false&letra=false",
+ "Live Action"
+ ),
+ )
+
+ val items = ArrayList()
+
+ items.add(
+ HomePageList(
+ "Capítulos actualizados",
+ app.get(mainUrl, timeout = 120).document.select(".col-6").map {
+ val title = it.selectFirst("p")!!.text()
+ val poster = it.selectFirst(".chapter img")!!.attr("src")
+ val epRegex = Regex("episodio-(\\d+)")
+ val url = it.selectFirst("a")!!.attr("href").replace("ver/", "dorama/")
+ .replace(epRegex, "sub-espanol")
+ val epNum = it.selectFirst("h3")!!.text().toIntOrNull()
+ newAnimeSearchResponse(title,url) {
+ this.posterUrl = fixUrl(poster)
+ addDubStatus(getDubStatus(title), epNum)
+ }
+ })
+ )
+
+ for (i in urls) {
+ try {
+ val home = app.get(i.first, timeout = 120).document.select(".col-6").map {
+ val title = it.selectFirst(".animedtls p")!!.text()
+ val poster = it.selectFirst(".anithumb img")!!.attr("src")
+ newAnimeSearchResponse(title, fixUrl(it.selectFirst("a")!!.attr("href"))) {
+ this.posterUrl = fixUrl(poster)
+ addDubStatus(getDubStatus(title))
+ }
+ }
+
+ items.add(HomePageList(i.second, home))
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+
+ if (items.size <= 0) throw ErrorLoadingException()
+ return HomePageResponse(items)
+ }
+
+ override suspend fun search(query: String): List {
+ return app.get("$mainUrl/buscar?q=$query", timeout = 120).document.select(".col-6").map {
+ val title = it.selectFirst(".animedtls p")!!.text()
+ val href = it.selectFirst("a")!!.attr("href")
+ val image = it.selectFirst(".animes img")!!.attr("src")
+ AnimeSearchResponse(
+ title,
+ href,
+ this.name,
+ TvType.Anime,
+ image,
+ null,
+ if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(
+ DubStatus.Dubbed
+ ) else EnumSet.of(DubStatus.Subbed),
+ )
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse {
+ val doc = app.get(url, timeout = 120).document
+ val poster = doc.selectFirst("div.flimimg img.img1")!!.attr("src")
+ val title = doc.selectFirst("h1")!!.text()
+ val type = doc.selectFirst("h4")!!.text()
+ val description = doc.selectFirst("p.textComplete")!!.text().replace("Ver menos", "")
+ val genres = doc.select(".nobel a").map { it.text() }
+ val status = when (doc.selectFirst(".state h6")?.text()) {
+ "Estreno" -> ShowStatus.Ongoing
+ "Finalizado" -> ShowStatus.Completed
+ else -> null
+ }
+ val episodes = doc.select(".heromain .col-item").map {
+ val name = it.selectFirst(".dtlsflim p")!!.text()
+ val link = it.selectFirst("a")!!.attr("href")
+ val epThumb = it.selectFirst(".flimimg img.img1")!!.attr("src")
+ Episode(link, name, posterUrl = epThumb)
+ }
+ return newAnimeLoadResponse(title, url, getType(type)) {
+ posterUrl = poster
+ addEpisodes(DubStatus.Subbed, episodes)
+ showStatus = status
+ plot = description
+ tags = genres
+ }
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ app.get(data).document.select("div.playother p").apmap {
+ val encodedurl = it.select("p").attr("data-player")
+ val urlDecoded = base64Decode(encodedurl)
+ val url = (urlDecoded).replace("https://doramasyt.com/reproductor?url=", "")
+// if (url.startsWith("https://www.fembed.com")) {
+// val extractor = FEmbed()
+// extractor.getUrl(url).forEach { link ->
+// callback.invoke(link)
+// }
+// } else {
+ loadExtractor(url, mainUrl, subtitleCallback, callback)
+// }
+ }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/DoramasYTProvider/src/main/kotlin/com/lagradost/DoramasYTProviderPlugin.kt b/DoramasYTProvider/src/main/kotlin/com/lagradost/DoramasYTProviderPlugin.kt
new file mode 100644
index 0000000..e5652d9
--- /dev/null
+++ b/DoramasYTProvider/src/main/kotlin/com/lagradost/DoramasYTProviderPlugin.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 DoramasYTProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(DoramasYTProvider())
+ }
+}
\ No newline at end of file
diff --git a/DramaSeeProvider/build.gradle.kts b/DramaSeeProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/DramaSeeProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/DramaSeeProvider/src/main/AndroidManifest.xml b/DramaSeeProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/DramaSeeProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/DramaSeeProvider/src/main/kotlin/com/lagradost/DramaSeeProvider.kt b/DramaSeeProvider/src/main/kotlin/com/lagradost/DramaSeeProvider.kt
new file mode 100644
index 0000000..22ccc56
--- /dev/null
+++ b/DramaSeeProvider/src/main/kotlin/com/lagradost/DramaSeeProvider.kt
@@ -0,0 +1,217 @@
+package com.lagradost
+
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.animeproviders.GogoanimeProvider.Companion.extractVidstream
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.loadExtractor
+
+class DramaSeeProvider : MainAPI() {
+ override var mainUrl = "https://dramasee.net"
+ override var name = "DramaSee"
+ override val hasQuickSearch = false
+ override val hasMainPage = true
+ override val hasChromecastSupport = false
+ override val hasDownloadSupport = true
+ override val supportedTypes = setOf(TvType.AsianDrama)
+
+ override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
+ val headers = mapOf("X-Requested-By" to mainUrl)
+ val document = app.get(mainUrl, headers = headers).document
+ val mainbody = document.getElementsByTag("body")
+
+ return HomePageResponse(
+ mainbody.select("section.block_area.block_area_home")?.map { main ->
+ val title = main.select("h2.cat-heading").text() ?: "Main"
+ val inner = main.select("div.flw-item") ?: return@map null
+
+ HomePageList(
+ title,
+ inner.mapNotNull {
+ val innerBody = it?.selectFirst("a")
+ // Fetch details
+ val link = fixUrlNull(innerBody?.attr("href")) ?: return@mapNotNull null
+ val image = fixUrlNull(it.select("img").attr("data-src")) ?: ""
+ val name = innerBody?.attr("title") ?: ""
+ //Log.i(this.name, "Result => (innerBody, image) ${innerBody} / ${image}")
+ MovieSearchResponse(
+ name,
+ link,
+ this.name,
+ TvType.AsianDrama,
+ image,
+ year = null,
+ id = null,
+ )
+ }.distinctBy { c -> c.url })
+ }?.filterNotNull() ?: listOf()
+ )
+ }
+
+ override suspend fun search(query: String): List {
+ val url = "$mainUrl/search?q=$query"
+ val document = app.get(url).document
+ val posters = document.select("div.film-poster")
+
+
+ return posters.mapNotNull {
+ val innerA = it.select("a") ?: return@mapNotNull null
+ val link = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null
+ val title = innerA.attr("title") ?: return@mapNotNull null
+ val year =
+ Regex(""".*\((\d{4})\)""").find(title)?.groupValues?.getOrNull(1)?.toIntOrNull()
+ val imgSrc = it.select("img")?.attr("data-src") ?: return@mapNotNull null
+ val image = fixUrlNull(imgSrc)
+
+ MovieSearchResponse(
+ name = title,
+ url = link,
+ apiName = this.name,
+ type = TvType.Movie,
+ posterUrl = image,
+ year = year
+ )
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse {
+ val doc = app.get(url).document
+ val body = doc.getElementsByTag("body")
+ val inner = body?.select("div.anis-content")
+
+ // Video details
+ val poster = fixUrlNull(inner?.select("img.film-poster-img")?.attr("src")) ?: ""
+ //Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}")
+ val title = inner?.select("h2.film-name.dynamic-name")?.text() ?: ""
+ val year = if (title.length > 5) {
+ title.substring(title.length - 5)
+ .trim().trimEnd(')').toIntOrNull()
+ } else {
+ null
+ }
+ //Log.i(this.name, "Result => (year) ${title.substring(title.length - 5)}")
+ val descript = body?.firstOrNull()?.select("div.film-description.m-hide")?.text()
+ val tags = inner?.select("div.item.item-list > a")
+ ?.mapNotNull { it?.text()?.trim() ?: return@mapNotNull null }
+ val recs = body.select("div.flw-item")?.mapNotNull {
+ val a = it.select("a") ?: return@mapNotNull null
+ val aUrl = fixUrlNull(a.attr("href")) ?: return@mapNotNull null
+ val aImg = fixUrlNull(it.select("img")?.attr("data-src"))
+ val aName = a.attr("title") ?: return@mapNotNull null
+ val aYear = aName.trim().takeLast(5).removeSuffix(")").toIntOrNull()
+ MovieSearchResponse(
+ url = aUrl,
+ name = aName,
+ type = TvType.Movie,
+ posterUrl = aImg,
+ year = aYear,
+ apiName = this.name
+ )
+ }
+
+ // Episodes Links
+ val episodeUrl = body.select("a.btn.btn-radius.btn-primary.btn-play").attr("href")
+ val episodeDoc = app.get(episodeUrl).document
+
+
+ val episodeList = episodeDoc.select("div.ss-list.ss-list-min > a").mapNotNull { ep ->
+ val episodeNumber = ep.attr("data-number").toIntOrNull()
+ val epLink = fixUrlNull(ep.attr("href")) ?: return@mapNotNull null
+
+// if (epLink.isNotBlank()) {
+// // Fetch video links
+// val epVidLinkEl = app.get(epLink, referer = mainUrl).document
+// val ajaxUrl = epVidLinkEl.select("div#js-player")?.attr("embed")
+// //Log.i(this.name, "Result => (ajaxUrl) ${ajaxUrl}")
+// if (!ajaxUrl.isNullOrEmpty()) {
+// val innerPage = app.get(fixUrl(ajaxUrl), referer = epLink).document
+// val listOfLinks = mutableListOf()
+// innerPage.select("div.player.active > main > div")?.forEach { em ->
+// val href = fixUrlNull(em.attr("src")) ?: ""
+// if (href.isNotBlank()) {
+// listOfLinks.add(href)
+// }
+// }
+//
+// //Log.i(this.name, "Result => (listOfLinks) ${listOfLinks.toJson()}")
+//
+// }
+// }
+ Episode(
+ name = null,
+ season = null,
+ episode = episodeNumber,
+ data = epLink,
+ posterUrl = null,
+ date = null
+ )
+ }
+
+ //If there's only 1 episode, consider it a movie.
+ if (episodeList.size == 1) {
+ return MovieLoadResponse(
+ name = title,
+ url = url,
+ apiName = this.name,
+ type = TvType.Movie,
+ dataUrl = episodeList.first().data,
+ posterUrl = poster,
+ year = year,
+ plot = descript,
+ recommendations = recs,
+ tags = tags
+ )
+ }
+ return TvSeriesLoadResponse(
+ name = title,
+ url = url,
+ apiName = this.name,
+ type = TvType.AsianDrama,
+ episodes = episodeList,
+ posterUrl = poster,
+ year = year,
+ plot = descript,
+ recommendations = recs,
+ tags = tags
+ )
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ println("DATATATAT $data")
+
+ val document = app.get(data).document
+ val iframeUrl = document.select("iframe").attr("src")
+ val iframe = app.get(iframeUrl)
+ val iframeDoc = iframe.document
+
+ argamap({
+ iframeDoc.select(".list-server-items > .linkserver")
+ .forEach { element ->
+ val status = element.attr("data-status") ?: return@forEach
+ if (status != "1") return@forEach
+ val extractorData = element.attr("data-video") ?: return@forEach
+ loadExtractor(extractorData, iframe.url, subtitleCallback, callback)
+ }
+ }, {
+ val iv = "9262859232435825"
+ val secretKey = "93422192433952489752342908585752"
+ val secretDecryptKey = "93422192433952489752342908585752"
+ extractVidstream(
+ iframe.url,
+ this.name,
+ callback,
+ iv,
+ secretKey,
+ secretDecryptKey,
+ isUsingAdaptiveKeys = false,
+ isUsingAdaptiveData = true,
+ iframeDocument = iframeDoc
+ )
+ })
+ return true
+ }
+}
diff --git a/DramaSeeProvider/src/main/kotlin/com/lagradost/DramaSeeProviderPlugin.kt b/DramaSeeProvider/src/main/kotlin/com/lagradost/DramaSeeProviderPlugin.kt
new file mode 100644
index 0000000..ea2b88a
--- /dev/null
+++ b/DramaSeeProvider/src/main/kotlin/com/lagradost/DramaSeeProviderPlugin.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 DramaSeeProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(DramaSeeProvider())
+ }
+}
\ No newline at end of file
diff --git a/DramaidProvider/build.gradle.kts b/DramaidProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/DramaidProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/DramaidProvider/src/main/AndroidManifest.xml b/DramaidProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/DramaidProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/DramaidProvider/src/main/kotlin/com/lagradost/DramaidProvider.kt b/DramaidProvider/src/main/kotlin/com/lagradost/DramaidProvider.kt
new file mode 100644
index 0000000..318a5ca
--- /dev/null
+++ b/DramaidProvider/src/main/kotlin/com/lagradost/DramaidProvider.kt
@@ -0,0 +1,213 @@
+package com.lagradost
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.getQualityFromName
+import com.lagradost.cloudstream3.utils.loadExtractor
+import org.jsoup.Jsoup
+import org.jsoup.nodes.Element
+
+class DramaidProvider : MainAPI() {
+ override var mainUrl = "https://185.224.83.103"
+ override var name = "DramaId"
+ override val hasQuickSearch = false
+ override val hasMainPage = true
+ override var lang = "id"
+ override val hasDownloadSupport = true
+ override val hasChromecastSupport = false
+ override val supportedTypes = setOf(TvType.AsianDrama)
+
+ companion object {
+ fun getStatus(t: String): ShowStatus {
+ return when (t) {
+ "Completed" -> ShowStatus.Completed
+ "Ongoing" -> ShowStatus.Ongoing
+ else -> ShowStatus.Completed
+ }
+ }
+ }
+
+ override val mainPage = mainPageOf(
+ "&status=&type=&order=update" to "Drama Terbaru",
+ "&order=latest" to "Baru Ditambahkan",
+ "&status=&type=&order=popular" to "Drama Popular",
+ )
+
+ override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
+ val document = app.get("$mainUrl/series/?page=$page${request.data}").document
+ val home = document.select("article[itemscope=itemscope]").mapNotNull {
+ it.toSearchResult()
+ }
+ return newHomePageResponse(request.name, home)
+ }
+
+ private fun getProperDramaLink(uri: String): String {
+ return if (uri.contains("/series/")) {
+ uri
+ } else {
+ "$mainUrl/series/" + Regex("$mainUrl/(.+)-ep.+").find(uri)?.groupValues?.get(1)
+ .toString()
+ }
+ }
+
+ private fun Element.toSearchResult(): SearchResponse? {
+ val href = getProperDramaLink(this.selectFirst("a.tip")!!.attr("href"))
+ val title = this.selectFirst("h2[itemprop=headline]")?.text()?.trim() ?: return null
+ val posterUrl = fixUrlNull(this.selectFirst(".limit > noscript > img")?.attr("src"))
+
+ return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
+ this.posterUrl = posterUrl
+ }
+ }
+
+ override suspend fun search(query: String): List {
+ val link = "$mainUrl/?s=$query"
+ val document = app.get(link).document
+
+ return document.select("article[itemscope=itemscope]").map {
+ val title = it.selectFirst("h2[itemprop=headline]")!!.text().trim()
+ val poster = it.selectFirst(".limit > noscript > img")!!.attr("src")
+ val href = it.selectFirst("a.tip")!!.attr("href")
+
+ newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
+ this.posterUrl = poster
+ }
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse {
+ val document = app.get(url).document
+
+ val title = document.selectFirst("h1.entry-title")!!.text().trim()
+ val poster = document.select(".thumb > noscript > img").attr("src")
+ val tags = document.select(".genxed > a").map { it.text() }
+
+ val year = Regex("\\d, ([0-9]*)").find(
+ document.selectFirst(".info-content > .spe > span > time")!!.text().trim()
+ )?.groupValues?.get(1).toString().toIntOrNull()
+ val status = getStatus(
+ document.select(".info-content > .spe > span:nth-child(1)")
+ .text().trim().replace("Status: ", "")
+ )
+ val description = document.select(".entry-content > p").text().trim()
+
+ val episodes = document.select(".eplister > ul > li").map {
+ val name = it.selectFirst("a > .epl-title")!!.text().trim()
+ val link = it.select("a").attr("href")
+ val epNum = it.selectFirst("a > .epl-num")!!.text().trim().toIntOrNull()
+ newEpisode(link) {
+ this.name = name
+ this.episode = epNum
+ }
+ }.reversed()
+
+ val recommendations =
+ document.select(".listupd > article[itemscope=itemscope]").map { rec ->
+ val epTitle = rec.selectFirst("h2[itemprop=headline]")!!.text().trim()
+ val epPoster = rec.selectFirst(".limit > noscript > img")!!.attr("src")
+ val epHref = fixUrl(rec.selectFirst("a.tip")!!.attr("href"))
+
+ newTvSeriesSearchResponse(epTitle, epHref, TvType.AsianDrama) {
+ this.posterUrl = epPoster
+ }
+ }
+
+ if (episodes.size == 1) {
+ return newMovieLoadResponse(title, url, TvType.Movie, episodes[0].data) {
+ posterUrl = poster
+ this.year = year
+ plot = description
+ this.tags = tags
+ this.recommendations = recommendations
+ }
+ } else {
+ return newTvSeriesLoadResponse(title, url, TvType.AsianDrama, episodes = episodes) {
+ posterUrl = poster
+ this.year = year
+ showStatus = status
+ plot = description
+ this.tags = tags
+ this.recommendations = recommendations
+ }
+ }
+
+ }
+
+ private data class Sources(
+ @JsonProperty("file") val file: String,
+ @JsonProperty("label") val label: String,
+ @JsonProperty("type") val type: String,
+ @JsonProperty("default") val default: Boolean?
+ )
+
+ private data class Tracks(
+ @JsonProperty("file") val file: String,
+ @JsonProperty("label") val label: String,
+ @JsonProperty("kind") val type: String,
+ @JsonProperty("default") val default: Boolean?
+ )
+
+ private suspend fun invokeDriveSource(
+ url: String,
+ name: String,
+ subCallback: (SubtitleFile) -> Unit,
+ sourceCallback: (ExtractorLink) -> Unit
+ ) {
+ val server = app.get(url).document.selectFirst(".picasa")?.nextElementSibling()?.data()
+
+ val source = "[${server!!.substringAfter("sources: [").substringBefore("],")}]".trimIndent()
+ val trackers = server.substringAfter("tracks:[").substringBefore("],")
+ .replace("//language", "")
+ .replace("file", "\"file\"")
+ .replace("label", "\"label\"")
+ .replace("kind", "\"kind\"").trimIndent()
+
+ tryParseJson>(source)?.map {
+ sourceCallback(
+ ExtractorLink(
+ name,
+ "Drive",
+ fixUrl(it.file),
+ referer = "https://motonews.club/",
+ quality = getQualityFromName(it.label)
+ )
+ )
+ }
+
+ tryParseJson(trackers)?.let {
+ subCallback.invoke(
+ SubtitleFile(
+ if (it.label.contains("Indonesia")) "${it.label}n" else it.label,
+ it.file
+ )
+ )
+ }
+
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ val document = app.get(data).document
+ val sources = document.select(".mobius > .mirror > option").mapNotNull {
+ fixUrl(Jsoup.parse(base64Decode(it.attr("value"))).select("iframe").attr("src"))
+ }
+
+ sources.map {
+ it.replace("https://ndrama.xyz", "https://www.fembed.com")
+ }.apmap {
+ when {
+ it.contains("motonews.club") -> invokeDriveSource(it, this.name, subtitleCallback, callback)
+ else -> loadExtractor(it, data, subtitleCallback, callback)
+ }
+ }
+
+ return true
+ }
+
+}
diff --git a/DramaidProvider/src/main/kotlin/com/lagradost/DramaidProviderPlugin.kt b/DramaidProvider/src/main/kotlin/com/lagradost/DramaidProviderPlugin.kt
new file mode 100644
index 0000000..4ee73cb
--- /dev/null
+++ b/DramaidProvider/src/main/kotlin/com/lagradost/DramaidProviderPlugin.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 DramaidProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(DramaidProvider())
+ }
+}
\ No newline at end of file
diff --git a/DubokuProvider/build.gradle.kts b/DubokuProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/DubokuProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/DubokuProvider/src/main/AndroidManifest.xml b/DubokuProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/DubokuProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/DubokuProvider/src/main/kotlin/com/lagradost/DubokuProvider.kt b/DubokuProvider/src/main/kotlin/com/lagradost/DubokuProvider.kt
new file mode 100644
index 0000000..a71d781
--- /dev/null
+++ b/DubokuProvider/src/main/kotlin/com/lagradost/DubokuProvider.kt
@@ -0,0 +1,133 @@
+package com.lagradost
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
+import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.M3u8Helper
+import org.jsoup.nodes.Element
+
+class DubokuProvider : MainAPI() {
+ override var mainUrl = "https://www.duboku.tv"
+ override var name = "Duboku"
+ override val hasMainPage = true
+ override var lang = "zh"
+ override val hasDownloadSupport = true
+ override val supportedTypes = setOf(
+ TvType.Movie,
+ TvType.TvSeries,
+ TvType.AsianDrama,
+ )
+
+ override val mainPage = mainPageOf(
+ "$mainUrl/vodshow/2--time------" to "连续剧 时间",
+ "$mainUrl/vodshow/2--hits------" to "连续剧 人气",
+ "$mainUrl/vodshow/13--time------" to "陆剧 时间",
+ "$mainUrl/vodshow/13--hits------" to "陆剧 人气",
+ "$mainUrl/vodshow/15--time------" to "日韩剧 时间",
+ "$mainUrl/vodshow/15--hits------" to "日韩剧 人气",
+ "$mainUrl/vodshow/21--time------" to "短剧 时间",
+ "$mainUrl/vodshow/21--hits------" to "短剧 人气",
+ "$mainUrl/vodshow/16--time------" to "英美剧 时间",
+ "$mainUrl/vodshow/16--hits------" to "英美剧 人气",
+ "$mainUrl/vodshow/14--time------" to "台泰剧 时间",
+ "$mainUrl/vodshow/14--hits------" to "台泰剧 人气",
+ "$mainUrl/vodshow/20--time------" to "港剧 时间",
+ "$mainUrl/vodshow/20--hits------" to "港剧 人气",
+ )
+
+ override suspend fun getMainPage(
+ page: Int,
+ request: MainPageRequest
+ ): HomePageResponse {
+ val document = app.get("${request.data}$page---.html").document
+ val home = document.select("ul.myui-vodlist.clearfix li").mapNotNull {
+ it.toSearchResult()
+ }
+ return newHomePageResponse(request.name, home)
+ }
+
+ private fun Element.toSearchResult(): SearchResponse? {
+ val title = this.selectFirst("h4.title a")?.text()?.trim() ?: return null
+ val href = fixUrl(this.selectFirst("a")?.attr("href").toString())
+ val posterUrl = fixUrlNull(this.selectFirst("a")?.attr("data-original"))
+ val episode = this.selectFirst("span.pic-text.text-right")?.text()?.filter { it.isDigit() }
+ ?.toIntOrNull()
+
+ return newAnimeSearchResponse(title, href, TvType.Movie) {
+ this.posterUrl = posterUrl
+ addSub(episode)
+ }
+ }
+
+ override suspend fun search(query: String): List {
+ val document = app.get("$mainUrl/vodsearch/-------------.html?wd=$query&submit=").document
+
+ return document.select("ul#searchList li").mapNotNull {
+ it.toSearchResult()
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse? {
+ val document = app.get(url).document
+
+ val title = document.selectFirst("h1.title")?.text()?.trim() ?: return null
+ val tvType = if (document.select("ul.myui-content__list li").size == 1
+ ) TvType.Movie else TvType.TvSeries
+ val actors = document.select("p.data")[2].select("a").map { it.text() }
+
+ val episodes = document.select("ul.myui-content__list li").map {
+ val href = fixUrl(it.select("a").attr("href"))
+ val name = it.select("a").text().trim()
+ Episode(
+ data = href,
+ name = name,
+ )
+ }
+ return newTvSeriesLoadResponse(title, url, tvType, episodes) {
+ this.posterUrl = fixUrlNull(
+ document.selectFirst("a.myui-vodlist__thumb.picture img")?.attr("data-original")
+ )
+ this.year =
+ document.select("p.data")[0].select("a").last()?.text()?.trim()?.toIntOrNull()
+ this.plot = document.selectFirst("span.sketch.content")?.text()?.trim()
+ this.tags = document.select("p.data")[0].select("a").map { it.text() }
+ this.rating = document.select("div#rating span.branch").text().toRatingInt()
+ addActors(actors)
+ }
+
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+
+ app.get(data).document.select("script").map { script ->
+ if (script.data().contains("var player_data={")) {
+ val dataJson =
+ script.data().substringAfter("var player_data={").substringBefore("}")
+ tryParseJson("{$dataJson}")?.let { source ->
+ M3u8Helper.generateM3u8(
+ this.name,
+ source.url ?: return@map,
+ referer = "https://w.duboku.io/",
+ headers = mapOf("Origin" to "https://w.duboku.io")
+ ).forEach(callback)
+ }
+ }
+ }
+
+
+ return true
+ }
+
+ data class Sources(
+ @JsonProperty("url") val url: String?,
+ )
+
+
+}
\ No newline at end of file
diff --git a/DubokuProvider/src/main/kotlin/com/lagradost/DubokuProviderPlugin.kt b/DubokuProvider/src/main/kotlin/com/lagradost/DubokuProviderPlugin.kt
new file mode 100644
index 0000000..4c77005
--- /dev/null
+++ b/DubokuProvider/src/main/kotlin/com/lagradost/DubokuProviderPlugin.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 DubokuProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(DubokuProvider())
+ }
+}
\ No newline at end of file
diff --git a/EgyBestProvider/build.gradle.kts b/EgyBestProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/EgyBestProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/EgyBestProvider/src/main/AndroidManifest.xml b/EgyBestProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/EgyBestProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/EgyBestProvider/src/main/kotlin/com/lagradost/EgyBestProvider.kt b/EgyBestProvider/src/main/kotlin/com/lagradost/EgyBestProvider.kt
new file mode 100644
index 0000000..933b0f2
--- /dev/null
+++ b/EgyBestProvider/src/main/kotlin/com/lagradost/EgyBestProvider.kt
@@ -0,0 +1,237 @@
+package com.lagradost
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.utils.AppUtils.parseJson
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
+import org.jsoup.nodes.Element
+
+class EgyBestProvider : MainAPI() {
+ override var lang = "ar"
+ override var mainUrl = "https://www.egy.best"
+ override var name = "EgyBest"
+ override val usesWebView = false
+ override val hasMainPage = true
+ override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime)
+
+ private fun String.getIntFromText(): Int? {
+ return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
+ }
+
+ private fun Element.toSearchResponse(): SearchResponse? {
+ val url = this.attr("href") ?: return null
+ val posterUrl = select("img")?.attr("src")
+ var title = select("span.title").text()
+ val year = title.getYearFromTitle()
+ val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
+ val tvType = if (isMovie) TvType.Movie else TvType.TvSeries
+ title = if (year !== null) title else title.split(" (")[0].trim()
+ val quality = select("span.ribbon span").text().replace("-", "")
+ // If you need to differentiate use the url.
+ return MovieSearchResponse(
+ title,
+ url,
+ this@EgyBestProvider.name,
+ tvType,
+ posterUrl,
+ year,
+ null,
+ quality = getQualityFromString(quality)
+ )
+ }
+
+ override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
+ // url, title
+ val doc = app.get(mainUrl).document
+ val pages = arrayListOf()
+ doc.select("#mainLoad div.mbox").apmap {
+ val name = it.select(".bdb.pda > strong").text()
+ if (it.select(".movie").first()?.attr("href")?.contains("season-(.....)|ep-(.....)".toRegex()) == true) return@apmap
+ val list = arrayListOf()
+ it.select(".movie").map { element ->
+ list.add(element.toSearchResponse()!!)
+ }
+ pages.add(HomePageList(name, list))
+ }
+ return HomePageResponse(pages)
+ }
+
+ override suspend fun search(query: String): List {
+ val q = query.replace(" ","%20")
+ val result = arrayListOf()
+ listOf("$mainUrl/explore/?q=$q").apmap { url ->
+ val d = app.get(url).document
+ d.select("div.movies a").not("a.auto.load.btn.b").mapNotNull {
+ it.toSearchResponse()?.let { it1 -> result.add(it1) }
+ }
+ }
+ return result.distinct().sortedBy { it.name }
+ }
+
+ private fun String.getYearFromTitle(): Int? {
+ return Regex("""\(\d{4}\)""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
+ }
+
+ override suspend fun load(url: String): LoadResponse {
+ val doc = app.get(url).document
+ val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
+ val posterUrl = doc.select("div.movie_img a img")?.attr("src")
+ val year = doc.select("div.movie_title h1 a")?.text()?.toIntOrNull()
+ val title = doc.select("div.movie_title h1 span").text()
+ val youtubeTrailer = doc.select("div.play")?.attr("url")
+
+ val synopsis = doc.select("div.mbox").firstOrNull {
+ it.text().contains("القصة")
+ }?.text()?.replace("القصة ", "")
+
+ val tags = doc.select("table.movieTable tbody tr").firstOrNull {
+ it.text().contains("النوع")
+ }?.select("a")?.map { it.text() }
+
+ val actors = doc.select("div.cast_list .cast_item").mapNotNull {
+ val name = it.selectFirst("div > a > img")?.attr("alt") ?: return@mapNotNull null
+ val image = it.selectFirst("div > a > img")?.attr("src") ?: return@mapNotNull null
+ val roleString = it.selectFirst("div > span")!!.text()
+ val mainActor = Actor(name, image)
+ ActorData(actor = mainActor, roleString = roleString)
+ }
+
+ return if (isMovie) {
+ val recommendations = doc.select(".movies_small .movie").mapNotNull { element ->
+ element.toSearchResponse()
+ }
+
+ newMovieLoadResponse(
+ title,
+ url,
+ TvType.Movie,
+ url
+ ) {
+ this.posterUrl = posterUrl
+ this.year = year
+ this.recommendations = recommendations
+ this.plot = synopsis
+ this.tags = tags
+ this.actors = actors
+ addTrailer(youtubeTrailer)
+ }
+ } else {
+ val episodes = ArrayList()
+ doc.select("#mainLoad > div:nth-child(2) > div.h_scroll > div a").map {
+ it.attr("href")
+ }.apmap {
+ val d = app.get(it).document
+ val season = Regex("season-(.....)").find(it)?.groupValues?.getOrNull(1)?.getIntFromText()
+ if(d.select("tr.published").isNotEmpty()) {
+ d.select("tr.published").map { element ->
+ val ep = Regex("ep-(.....)").find(element.select(".ep_title a").attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText()
+ episodes.add(
+ Episode(
+ element.select(".ep_title a").attr("href"),
+ name = element.select("td.ep_title").html().replace(".*|".toRegex(), ""),
+ season,
+ ep,
+ rating = element.select("td.tam:not(.date, .ep_len)").text().getIntFromText()
+ )
+ )
+ }
+ } else {
+ d.select("#mainLoad > div:nth-child(3) > div.movies_small a").map { eit ->
+ val ep = Regex("ep-(.....)").find(eit.attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText()
+ episodes.add(
+ Episode(
+ eit.attr("href"),
+ eit.select("span.title").text(),
+ season,
+ ep,
+ )
+ )
+ }
+ }
+ }
+ newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
+ this.posterUrl = posterUrl
+ this.tags = tags
+ this.year = year
+ this.plot = synopsis
+ this.actors = actors
+ addTrailer(youtubeTrailer)
+ }
+ }
+ }
+ data class Sources (
+ @JsonProperty("quality") val quality: Int?,
+ @JsonProperty("link") val link: String
+ )
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ /*val baseURL = data.split("/")[0] + "//" + data.split("/")[2]
+ val episodeSoup = app.get(data).document
+
+ val vidstreamURL = fixUrlNull(episodeSoup.selectFirst("iframe.auto-size")?.attr("src") ) ?: throw ErrorLoadingException("No iframe")
+ val videoSoup = app.get(vidstreamURL).document
+ fixUrlNull( videoSoup.select("source").firstOrNull { it.hasAttr("src") }?.attr("src"))?.let {
+ callback.invoke(ExtractorLink(this.name,this.name,it,"",Qualities.Unknown.value,it.contains(".m3u8")))
+ } ?: run {
+ var jsCode = videoSoup.select("script")[1].data()
+
+ val verificationToken = Regex("{'[0-9a-zA-Z_]*':'ok'}").findAll(jsCode)[0][2:-7]
+ val encodedAdLinkVar = Regex("([0-9a-zA-Z_]{2,12}\[Math").findAll(jsCode)[0][1:-5]
+ val encodingArraysRegEx = Regex(",[0-9a-zA-Z_]{2,12}=\[\]").findAll(jsCode)
+ val firstEncodingArray = encodingArraysRegEx[1][1:-3]
+ val secondEncodingArray = encodingArraysRegEx[2][1:-3]
+
+ jsCode = Regex("^ a").mapNotNull {
+ it.toEpisode(showId, key, keyValue, mapOf(cookieKey to cookieValue))
+ }
+ isSeries to episodes
+ } else {
+ false to emptyList()
+ }
+ } else {
+ false to emptyList()
+ }
+
+ return if (isSeries || episodes.size > 1) newTvSeriesLoadResponse(
+ title,
+ url,
+ TvType.TvSeries,
+ episodes
+ ) {
+ this.comingSoon = playUrl.isEmpty()
+ } else
+ newMovieLoadResponse(
+ title,
+ url,
+ TvType.Movie,
+ episodes.firstOrNull()?.data ?: ""
+ ) {
+ this.posterUrl = posterUrl
+ this.year = year
+ this.tags = tags
+
+ if (duration != 0)
+ this.duration = duration
+
+ this.recommendations = recommendations
+ this.comingSoon = playUrl.isEmpty() || episodes.isEmpty()
+ }
+ }
+
+
+ data class File(
+ val file: String? = null,
+ val type: String? = null,
+ val label: String? = null
+ )
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ val parsed = parseJson(data)
+ val url = "$mainUrl/movie/load-stream/${parsed.showId}/${parsed.episodeId}"
+ val response = app.post(
+ url,
+ referer = parsed.episodeUrl,
+ headers = mapOf(
+ "X-Requested-With" to "XMLHttpRequest",
+ ),
+ data = mapOf(parsed.key to parsed.keyValue),
+ cookies = parsed.cookies + cookies,
+ ).text
+
+ val urlRegex = Regex("""file['"].*?['"]([^'"]*)""")
+ val link = urlRegex.find(response)?.groupValues!![1]
+
+// files.forEach { (isVip, list) ->
+// list.forEach file@{ file ->
+// if (file.file == null) return@file
+ callback.invoke(
+ ExtractorLink(
+ this.name,
+ this.name,
+ link.replace("\\", ""),
+ this.mainUrl,
+// file.label?.getIntFromText() ?:
+ Qualities.Unknown.value,
+ true
+// file.type?.contains("hls", ignoreCase = true) == true,
+ )
+ )
+// }
+// }
+
+ return true // files.sumOf { it.second.size } > 0
+ }
+}
diff --git a/XcineProvider/src/main/kotlin/com/lagradost/XcineProviderPlugin.kt b/XcineProvider/src/main/kotlin/com/lagradost/XcineProviderPlugin.kt
new file mode 100644
index 0000000..c543d4a
--- /dev/null
+++ b/XcineProvider/src/main/kotlin/com/lagradost/XcineProviderPlugin.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 XcineProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(XcineProvider())
+ }
+}
\ No newline at end of file
diff --git a/YomoviesProvider/build.gradle.kts b/YomoviesProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/YomoviesProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // 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
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/YomoviesProvider/src/main/AndroidManifest.xml b/YomoviesProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/YomoviesProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/YomoviesProvider/src/main/kotlin/com/lagradost/YomoviesProvider.kt b/YomoviesProvider/src/main/kotlin/com/lagradost/YomoviesProvider.kt
new file mode 100644
index 0000000..ac6ad12
--- /dev/null
+++ b/YomoviesProvider/src/main/kotlin/com/lagradost/YomoviesProvider.kt
@@ -0,0 +1,161 @@
+package com.lagradost
+
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
+import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
+import com.lagradost.cloudstream3.mvvm.safeApiCall
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.loadExtractor
+import org.jsoup.nodes.Element
+
+class YomoviesProvider : MainAPI() {
+ override var mainUrl = "https://yomovies.skin"
+ override var name = "Yomovies"
+ override val hasMainPage = true
+ override var lang = "hi"
+ override val hasDownloadSupport = true
+ override val supportedTypes = setOf(
+ TvType.Movie,
+ TvType.TvSeries,
+ )
+
+ override val mainPage = mainPageOf(
+ "$mainUrl/most-favorites/page/" to "Most Viewed",
+ "$mainUrl/genre/web-series/page/" to "Web Series Movies",
+ "$mainUrl/genre/dual-audio/page/" to "Dual Audio Movies",
+ "$mainUrl/genre/bollywood/page/" to "Bollywood Movies",
+ "$mainUrl/genre/tv-shows/page/" to "TV Shows Movies",
+ "$mainUrl/genre/hollywood/page/" to "Hollywood Movies",
+ "$mainUrl/series/page/" to "All TV Series",
+ )
+
+ override suspend fun getMainPage(
+ page: Int,
+ request: MainPageRequest
+ ): HomePageResponse {
+ val document = app.get(request.data + page).document
+ val home = document.select("div.ml-item").mapNotNull {
+ it.toSearchResult()
+ }
+ return newHomePageResponse(request.name, home)
+ }
+
+ private fun Element.toSearchResult(): SearchResponse? {
+ val title = this.selectFirst("h2")?.text()?.trim() ?: return null
+ val href = fixUrl(this.selectFirst("a")?.attr("href").toString())
+ val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("data-original"))
+
+ return newMovieSearchResponse(title, href, TvType.Movie) {
+ this.posterUrl = posterUrl
+ }
+ }
+
+ override suspend fun search(query: String): List {
+ val document = app.get("$mainUrl/?s=$query").document
+
+ return document.select("div.ml-item").mapNotNull {
+ it.toSearchResult()
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse? {
+ val document = app.get(url).document
+
+ val title = document.selectFirst("div.mvic-desc h3")?.text()?.trim() ?: return null
+ val poster = fixUrlNull(document.selectFirst("div.thumb.mvic-thumb img")?.attr("src"))
+ val tags = document.select("div.mvici-left p:nth-child(1) a").map { it.text() }
+ val year = document.select("div.mvici-right p:nth-child(3) a").text().trim()
+ .toIntOrNull()
+ val tvType = if (document.selectFirst("div.les-content")
+ ?.select("a")?.size!! > 1 || document.selectFirst("ul.idTabs li strong")?.text()
+ ?.contains(Regex("(?i)(EP\\s?[0-9]+)|(episode\\s?[0-9]+)")) == true
+ ) TvType.TvSeries else TvType.Movie
+ val description = document.selectFirst("p.f-desc")?.text()?.trim()
+ val trailer = fixUrlNull(document.select("iframe#iframe-trailer").attr("src"))
+ val rating = document.select("div.mvici-right > div.imdb_r span").text().toRatingInt()
+ val actors = document.select("div.mvici-left p:nth-child(3) a").map { it.text() }
+ val recommendations = document.select("div.ml-item").mapNotNull {
+ it.toSearchResult()
+ }
+
+ return if (tvType == TvType.TvSeries) {
+ val episodes = if (document.selectFirst("div.les-title strong")?.text().toString()
+ .contains(Regex("(?i)EP\\s?[0-9]+|Episode\\s?[0-9]+"))
+ ) {
+ document.select("ul.idTabs li").map {
+ val id = it.select("a").attr("href")
+ Episode(
+ data = fixUrl(document.select("div$id iframe").attr("src")),
+ name = it.select("strong").text(),
+ )
+ }
+ } else {
+ document.select("div.les-content a").map {
+ Episode(
+ data = it.attr("href"),
+ name = it.text().trim(),
+ )
+ }
+ }
+
+ newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
+ this.posterUrl = poster
+ this.year = year
+ this.plot = description
+ this.tags = tags
+ this.rating = rating
+ addActors(actors)
+ this.recommendations = recommendations
+ addTrailer(trailer)
+ }
+ } else {
+ newMovieLoadResponse(title, url, TvType.Movie, url) {
+ this.posterUrl = poster
+ this.year = year
+ this.plot = description
+ this.tags = tags
+ this.rating = rating
+ addActors(actors)
+ this.recommendations = recommendations
+ addTrailer(trailer)
+ }
+ }
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+
+ if (data.startsWith(mainUrl)) {
+ app.get(data).document.select("div.movieplay iframe").map { fixUrl(it.attr("src")) }
+ .apmap { source ->
+ safeApiCall {
+ when {
+ source.startsWith("https://membed.net") -> app.get(
+ source,
+ referer = "$mainUrl/"
+ ).document.select("ul.list-server-items li")
+ .apmap {
+ loadExtractor(
+ it.attr("data-video").substringBefore("=https://msubload"),
+ "$mainUrl/",
+ subtitleCallback,
+ callback
+ )
+ }
+ else -> loadExtractor(source, "$mainUrl/", subtitleCallback, callback)
+ }
+ }
+ }
+ } else {
+ loadExtractor(data, "$mainUrl/", subtitleCallback, callback)
+ }
+
+ return true
+ }
+
+
+}
diff --git a/YomoviesProvider/src/main/kotlin/com/lagradost/YomoviesProviderPlugin.kt b/YomoviesProvider/src/main/kotlin/com/lagradost/YomoviesProviderPlugin.kt
new file mode 100644
index 0000000..f797a8c
--- /dev/null
+++ b/YomoviesProvider/src/main/kotlin/com/lagradost/YomoviesProviderPlugin.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 YomoviesProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(YomoviesProvider())
+ }
+}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 6e93698..393a90a 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,4 +1,4 @@
-import com.lagradost.cloudstream3.gradle.CloudstreamExtension
+import com.lagradost.cloudstream3.gradle.CloudstreamExtension
import com.android.build.gradle.BaseExtension
buildscript {
@@ -25,9 +25,11 @@ allprojects {
}
}
-fun Project.cloudstream(configuration: CloudstreamExtension.() -> Unit) = extensions.getByName("cloudstream").configuration()
+fun Project.cloudstream(configuration: CloudstreamExtension.() -> Unit) =
+ extensions.getByName("cloudstream").configuration()
-fun Project.android(configuration: BaseExtension.() -> Unit) = extensions.getByName("android").configuration()
+fun Project.android(configuration: BaseExtension.() -> Unit) =
+ extensions.getByName("android").configuration()
subprojects {
apply(plugin = "com.android.library")
@@ -76,7 +78,11 @@ subprojects {
// https://github.com/recloudstream/cloudstream/blob/master/app/build.gradle
implementation(kotlin("stdlib")) // adds standard kotlin features, like listOf, mapOf etc
implementation("com.github.Blatzar:NiceHttp:0.3.2") // http library
+ implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.1")
implementation("org.jsoup:jsoup:1.13.1") // html parser
+
+ //run JS
+ implementation("org.mozilla:rhino:1.7.14")
}
}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index f6b961f..7454180 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index d2f276a..69a9715 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Sun Feb 20 16:26:11 CET 2022
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
\ No newline at end of file
diff --git a/gradlew b/gradlew
index 6e5d9ef..744e882 100755
--- a/gradlew
+++ b/gradlew
@@ -1,5 +1,21 @@
#!/usr/bin/env sh
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
##############################################################################
##
## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@@ -56,7 +72,7 @@ case "`uname`" in
Darwin* )
darwin=true
;;
- MINGW* )
+ MSYS* | MINGW* )
msys=true
;;
NONSTOP* )
@@ -66,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -109,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -138,19 +156,19 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
- i=$((i+1))
+ i=`expr $i + 1`
done
case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -159,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
-APP_ARGS=$(save "$@")
+APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
-fi
-
-exec "$JAVACMD" "$@"
\ No newline at end of file
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index dee787c..107acd3 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,3 +1,19 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,28 +64,14 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
@@ -81,4 +86,4 @@ exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
-:omega
\ No newline at end of file
+:omega
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 43f715c..e7988ca 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -5,5 +5,73 @@ rootProject.name = "CloudstreamPlugins"
// Plugins are included like this
include(
- "ExampleProvider"
+ "XcineProvider",
+ "StreamingcommunityProvider",
+ "FilmanProvider",
+ "VMoveeProvider",
+ "AsiaFlixProvider",
+ "DoramasYTProvider",
+// "SflixProProvider",
+// "PinoyMoviePediaProvider",
+ "SeriesflixProvider",
+ "TrailersTwoProvider",
+// "PinoyMoviesEsProvider",
+ "KisskhProvider",
+// "DramaSeeProvider",
+// "VidstreamProviderTemplate",
+ "RebahinProvider",
+ "AllMoviesForYouProvider",
+ "UakinoProvider",
+ "DramaidProvider",
+ "FaselHDProvider",
+ "MeloMovieProvider",
+ "PelisplusProvider",
+// "AsianLoadProvider",
+ "YomoviesProvider",
+ "AkwamProvider",
+// "VidEmbedProvider",
+ "IdlixProvider",
+ "NginxProvider",
+ "SoaptwoDayProvider",
+ "PinoyHDXyzProvider",
+ "AltadefinizioneProvider",
+ "PelisflixProvider",
+// "SflixProvider",
+ "ElifilmsProvider",
+// "VidSrcProvider",
+ "EgyBestProvider",
+// "WatchAsianProvider",
+ "VfSerieProvider",
+ "LayarKacaProvider",
+ "EntrepeliculasyseriesProvider",
+ "TantiFilmProvider",
+// "TwoEmbedProvider",
+ "SuperStream",
+ "FilmpertuttiProvider",
+ "FrenchStreamProvider",
+// "KdramaHoodProvider",
+ "MyCimaProvider",
+ "IlGenioDelloStreamingProvider",
+ "EstrenosDoramasProvider",
+// "HDTodayProvider",
+// "DopeboxProvider",
+ "DubokuProvider",
+ "HDMProvider",
+ "PhimmoichillProvider",
+ "PelisplusProviderTemplate",
+ "OlgplyProvider",
+// "SolarmovieProvider",
+ "PeliSmartProvider",
+ "VfFilmProvider",
+ "IHaveNoTvProvider",
+ "CuevanaProvider",
+ "CinecalidadProvider",
+ "HDMovie5",
+ "HDrezkaProvider",
+ "PelisplusHDProvider",
+ "MultiplexProvider",
+// "OpenVidsProvider",
+ //"BflixProvider",
+// "FmoviesToProvider",
+ "TheFlixToProvider",
)