diff --git a/5movierulzProvider/build.gradle.kts b/MHDTVProvider/build.gradle.kts similarity index 51% rename from 5movierulzProvider/build.gradle.kts rename to MHDTVProvider/build.gradle.kts index 219ef91..4ed3987 100644 --- a/5movierulzProvider/build.gradle.kts +++ b/MHDTVProvider/build.gradle.kts @@ -5,7 +5,7 @@ cloudstream { language = "hi" // All of these properties are optional, you can safely remove them - description = "This website support English/Hindi/Bengali/Malayalam/Tamil/Telugu/Punjabi languages" + description = "This website support English/Hindi/Kannada/Malayalam/Tamil/Telugu live channels and Hindi Old Movies/Malayalam Movies \n For language in Sports: Please check background image[country flag] of the episode" authors = listOf("darkdemon") /** @@ -17,8 +17,8 @@ cloudstream { * */ status = 1 // will be 3 if unspecified tvTypes = listOf( - "Movie", + "Live" ) - iconUrl = "https://www.google.com/s2/favicons?domain=5movierulz.cm&sz=%size%" + iconUrl = "https://www.google.com/s2/favicons?domain=mhdtvworld.xyz&sz=%size%" } diff --git a/MHDTVProvider/src/main/AndroidManifest.xml b/MHDTVProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7fbfe5f --- /dev/null +++ b/MHDTVProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/MHDTVProvider/src/main/kotlin/com/darkdemon/MHDTVPlugin.kt b/MHDTVProvider/src/main/kotlin/com/darkdemon/MHDTVPlugin.kt new file mode 100644 index 0000000..0149abf --- /dev/null +++ b/MHDTVProvider/src/main/kotlin/com/darkdemon/MHDTVPlugin.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 MHDTVPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(MHDTVProvider()) + } +} diff --git a/MHDTVProvider/src/main/kotlin/com/darkdemon/MHDTVProvider.kt b/MHDTVProvider/src/main/kotlin/com/darkdemon/MHDTVProvider.kt new file mode 100644 index 0000000..5d2eadd --- /dev/null +++ b/MHDTVProvider/src/main/kotlin/com/darkdemon/MHDTVProvider.kt @@ -0,0 +1,295 @@ +package com.darkdemon + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.getAndUnpack +import org.jsoup.Jsoup +import org.jsoup.nodes.Element +import kotlin.math.floor + +class MHDTVProvider : MainAPI() { // all providers must be an instance of MainAPI + override var mainUrl = "https://mhdtvworld.xyz" + override var name = "MHDTVWorld" + override val hasMainPage = true + override var lang = "hi" + override val hasDownloadSupport = false + override val supportedTypes = setOf( + TvType.Live + ) + + override val mainPage = mainPageOf( + "$mainUrl/channel/sports/page/" to "Sports", + "$mainUrl/channel/english/page/" to "English", + "$mainUrl/channel/hindi/page/" to "Hindi", + "$mainUrl/channel/marathi/page/" to "Marathi", + "$mainUrl/channel/tamil/page/" to "Tamil", + "$mainUrl/channel/telugu/page/" to "Telugu", + "$mainUrl/channel/malayalam/page/" to "Malayalam", + "$mainUrl/channel/malayalam-news/page/" to "Malayalam News", + "$mainUrl/channel/kannada/page/" to "Kannada", + "$mainUrl/channel/punjabi/page/" to "Punjabi", + "$mainUrl/channel/bangla/page/" to "Bangla", + "$mainUrl/channel/hindi-movies/page/" to "Hindi Movies", + "$mainUrl/channel/malayalam-movies/page/" to "Malayalam Movies", + "$mainUrl/channel/pakistani/page/" to "Pakistani TV", + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val url = if (request.data.contains("page")) { + request.data + page + } else { + request.data + } + val document = app.get(url).document + val home = document.select("article").mapNotNull { + it.toSearchResult() + } + return newHomePageResponse(request.name, home) + } + + private fun Element.toSearchResult(): SearchResponse? { + val title = this.selectFirst("img")?.attr("alt")?.trim() ?: return null + val href = fixUrl(this.selectFirst("a")?.attr("href").toString()) + val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src")) + + return newMovieSearchResponse(title, href, TvType.Live) { + this.posterUrl = posterUrl + } + } + + override suspend fun search(query: String): List { + val document = app.get("$mainUrl/?s=$query").document + + return document.select("article").mapNotNull { + it.toSearchResult() + } + } + + private suspend fun getPostUrl(url: String, post: String, nume: String, type: String): String { + return app.post( + url = "$mainUrl/wp-admin/admin-ajax.php", + data = mapOf( + "action" to "doo_player_ajax", + "post" to post, + "nume" to nume, + "type" to type + ), + referer = url, + headers = mapOf("X-Requested-With" to "XMLHttpRequest") + ).parsed().embed_url + } + + override suspend fun load(url: String): LoadResponse? { + val document = app.get(url).document + + val title = document.selectFirst("h1")?.text()?.trim() ?: return null + val poster = fixUrlNull(document.selectFirst(".poster img")?.attr("src")) + val episodes = document.select("ul#playeroptionsul li").mapIndexedNotNull { index, it -> + val name = it.selectFirst(".title")?.text()?.trim() + val post = it.attr("data-post") + val nume = it.attr("data-nume") + val type = it.attr("data-type") + val thumbs = it.select(".flag img").attr("src") + val href = getPostUrl(url, post, nume, type) + val link = + if (href.contains("video")) Jsoup.parse(href).select("source").attr("src") + else if (href.contains("iframe")) Jsoup.parse(href).select("iframe").attr("src") + else if (href.startsWith("/delta")) "$mainUrl$href" + else href + Episode( + link, + name, + season = 1, + episode = index + 1, + posterUrl = thumbs + ) + } + return if (!document.select(".sgeneros a").last()?.text()!!.contains("movies")) { + newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) { + this.posterUrl = poster + } + } else { + val doc = document.select("ul#playeroptionsul li").mapIndexedNotNull { _, it -> + val post = it.attr("data-post") + val nume = it.attr("data-nume") + val type = it.attr("data-type") + getPostUrl(url, post, nume, type) + } + val trailer = if (doc.size == 1) "" else doc[0] + val href = if (doc.size == 1) doc[0] else doc[1] + val link = if (href.startsWith("/delta")) "$mainUrl$href" else href + return newMovieLoadResponse(title, url, TvType.Movie, link) { + this.posterUrl = poster + addTrailer(trailer) + } + } + } + + private fun decode(input: String): String = java.net.URLDecoder.decode(input, "utf-8") + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + + val document = app.get(url = data, referer = "$mainUrl/").document + if (data.startsWith("https://mhdtvworld.xyz/jwplayer/")) { + + val decoded = decode(data) + val source = decoded.substringAfter("source=").substringBefore("&id") + callback.invoke( + ExtractorLink( + this.name, + this.name, + url = source, + referer = data, + quality = Qualities.Unknown.value, + isM3u8 = true, + ) + ) + } else if (data.startsWith("https://mhdtvworld.xyz/delta") || data.startsWith("https://yuppstream.net.in/")) { + val srcRegex = Regex("""hls: '(.*?.)',""") + val regexMatch = + srcRegex.find(document.toString())?.groupValues?.getOrNull(1).toString() + val source = + if (!regexMatch.startsWith("https")) "${data.substringBefore("/play.php")}$regexMatch" else regexMatch + val referer = + if (data.startsWith(mainUrl)) "$mainUrl/" else data.substringBefore("play.php") + callback.invoke( + ExtractorLink( + this.name, + this.name, + url = source, + referer = referer, + quality = Qualities.Unknown.value, + isM3u8 = true, + ) + ) + + } else if (data.contains("m3u8")) { + ExtractorLink( + this.name, + this.name, + url = data.trim(), + referer = "", + quality = Qualities.Unknown.value, + isM3u8 = true, + ) + } else if (data.startsWith("https://tvstream.fun") || data.startsWith("https://tvworld.fun/") || data.startsWith( + "https://tv.googledrivelinks.com/" + ) + ) { + val domain = + if (data.startsWith("https://tvstream.fun")) data.substringBefore("/jtv") else data.substringBefore( + "/play.php" + ) + val srcRegex = Regex("""source: "(.*?.)",|hls: '(.*?.)',""") + val source = + if (!srcRegex.find(document.toString())?.groupValues?.getOrNull(2).isNullOrEmpty()) + "$domain${ + srcRegex.find(document.toString())?.groupValues?.getOrNull(2) + }" else if (document.select("source").attr("src") + .startsWith("/") + ) "$domain${document.select("source").attr("src")}" else "$domain/${ + document.select( + "source" + ).attr("src") + }" + callback.invoke( + ExtractorLink( + this.name, + this.name, + source, + referer = data, + quality = Qualities.Unknown.value, + isM3u8 = true, + ) + ) + } else if (data.startsWith("https://techclips.net/")) { + val domain = data.substringBefore("clip/") + val srcRegex = Regex("""servs = \[(.*?.)];""") + val servers = srcRegex.find(document.toString())?.groupValues?.getOrNull(1)?.split(",") + val server = + servers?.get(floor(Math.random() * servers.size).toInt())?.replace("\"", "") + ?.trim() + + val source = "https://$server${data.substringAfterLast("/").replace("html", "m3u8")}" + callback.invoke( + ExtractorLink( + this.name, + this.name, + source, + referer = domain, + quality = Qualities.Unknown.value, + isM3u8 = true, + ) + ) + } else if (data.startsWith("https://gocast123.me/")) { + val srcRegex = Regex("""source: '(https?.*?.m3u8)',""") + val source = + srcRegex.find(document.toString())?.groupValues?.getOrNull(1).toString() + callback.invoke( + ExtractorLink( + this.name, + this.name, + url = source, + referer = "https://123ecast.me/", + quality = Qualities.Unknown.value, + isM3u8 = true, + ) + ) + } else if (data.startsWith("https://v4.sportsonline.to")) { + val embedLink = document.select("iframe").attr("src") + app.get( + embedLink, + referer = data.substringBefore("channels") + ).document.select("script").map { it.data() } + .filter { it.contains("eval(function(p,a,c,k,e,d)") } + .map { script -> + val unpacked = if (script.contains("m3u8")) getAndUnpack(script) else "" + val link = + Regex("""[src="](https?.*?)"""").findAll(unpacked).map { it.value }.toList() + .toList() + val domain = embedLink.substringBefore("embed") + link.forEach { + callback.invoke( + ExtractorLink( + this.name, + this.name, + it.replace("\"", ""), + domain, + Qualities.Unknown.value, + isM3u8 = true + ) + ) + } + } + } + return true + } + + private fun fixUrl(url: String): String { + if (url.isEmpty()) return "" + + if (url.startsWith("//")) { + return "http:$url" + } + if (!url.startsWith("http")) { + return "http://$url" + } + return url + } + + data class ResponseHash( + @JsonProperty("embed_url") val embed_url: String, + @JsonProperty("type") val type: String?, + ) +}