diff --git a/5movierulzProvider/build.gradle.kts b/5movierulzProvider/build.gradle.kts new file mode 100644 index 0000000..219ef91 --- /dev/null +++ b/5movierulzProvider/build.gradle.kts @@ -0,0 +1,24 @@ +version = 1 + + +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" + 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( + "Movie", + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=5movierulz.cm&sz=%size%" +} diff --git a/5movierulzProvider/src/main/AndroidManifest.xml b/5movierulzProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7fbfe5f --- /dev/null +++ b/5movierulzProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/5movierulzProvider/src/main/kotlin/com/darkdemon/FivemovierulzPlugin.kt b/5movierulzProvider/src/main/kotlin/com/darkdemon/FivemovierulzPlugin.kt new file mode 100644 index 0000000..acd2eac --- /dev/null +++ b/5movierulzProvider/src/main/kotlin/com/darkdemon/FivemovierulzPlugin.kt @@ -0,0 +1,17 @@ +package com.darkdemon + +import com.lagradost.cloudstream3.plugins.CloudstreamPlugin +import com.lagradost.cloudstream3.plugins.Plugin +import android.content.Context + +@CloudstreamPlugin +class FivemovierulzPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerExtractorAPI(Sbanh()) + registerExtractorAPI(Sendcm()) + registerExtractorAPI(Ncdnstm()) + registerExtractorAPI(StreamTapeAdblockUser()) + registerMainAPI(FivemovierulzProvider()) + } +} diff --git a/5movierulzProvider/src/main/kotlin/com/darkdemon/FivemovierulzProvider.kt b/5movierulzProvider/src/main/kotlin/com/darkdemon/FivemovierulzProvider.kt new file mode 100644 index 0000000..de6323e --- /dev/null +++ b/5movierulzProvider/src/main/kotlin/com/darkdemon/FivemovierulzProvider.kt @@ -0,0 +1,135 @@ +package com.darkdemon + +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.LoadResponse.Companion.addActors +import com.lagradost.cloudstream3.extractors.StreamSB +import com.lagradost.cloudstream3.extractors.StreamTape +import com.lagradost.cloudstream3.extractors.XStreamCdn +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.loadExtractor +import org.jsoup.nodes.Element + +class FivemovierulzProvider : MainAPI() { // all providers must be an instance of MainAPI + override var mainUrl = "https://5movierulz.cm" + override var name = "5movierulz" + override val hasMainPage = true + override var lang = "hi" + override val hasDownloadSupport = true + override val supportedTypes = setOf( + TvType.Movie, + ) + + override val mainPage = mainPageOf( + "$mainUrl/category/featured/page/" to "Popular Movies", + "$mainUrl/category/hollywood-movie-2021/page/" to "English", + "$mainUrl/bollywood-movie-free/page/" to "Hindi", + "$mainUrl/tamil-movie-free/page/" to "Tamil", + "$mainUrl/telugu-movie/page/" to "Telugu", + "$mainUrl/malayalam-movie-online/page/" to "Malayalam", + "$mainUrl/category/bengali-movie/page/" to "Bengali", + "$mainUrl/category/punjabi-movie/page/" to "Punjabi", + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document + val home = document.select("#main .cont_display").mapNotNull { + it.toSearchResult() + } + return newHomePageResponse(request.name, home) + } + + private fun Element.toSearchResult(): SearchResponse? { + val title = + this.selectFirst("a")?.attr("title")?.trim()?.substringBefore("(") ?: return null + val href = fixUrl(this.selectFirst("a")?.attr("href").toString()) + val posterUrl = fixUrlNull(this.selectFirst("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").document + + return document.select("#main .cont_display").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()?.substringBefore("(") + ?: return null + val poster = fixUrlNull(document.selectFirst(".entry-content img")?.attr("src")) + val tags = + document.select("div.entry-content > p:nth-child(5)").text().substringAfter("Genres:") + .substringBefore("Country:").split(",").map { it } + val yearRegex = Regex("""\d{4}""") + val year = yearRegex.find( + document.select("h2.entry-title").text() + )?.groupValues?.getOrNull(0)?.toIntOrNull() + val description = document.select("div.entry-content > p:nth-child(6)").text().trim() + val actors = + document.select("div.entry-content > p:nth-child(5)").text() + .substringAfter("Starring by:") + .substringBefore("Genres:").split(",").map { it } + + return newMovieLoadResponse(title, url, TvType.Movie, url) { + this.posterUrl = poster + this.year = year + this.plot = description + this.tags = tags + addActors(actors) + } + } + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + val sources = ArrayList() + app.get(data).document.select(".entry-content p a[target=_blank]") + .mapNotNull { + if (it.attr("href").startsWith("https://down")) { + sources.add( + app.get(it.attr("href")).document.select(".entry-content iframe") + .attr("src") + ) + } else { + sources.add(it.attr("href")) + } + } + sources.forEach { source -> + val src = if (source.startsWith("https://stream")) source.replace( + "/([a-z])/".toRegex(), + "/e/" + ) else source + loadExtractor( + src, + "$mainUrl/", + subtitleCallback, + callback + ) + } + return true + } +} + +class Sbanh : StreamSB() { + override var mainUrl = "https://sbanh.com" +} + +class Ncdnstm : XStreamCdn() { + override var mainUrl = "https://ncdnstm.xyz" +} + +class StreamTapeAdblockUser : StreamTape() { + override var mainUrl = "https://streamtapeadblockuser.homes" +} diff --git a/5movierulzProvider/src/main/kotlin/com/darkdemon/Sendcm.kt b/5movierulzProvider/src/main/kotlin/com/darkdemon/Sendcm.kt new file mode 100644 index 0000000..07b56c9 --- /dev/null +++ b/5movierulzProvider/src/main/kotlin/com/darkdemon/Sendcm.kt @@ -0,0 +1,28 @@ +package com.darkdemon + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities + +open class Sendcm: ExtractorApi() { + override val name = "Sendcm" + override val mainUrl = "https://send.cm" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List { + val sources = mutableListOf() + val url = app.get(url).document.select("source").attr("src") + sources.add( + ExtractorLink( + name = name, + source = name, + url = url, + isM3u8 = false, + quality = Qualities.Unknown.value, + referer = url + ) + ) + return sources + } +} \ No newline at end of file diff --git a/SnehIPTVProvider/build.gradle.kts b/SnehIPTVProvider/build.gradle.kts new file mode 100644 index 0000000..5b54a1d --- /dev/null +++ b/SnehIPTVProvider/build.gradle.kts @@ -0,0 +1,24 @@ +version = 1 + + +cloudstream { + language = "hi" + // All of these properties are optional, you can safely remove them + + description = "This extension provide live channels from Sonyliv, Voot and Jiotv" + 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( + "Live", + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=snehiptv.netlify.app&sz=%size%" +} diff --git a/SnehIPTVProvider/src/main/AndroidManifest.xml b/SnehIPTVProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7fbfe5f --- /dev/null +++ b/SnehIPTVProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/SnehIPTVProvider/src/main/kotlin/com/darkdemon/SnehIPTVPlugin.kt b/SnehIPTVProvider/src/main/kotlin/com/darkdemon/SnehIPTVPlugin.kt new file mode 100644 index 0000000..082cb25 --- /dev/null +++ b/SnehIPTVProvider/src/main/kotlin/com/darkdemon/SnehIPTVPlugin.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 SnehIPTVPlugin : Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(SnehIPTVProvider()) + } +} diff --git a/SnehIPTVProvider/src/main/kotlin/com/darkdemon/SnehIPTVProvider.kt b/SnehIPTVProvider/src/main/kotlin/com/darkdemon/SnehIPTVProvider.kt new file mode 100644 index 0000000..9a59f77 --- /dev/null +++ b/SnehIPTVProvider/src/main/kotlin/com/darkdemon/SnehIPTVProvider.kt @@ -0,0 +1,139 @@ +package com.darkdemon + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.AppUtils.parseJson + +class SnehIPTVProvider : MainAPI() { // all providers must be an instance of MainAPI + override var mainUrl = "https://snehiptv.netlify.app" + override var name = "SnehIPTV" + override val hasMainPage = true + override var lang = "hi" + override val hasDownloadSupport = false + override val supportedTypes = setOf( + TvType.Live + ) + + data class IPTV( + @JsonProperty("id") var id: String? = null, + @JsonProperty("tvgLogo") var tvgLogo: String? = null, + @JsonProperty("title") var title: String? = null, + @JsonProperty("url") var url: String? = null, + @JsonProperty("url1") var url1: String? = null + ) + + private suspend fun getScriptData(url: String): String { + val html = app.get(url).document + val script = html.select("script").last()?.attr("src") + val doc = app.get("$mainUrl$script").text + return doc.substringAfter("JSON.parse('").substringBefore("')},:") + } + + override suspend fun getMainPage( + page: Int, request: MainPageRequest + ): HomePageResponse { + + val categories = listOf( + "sonyliv", + "voot", + "sports", + "entertainment", + "movies", + "news", + "music", + "kids", + "infotainment", + "lifestyle", + "business", + "educational", + "devotional" + + ) + val items = ArrayList() + val scriptData = getScriptData(mainUrl) + val response = parseJson>(scriptData) + categories.forEach { cat -> + val results: MutableList = mutableListOf() + val filtered = response.filter { it.title?.lowercase()?.contains(cat) == true } + filtered.forEach { + val title = it.title?.replace(regex = "\\s\\[[A-Za-z]+]".toRegex(), "").toString() + val posterUrl = it.tvgLogo.toString() + results.add( + newMovieSearchResponse(title, title, TvType.Live) { + this.posterUrl = posterUrl + } + ) + } + items.add( + HomePageList( + capitalizeString(cat), + results, + isHorizontalImages = true + ) + ) + } + return HomePageResponse(items) + } + + override suspend fun search(query: String): List? { + + val scriptData = getScriptData(mainUrl) + val response = parseJson>(scriptData) + val searchResults = + response.filter { it.title?.lowercase()?.contains(query.lowercase()) == true } + return searchResults.map { + val title = it.title?.replace(regex = "\\s\\[[A-Za-z]+]".toRegex(), "").toString() + val posterUrl = it.tvgLogo.toString() + newMovieSearchResponse(title, title, TvType.Live) { + this.posterUrl = posterUrl + } + } + } + + override suspend fun load(url: String): LoadResponse? { + + val scriptData = getScriptData(mainUrl) + val response = parseJson>(scriptData) + val searchResults = + response.filter { it.title?.contains(url.substringAfterLast("/")) == true } + val title = + searchResults[0].title?.replace(regex = "\\s\\[[A-Za-z]+]".toRegex(), "").toString() + val posterUrl = searchResults[0].tvgLogo.toString() + val href = + if (searchResults[0].url.isNullOrEmpty()) searchResults[0].url1 else searchResults[0].url + return newMovieLoadResponse(title, url, TvType.Movie, href) { + this.posterUrl = posterUrl + } + } + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + + val link = if (data.contains("sonyliv")) { + app.get(data).document.selectFirst(".movie__credits a")?.attr("href").toString() + } else if (data.contains("voot")) { + app.get(data).document.selectFirst("source")?.attr("src").toString() + } else { + val html = app.get(data) + html.url.substringBeforeLast("/") + "/${ + html.document.selectFirst("source")?.attr("src") + }" + }.toString() + callback.invoke( + ExtractorLink( + this.name, + this.name, + link, + referer = "", + quality = Qualities.Unknown.value, + isM3u8 = true, + ) + ) + return true + } +}