diff --git a/OnlineMoviesHinditProvider/src/main/kotlin/com/darkdemon/OnlineMoviesHindiProvider.kt b/OnlineMoviesHinditProvider/src/main/kotlin/com/darkdemon/OnlineMoviesHindiProvider.kt index 70f92a9..c8d601c 100644 --- a/OnlineMoviesHinditProvider/src/main/kotlin/com/darkdemon/OnlineMoviesHindiProvider.kt +++ b/OnlineMoviesHinditProvider/src/main/kotlin/com/darkdemon/OnlineMoviesHindiProvider.kt @@ -60,7 +60,6 @@ class OnlineMoviesHindiProvider : MainAPI() { // all providers must be an instan 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() @@ -87,13 +86,11 @@ class OnlineMoviesHindiProvider : MainAPI() { // all providers must be an instan 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 diff --git a/StreamBlastersProvider/build.gradle.kts b/StreamBlastersProvider/build.gradle.kts new file mode 100644 index 0000000..77ec5bf --- /dev/null +++ b/StreamBlastersProvider/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/StreamBlastersProvider/src/main/AndroidManifest.xml b/StreamBlastersProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7fbfe5f --- /dev/null +++ b/StreamBlastersProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/StreamBlastersProvider/src/main/kotlin/com/darkdemon/StreamBlastersPlugin.kt b/StreamBlastersProvider/src/main/kotlin/com/darkdemon/StreamBlastersPlugin.kt new file mode 100644 index 0000000..7cd2882 --- /dev/null +++ b/StreamBlastersProvider/src/main/kotlin/com/darkdemon/StreamBlastersPlugin.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 StreamBlastersPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(StreamBlastersProvider()) + } +} diff --git a/StreamBlastersProvider/src/main/kotlin/com/darkdemon/StreamBlastersProvider.kt b/StreamBlastersProvider/src/main/kotlin/com/darkdemon/StreamBlastersProvider.kt new file mode 100644 index 0000000..8a0d2ca --- /dev/null +++ b/StreamBlastersProvider/src/main/kotlin/com/darkdemon/StreamBlastersProvider.kt @@ -0,0 +1,164 @@ + +package com.darkdemon + +import com.fasterxml.jackson.annotation.JsonProperty +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.* +import org.jsoup.nodes.Element + +class StreamBlastersProvider : MainAPI() { // all providers must be an instance of MainAPI + override var mainUrl = "https://streamblasters.lol" + override var name = "StreamBlasters" + 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/genre/english/page/" to "English", + "$mainUrl/genre/hindi/page/" to "Hindi", + "$mainUrl/genre/kannada/page/" to "Kannada", + "$mainUrl/genre/malayalam/page/" to "Malayalam", + "$mainUrl/genre/tamil/page/" to "Tamil", + "$mainUrl/genre/telugu/page/" to "Telugu" + ) + + 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("a")?.text()?.trim() ?: return null + val href = fixUrl(this.selectFirst("a")?.attr("href").toString()) + val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("data-src")) + val quality = getQualityFromString(this.select("span.quality").text()) + + return newMovieSearchResponse(title, href, TvType.Movie) { + this.posterUrl = posterUrl + this.quality = quality + } + } + + override suspend fun search(query: String): List { + val document = app.get("$mainUrl/?s=$query").document + + return document.select(".result-item").mapNotNull { + val title = it.select(".title a")?.text()?.trim() ?: return@mapNotNull null + val href = fixUrl(it.selectFirst(".title a")?.attr("href").toString()) + val posterUrl = fixUrlNull(it.selectFirst(".thumbnail img")?.attr("src")) + val quality = getQualityFromString(it.select("span.quality").text()) + val tvtype = if (href.contains("tvshows")) TvType.TvSeries else TvType.Movie + newMovieSearchResponse(title, href, tvtype) { + this.posterUrl = posterUrl + this.quality = quality + } + } + } + + override suspend fun load(url: String): LoadResponse? { + val document = app.get(url).document + + val title = document.selectFirst("div.sheader h1")?.text()?.trim() ?: return null + val poster = fixUrlNull(document.selectFirst("div.poster img")?.attr("src")) + //val tags = document.select("div.mvici-left p:nth-child(1) a").map { it.text() } + val year = document.select("span.date").text().trim().split(",").last() + .toIntOrNull() + val tvType = if (document.select("#seasons") + .isNullOrEmpty() + ) TvType.Movie else TvType.TvSeries + val description = document.selectFirst(".wp-content p")?.text()?.trim() + val trailer = fixUrlNull(document.select("iframe").attr("src")) + val rating = document.select("#info span strong").text().toRatingInt() + val actors = document.select("#cast > div:nth-child(4)").map { it.text() } + val recommendations = document.select("article").mapNotNull { + it.toSearchResult() + } + + return if (tvType == TvType.TvSeries) { + val episodes = document.select("ul.episodios li").mapNotNull { + val href = fixUrl(it.select("a").attr("href")?: return null) + val name = it.select("a").text().trim() + val thumbs = it.select("img").attr("src") + val season = it.select(".numerando").text().split(" - ").first().toInt() + val episode = it.select(".numerando").text().split(" - ").last().toInt() + Episode( + href, + name, + season, + episode, + thumbs + ) + } + + 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 + val id = document.select(".dooplay_player_option").attr("data-post") + document.select("ul#playeroptionsul li#player-option-1").map { + it.attr("data-nume") + }.apmap { nume -> + safeApiCall { + val source = app.post( + url = "$mainUrl/wp-admin/admin-ajax.php", + data = mapOf( + "action" to "doo_player_ajax", + "post" to id, + "nume" to nume, + "type" to "movie" + ), + referer = data, + headers = mapOf("X-Requested-With" to "XMLHttpRequest") + ).parsed().embed_url + + loadExtractor(source, data, subtitleCallback, callback) + } + } + return true + } + data class ResponseHash( + @JsonProperty("embed_url") val embed_url: String, + @JsonProperty("type") val type: String?, + ) +} diff --git a/build.gradle.kts b/build.gradle.kts index 2cd20b3..526da96 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -78,6 +78,8 @@ subprojects { implementation(kotlin("stdlib")) // adds standard kotlin features, like listOf, mapOf etc implementation("com.github.Blatzar:NiceHttp:0.3.2") // http library implementation("org.jsoup:jsoup:1.13.1") // html parser + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.1") + implementation("io.karn:khttp-android:0.1.2") } }