diff --git a/KuramanimeProvider/build.gradle.kts b/KuramanimeProvider/build.gradle.kts index 4c82120c..984e72da 100644 --- a/KuramanimeProvider/build.gradle.kts +++ b/KuramanimeProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 2 +version = 3 cloudstream { diff --git a/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProvider.kt b/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProvider.kt index 1edb9f0c..49cbcee4 100644 --- a/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProvider.kt +++ b/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProvider.kt @@ -1,8 +1,11 @@ package com.hexated import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.loadExtractor import org.jsoup.Jsoup import org.jsoup.nodes.Element @@ -132,29 +135,56 @@ class KuramanimeProvider : MainAPI() { } + private suspend fun invokeLocalSource( + url: String, + ref: String, + callback: (ExtractorLink) -> Unit + ) { + val document = app.get( + url, + referer = ref, + headers = mapOf("X-Requested-With" to "XMLHttpRequest") + ).document + document.select("video#player > source").map { + val link = fixUrl(it.attr("src")) + val quality = it.attr("size").toIntOrNull() + callback.invoke( + ExtractorLink( + name, + name, + link, + referer = "$mainUrl/", + quality = quality ?: Qualities.Unknown.value, + headers = mapOf( + "Range" to "bytes=0-" + ) + ) + ) + } + } + override suspend fun loadLinks( data: String, isCasting: Boolean, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ): Boolean { - val servers = app.get(data).document - servers.select("video#player > source").map { - suspendSafeApiCall { - val url = it.attr("src") - val quality = it.attr("size").toInt() - callback.invoke( - ExtractorLink( - name, - name, - url, - referer = "$mainUrl/", - quality = quality, - headers = mapOf( - "Range" to "bytes=0-" - ) - ) - ) + val res = app.get(data).document + res.select("select#changeServer option").apmap { source -> + safeApiCall { + val server = source.attr("value") + val link = "$data?activate_stream=1&stream_server=$server" + if (server == "kuramadrive") { + invokeLocalSource(link, data, callback) + } else { + app.get( + link, + referer = data, + headers = mapOf("X-Requested-With" to "XMLHttpRequest") + ).document.select("div.iframe-container iframe").attr("src").let { videoUrl -> + loadExtractor(fixUrl(videoUrl), "$mainUrl/", subtitleCallback, callback) + } + } } } diff --git a/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProviderPlugin.kt b/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProviderPlugin.kt index fe6b59a1..6580af37 100644 --- a/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProviderPlugin.kt +++ b/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProviderPlugin.kt @@ -10,5 +10,6 @@ class KuramanimeProviderPlugin: Plugin() { override fun load(context: Context) { // All providers should be added in this manner. Please don't edit the providers list directly. registerMainAPI(KuramanimeProvider()) + registerExtractorAPI(Nyomo()) } } \ No newline at end of file diff --git a/KuramanimeProvider/src/main/kotlin/com/hexated/Nyomo.kt b/KuramanimeProvider/src/main/kotlin/com/hexated/Nyomo.kt new file mode 100644 index 00000000..2174c7e4 --- /dev/null +++ b/KuramanimeProvider/src/main/kotlin/com/hexated/Nyomo.kt @@ -0,0 +1,7 @@ +package com.hexated + +import com.lagradost.cloudstream3.extractors.StreamSB + +class Nyomo : StreamSB() { + override var mainUrl = "https://nyomo.my.id" +} \ No newline at end of file diff --git a/RebahinProvider/build.gradle.kts b/RebahinProvider/build.gradle.kts index 8d2dfd1d..11c96ec4 100644 --- a/RebahinProvider/build.gradle.kts +++ b/RebahinProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 1 +version = 2 cloudstream { diff --git a/RebahinProvider/src/main/kotlin/com/hexated/Kitanonton.kt b/RebahinProvider/src/main/kotlin/com/hexated/Kitanonton.kt new file mode 100644 index 00000000..115fe63d --- /dev/null +++ b/RebahinProvider/src/main/kotlin/com/hexated/Kitanonton.kt @@ -0,0 +1,32 @@ +package com.hexated + +import com.lagradost.cloudstream3.* + +class Kitanonton : RebahinProvider() { + override var mainUrl = "https://124.150.139.91" + override var name = "KitaNonton" + override var mainServer = "https://199.87.210.226" + + override val mainPage = mainPageOf( + "$mainUrl/genre/populer/page/" to "Populer Movies", + "$mainUrl/movies/page/" to "New Movies", + "$mainUrl/genre/westseries/page/" to "West TV Series", + "$mainUrl/genre/drama-korea/page/" to "Drama Korea", + "$mainUrl/genre/animation/page/" to "Anime", + "$mainUrl/genre/series-indonesia/page/" to "Drama Indonesia", + "$mainUrl/genre/drama-jepang/page/" to "Drama Jepang", + "$mainUrl/genre/drama-china/page/" to "Drama China", + "$mainUrl/genre/thailand-series/page/" to "Drama Thailand", + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document + val home = document.select("div#featured div.ml-item").mapNotNull { + it.toSearchResult() + } + return newHomePageResponse(request.name, home) + } +} \ No newline at end of file diff --git a/RebahinProvider/src/main/kotlin/com/hexated/RebahinProvider.kt b/RebahinProvider/src/main/kotlin/com/hexated/RebahinProvider.kt index 3fd3e8d5..877f587d 100644 --- a/RebahinProvider/src/main/kotlin/com/hexated/RebahinProvider.kt +++ b/RebahinProvider/src/main/kotlin/com/hexated/RebahinProvider.kt @@ -7,19 +7,18 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.network.WebViewResolver +import com.lagradost.cloudstream3.utils.* 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.nodes.Element import java.net.URI -class RebahinProvider : MainAPI() { - override var mainUrl = "http://104.237.198.194" +open class RebahinProvider : MainAPI() { + override var mainUrl = "http://104.237.198.196" override var name = "Rebahin" override val hasMainPage = true override var lang = "id" override val hasDownloadSupport = true + open var mainServer = "http://172.96.161.72" override val supportedTypes = setOf( TvType.Movie, TvType.TvSeries, @@ -27,7 +26,7 @@ class RebahinProvider : MainAPI() { TvType.AsianDrama ) - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { + override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { val urls = listOf( Pair("Featured", "xtab1"), Pair("Film Terbaru", "xtab2"), @@ -50,7 +49,7 @@ class RebahinProvider : MainAPI() { val home = app.get("$mainUrl/wp-content/themes/indoxxi/ajax-top-$tab.php").document.select( "div.ml-item" - ).map { + ).mapNotNull { it.toSearchResult() } items.add(HomePageList(header, home)) @@ -63,13 +62,13 @@ class RebahinProvider : MainAPI() { return HomePageResponse(items) } - private fun Element.toSearchResult(): SearchResponse { - val title = this.selectFirst("span.mli-info > h2")!!.text().trim() + fun Element.toSearchResult(): SearchResponse? { + val title = this.selectFirst("span.mli-info > h2")?.text() ?: return null val href = this.selectFirst("a")!!.attr("href") val type = if (this.select("span.mli-quality").isNotEmpty()) TvType.Movie else TvType.TvSeries return if (type == TvType.Movie) { - val posterUrl = this.select("img").attr("src") + val posterUrl = fixUrlNull(this.select("img").attr("src")) val quality = getQualityFromString(this.select("span.mli-quality").text().trim()) newMovieSearchResponse(title, href, TvType.Movie) { this.posterUrl = posterUrl @@ -77,7 +76,9 @@ class RebahinProvider : MainAPI() { } } else { val posterUrl = - this.select("img").attr("src").ifEmpty { this.select("img").attr("data-original") } + fixUrlNull( + this.select("img").attr("src") + .ifEmpty { this.select("img").attr("data-original") }) val episode = this.select("div.mli-eps > span").text().replace(Regex("[^0-9]"), "").toIntOrNull() newAnimeSearchResponse(title, href, TvType.TvSeries) { @@ -91,7 +92,7 @@ class RebahinProvider : MainAPI() { val link = "$mainUrl/?s=$query" val document = app.get(link).document - return document.select("div.ml-item").map { + return document.select("div.ml-item").mapNotNull { it.toSearchResult() } } @@ -157,10 +158,15 @@ class RebahinProvider : MainAPI() { } } + private fun getLanguage(str: String): String { + return when { + str.contains("indonesia", true) || str.contains("bahasa", true) -> "Indonesian" + else -> str + } + } + private suspend fun invokeLokalSource( url: String, - name: String, - ref: String, subCallback: (SubtitleFile) -> Unit, sourceCallback: (ExtractorLink) -> Unit ) { @@ -171,37 +177,35 @@ class RebahinProvider : MainAPI() { headers = mapOf("Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8") ).document - document.select("script").map { script -> - if (script.data().contains("sources: [")) { - val source = tryParseJson( - script.data().substringAfter("sources: [").substringBefore("],") - ) - val m3uData = app.get(source!!.file, referer = ref).text - val quality = Regex("\\d{3,4}\\.m3u8").findAll(m3uData).map { it.value }.toList() - - quality.forEach { + document.select("script").find { it.data().contains("config =") }?.data()?.let { script -> + Regex("\"file\":\\s?\"(.+.m3u8)\"").find(script)?.groupValues?.getOrNull(1) + ?.let { link -> sourceCallback.invoke( ExtractorLink( source = name, name = name, - url = source.file.replace("video.m3u8", it), - referer = ref, - quality = getQualityFromName("${it.replace(".m3u8", "")}p"), - isM3u8 = true + url = link, + referer = "$mainServer/", + quality = Qualities.Unknown.value, + isM3u8 = true, + headers = mapOf("Accept" to "*/*", "Origin" to mainServer) ) ) } - val trackJson = script.data().substringAfter("tracks: [").substringBefore("],") - val track = tryParseJson>("[$trackJson]") - track?.map { - subCallback.invoke( - SubtitleFile( - "Indonesian", - (if (it.file.contains(".srt")) it.file else null)!! - ) + val subData = + Regex("\"?tracks\"?:\\s\\n?\\[(.*)],").find(script)?.groupValues?.getOrNull(1) + ?: Regex("\"?tracks\"?:\\s\\n?\\[\\s*(?s:(.+)],\\n\\s*\"sources)").find(script)?.groupValues?.getOrNull( + 1 ) - } + tryParseJson>("[$subData]")?.map { + subCallback.invoke( + SubtitleFile( + getLanguage(it.label ?: return@map null), + if (it.file?.contains(".srt") == true) it.file else return@map null + ) + ) + } } } @@ -233,7 +237,7 @@ class RebahinProvider : MainAPI() { sources.captions?.map { subCallback.invoke( SubtitleFile( - if (it.language.lowercase().contains("eng")) it.language else "Indonesian", + getLanguage(it.language), "$domainUrl/asset/userdata/$userData/caption/${it.hash}/${it.id}.srt" ) ) @@ -251,10 +255,8 @@ class RebahinProvider : MainAPI() { data.removeSurrounding("[", "]").split(",").map { it.trim() }.apmap { link -> safeApiCall { when { - link.startsWith("http://172.96.161.72") -> invokeLokalSource( + link.startsWith(mainServer) -> invokeLokalSource( link, - this.name, - "http://172.96.161.72/", subtitleCallback, callback ) @@ -286,16 +288,10 @@ class RebahinProvider : MainAPI() { return true } - private data class ResponseLocal( - @JsonProperty("file") val file: String, - @JsonProperty("label") val label: String, - @JsonProperty("type") val type: String? - ) - private data class Tracks( - @JsonProperty("file") val file: String, - @JsonProperty("label") val label: String?, - @JsonProperty("kind") val kind: String? + @JsonProperty("file") val file: String? = null, + @JsonProperty("label") val label: String? = null, + @JsonProperty("kind") val kind: String? = null ) private data class Captions( diff --git a/RebahinProvider/src/main/kotlin/com/hexated/RebahinProviderPlugin.kt b/RebahinProvider/src/main/kotlin/com/hexated/RebahinProviderPlugin.kt index 7fc66950..4dd5882e 100644 --- a/RebahinProvider/src/main/kotlin/com/hexated/RebahinProviderPlugin.kt +++ b/RebahinProvider/src/main/kotlin/com/hexated/RebahinProviderPlugin.kt @@ -10,5 +10,6 @@ class RebahinProviderPlugin: Plugin() { override fun load(context: Context) { // All providers should be added in this manner. Please don't edit the providers list directly. registerMainAPI(RebahinProvider()) + registerMainAPI(Kitanonton()) } } \ No newline at end of file diff --git a/YomoviesProvider/build.gradle.kts b/YomoviesProvider/build.gradle.kts index 1af20ab6..d332fd47 100644 --- a/YomoviesProvider/build.gradle.kts +++ b/YomoviesProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 6 +version = 7 cloudstream { diff --git a/YomoviesProvider/src/main/kotlin/com/hexated/SpeedoStream.kt b/YomoviesProvider/src/main/kotlin/com/hexated/SpeedoStream.kt new file mode 100644 index 00000000..a9fad667 --- /dev/null +++ b/YomoviesProvider/src/main/kotlin/com/hexated/SpeedoStream.kt @@ -0,0 +1,36 @@ +package com.hexated + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.AppUtils +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper + +class SpeedoStream1 : ExtractorApi() { + override val name = "SpeedoStream" + override val mainUrl = "https://speedostream.nl" + override val requiresReferer = true + + override suspend fun getUrl(url: String, referer: String?): List { + val sources = mutableListOf() + app.get(url, referer = referer).document.select("script").map { script -> + if (script.data().contains("jwplayer(\"vplayer\").setup(")) { + val data = script.data().substringAfter("sources: [") + .substringBefore("],").replace("file", "\"file\"").trim() + AppUtils.tryParseJson(data)?.let { + M3u8Helper.generateM3u8( + name, + it.file, + "$mainUrl/", + ).forEach { m3uData -> sources.add(m3uData) } + } + } + } + return sources + } + + private data class File( + @JsonProperty("file") val file: String, + ) +} \ No newline at end of file diff --git a/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt b/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt index 72cbcd16..238f820e 100644 --- a/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt +++ b/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt @@ -10,5 +10,6 @@ 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()) + registerExtractorAPI(SpeedoStream1()) } } \ No newline at end of file