diff --git a/ExampleProvider/build.gradle.kts b/ExampleProvider/build.gradle.kts deleted file mode 100644 index 58645fe..0000000 --- a/ExampleProvider/build.gradle.kts +++ /dev/null @@ -1,24 +0,0 @@ -// 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 - - // List of video source types. Users are able to filter for extensions in a given category. - // You can find a list of avaliable types here: - // https://recloudstream.github.io/cloudstream/html/app/com.lagradost.cloudstream3/-tv-type/index.html - tvTypes = listOf("Others") -} diff --git a/ExampleProvider/src/main/kotlin/com/example/ExampleProvider.kt b/ExampleProvider/src/main/kotlin/com/example/ExampleProvider.kt deleted file mode 100644 index e44a21b..0000000 --- a/ExampleProvider/src/main/kotlin/com/example/ExampleProvider.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.example - -import com.lagradost.cloudstream3.TvType -import com.lagradost.cloudstream3.MainAPI -import com.lagradost.cloudstream3.SearchResponse - -class ExampleProvider : MainAPI() { // all providers must be an instance of MainAPI - override var mainUrl = "https://example.com/" - override var name = "Example provider" - override val supportedTypes = setOf(TvType.Movie) - - override var lang = "en" - - // enable this when your provider has a main page - override val hasMainPage = true - - // this function gets called when you search for something - override suspend fun search(query: String): List { - return listOf() - } -} \ No newline at end of file diff --git a/OnlineMoviesHinditProvider/build.gradle.kts b/OnlineMoviesHinditProvider/build.gradle.kts new file mode 100644 index 0000000..77ec5bf --- /dev/null +++ b/OnlineMoviesHinditProvider/build.gradle.kts @@ -0,0 +1,25 @@ +version = 1 + + +cloudstream { + language = "hi" + // All of these properties are optional, you can safely remove them + + // description = "Lorem Ipsum" + authors = listOf("darkdemon") + + /** + * Status int as the following: + * 0: Down + * 1: Ok + * 2: Slow + * 3: Beta only + * */ + status = 1 // will be 3 if unspecified + tvTypes = listOf( + "TvSeries", + "Movie", + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=111.90.159.132&sz=%size%" +} diff --git a/ExampleProvider/src/main/AndroidManifest.xml b/OnlineMoviesHinditProvider/src/main/AndroidManifest.xml similarity index 52% rename from ExampleProvider/src/main/AndroidManifest.xml rename to OnlineMoviesHinditProvider/src/main/AndroidManifest.xml index 1863f02..7fbfe5f 100644 --- a/ExampleProvider/src/main/AndroidManifest.xml +++ b/OnlineMoviesHinditProvider/src/main/AndroidManifest.xml @@ -1,2 +1,2 @@ - \ No newline at end of file + diff --git a/OnlineMoviesHinditProvider/src/main/kotlin/com/darkdemon/OnlineMoviesHindiPlugin.kt b/OnlineMoviesHinditProvider/src/main/kotlin/com/darkdemon/OnlineMoviesHindiPlugin.kt new file mode 100644 index 0000000..7ca7165 --- /dev/null +++ b/OnlineMoviesHinditProvider/src/main/kotlin/com/darkdemon/OnlineMoviesHindiPlugin.kt @@ -0,0 +1,13 @@ +package com.darkdemon + +import com.lagradost.cloudstream3.plugins.CloudstreamPlugin +import com.lagradost.cloudstream3.plugins.Plugin +import android.content.Context + +@CloudstreamPlugin +class OnlineMoviesHindiPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(OnlineMoviesHindiProvider()) + } +} diff --git a/OnlineMoviesHinditProvider/src/main/kotlin/com/darkdemon/OnlineMoviesHindiProvider.kt b/OnlineMoviesHinditProvider/src/main/kotlin/com/darkdemon/OnlineMoviesHindiProvider.kt new file mode 100644 index 0000000..70f92a9 --- /dev/null +++ b/OnlineMoviesHinditProvider/src/main/kotlin/com/darkdemon/OnlineMoviesHindiProvider.kt @@ -0,0 +1,140 @@ + +package com.darkdemon + +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.LoadResponse.Companion.addActors +import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer +import com.lagradost.cloudstream3.utils.* +import org.jsoup.nodes.Element + +class OnlineMoviesHindiProvider : MainAPI() { // all providers must be an instance of MainAPI + override var mainUrl = "https://111.90.159.132" + override var name = "Online Movies Hindi" + 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/year/2022/page/" to "Latest Movies", + "$mainUrl/best-rating/page/" to "Popular Movies", + "$mainUrl/hollywood-movies/page/" to "Hollywood Movies", + "$mainUrl/bollywood-movies/page/" to "Bollywood Movies", + "$mainUrl/tv-show/page/" to "TV Shows" + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document + val home = document.select("article").mapNotNull { + it.toSearchResult() + } + return newHomePageResponse(request.name, home) + } + + private fun Element.toSearchResult(): SearchResponse? { + val title = this.selectFirst("p.entry-title")?.text()?.trim() ?: return null + val href = fixUrl(this.selectFirst("a")?.attr("href").toString()) + val posterUrl = fixUrlNull(this.selectFirst("article img")?.attr("src")) + + return newMovieSearchResponse(title, href, TvType.Movie) { + this.posterUrl = posterUrl + } + } + + override suspend fun search(query: String): List { + val document = app.get("$mainUrl/?s=$query&post_type%5B%5D=post&post_type%5B%5D=tv").document + + return document.select("article").mapNotNull { + it.toSearchResult() + } + } + + override suspend fun load(url: String): LoadResponse? { + val document = app.get(url).document + + val title = document.selectFirst("h2.entry-title")?.text()?.trim() ?: return null + val poster = fixUrlNull(document.selectFirst("div.gmr-movie-data img")?.attr("src")) + //val tags = document.select("div.mvici-left p:nth-child(1) a").map { it.text() } + val year = document.select("div.gmr-moviedata time").text().trim().split(" ").last() + .toIntOrNull() + val tvType = if (document.selectFirst("div.gmr-listseries a")?.text() + ?.contains(Regex("(?i)(Eps\\s?[0-9]+)|(episode\\s?[0-9]+)")) == true + ) TvType.TvSeries else TvType.Movie + val description = document.selectFirst("div.entry-content p")?.text()?.trim() + val trailer = fixUrlNull(document.select("iframe").attr("src")) + val rating = document.select("div.gmr-meta-rating > span:nth-child(3)").text().toRatingInt() + val actors = document.select("div.clearfix.content-moviedata > div:nth-child(7) a").map { it.text() } + val recommendations = document.select("article").mapNotNull { + it.toSearchResult() + } + + return if (tvType == TvType.TvSeries) { + val episodes = document.select("div.gmr-listseries a").mapNotNull { + val href = fixUrl(it.attr("href")?: return null) + val name = it.text()?.trim()?: return null + val season = name.substringAfter("S").substringBefore(' ').toInt() ?: return null + val episode = name.substringAfterLast("Eps").toInt()?: return null + Episode( + href, + name, + season, + episode + ) + } + println(episodes) + + 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 { + + val document = app.get(data).document + document.select("video source").map { res -> + callback.invoke( + ExtractorLink( + this.name, + this.name, + res.attr("src") , + referer = data, + quality = Qualities.Unknown.value, + //headers = mapOf("Range" to "bytes=0-"), + ) + ) + } + return true + } + + +} diff --git a/PrmoviesProvider/build.gradle.kts b/PrmoviesProvider/build.gradle.kts new file mode 100644 index 0000000..f0659d0 --- /dev/null +++ b/PrmoviesProvider/build.gradle.kts @@ -0,0 +1,25 @@ +version = 1 + + +cloudstream { + language = "hi" + // All of these properties are optional, you can safely remove them + + // description = "Lorem Ipsum" + authors = listOf("darkdemon") + + /** + * Status int as the following: + * 0: Down + * 1: Ok + * 2: Slow + * 3: Beta only + * */ + status = 1 // will be 3 if unspecified + tvTypes = listOf( + "TvSeries", + "Movie", + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=prmovies.homes&sz=%size%" +} diff --git a/PrmoviesProvider/src/main/AndroidManifest.xml b/PrmoviesProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7fbfe5f --- /dev/null +++ b/PrmoviesProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/ExampleProvider/src/main/kotlin/com/example/ExamplePlugin.kt b/PrmoviesProvider/src/main/kotlin/com/darkdemon/PrmoviesPlugin.kt similarity index 75% rename from ExampleProvider/src/main/kotlin/com/example/ExamplePlugin.kt rename to PrmoviesProvider/src/main/kotlin/com/darkdemon/PrmoviesPlugin.kt index 8ddce48..ce4b3e7 100644 --- a/ExampleProvider/src/main/kotlin/com/example/ExamplePlugin.kt +++ b/PrmoviesProvider/src/main/kotlin/com/darkdemon/PrmoviesPlugin.kt @@ -1,13 +1,13 @@ -package com.example +package com.darkdemon import com.lagradost.cloudstream3.plugins.CloudstreamPlugin import com.lagradost.cloudstream3.plugins.Plugin import android.content.Context @CloudstreamPlugin -class TestPlugin: Plugin() { +class PrmoviesPlugin: Plugin() { override fun load(context: Context) { // All providers should be added in this manner. Please don't edit the providers list directly. - registerMainAPI(ExampleProvider()) + registerMainAPI(PrmoviesProvider()) } -} \ No newline at end of file +} diff --git a/PrmoviesProvider/src/main/kotlin/com/darkdemon/PrmoviesProvider.kt b/PrmoviesProvider/src/main/kotlin/com/darkdemon/PrmoviesProvider.kt new file mode 100644 index 0000000..95682e0 --- /dev/null +++ b/PrmoviesProvider/src/main/kotlin/com/darkdemon/PrmoviesProvider.kt @@ -0,0 +1,170 @@ +// https://github.com/hexated/cloudstream-extensions-hexated/blob/master/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProvider.kt + +package com.darkdemon + +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 PrmoviesProvider : MainAPI() { // all providers must be an instance of MainAPI + override var mainUrl = "https://prmovies.homes" + override var name = "Prmovies" + 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/director/netflix/page/" to "Netflix", + "$mainUrl/director/amazon-prime/page/" to "Amazon Prime", + "$mainUrl/director/altbalaji/page/" to "Alt Balaji", + "$mainUrl/director/zee5/page/" to "Zee5", + "$mainUrl/director/voot-originals/page/" to "Voot Originals", + "$mainUrl/director/sonyliv-original/page/" to "Sonyliv Originals", + "$mainUrl/director/hotstar/page/" to "Hotstar", + "$mainUrl/director/viu-originals/page/" to "Viu Originals", + "$mainUrl/director/discovery/page/" to "Discovery" + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = if (page == 1) { + app.get(request.data.removeSuffix("page/")).document + } else { + 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().replace("Server Ep", "Episode") + ) + } + } else { + document.select("div.les-content a").map { + Episode( + data = it.attr("href"), + name = it.text().replace("Server Ep", "Episode").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/build.gradle.kts b/build.gradle.kts index b19ff67..2cd20b3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,7 +37,7 @@ subprojects { cloudstream { // when running through github workflow, GITHUB_REPOSITORY should contain current repository name // you can modify it to use other git hosting services, like gitlab - setRepo(System.getenv("GITHUB_REPOSITORY") ?: "https://github.com/user/repo") + setRepo(System.getenv("GITHUB_REPOSITORY") ?: "https://github.com/daarkdemon/cs-darkdemon-extensions") } android {