diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index 368c9986..44a734e5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -109,7 +109,8 @@ object APIHolder { PhimmoichillProvider(), HDrezkaProvider(), YomoviesProvider(), - + DubokuProvider(), + KisskhProvider(), // Metadata providers //TmdbProvider(), @@ -148,6 +149,7 @@ object APIHolder { AnimeIndoProvider(), AnimeSailProvider(), TocanimeProvider(), + WcofunProvider(), //MultiAnimeProvider(), NginxProvider(), OlgplyProvider(), diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeIndoProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeIndoProvider.kt index 4a2867a7..295f134a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeIndoProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeIndoProvider.kt @@ -62,20 +62,20 @@ class AnimeIndoProvider : MainAPI() { } } - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = request(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/anime-terbaru/page/" to "Anime Terbaru", + "$mainUrl/donghua-terbaru/page/" to "Donghua Terbaru" + ) - val homePageList = ArrayList() - - document.select("div.widget_senction").forEach { block -> - val header = block.selectFirst("div.widget-title > h3")!!.text().trim() - val items = block.select("div.post-show > article").map { - it.toSearchResult() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = request(request.data + page).document + val home = document.select("div.post-show > article").mapNotNull { + it.toSearchResult() } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } private fun getProperAnimeLink(uri: String): String { @@ -96,8 +96,8 @@ class AnimeIndoProvider : MainAPI() { } } - private fun Element.toSearchResult(): AnimeSearchResponse { - val title = this.selectFirst("div.title")!!.text().trim() + private fun Element.toSearchResult(): AnimeSearchResponse? { + val title = this.selectFirst("div.title")?.text()?.trim() ?: return null val href = getProperAnimeLink(this.selectFirst("a")!!.attr("href")) val posterUrl = this.select("img[itemprop=image]").attr("src").toString() val type = getType(this.select("div.type").text().trim()) diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeSailProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeSailProvider.kt index 262e4a60..07a93fd7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeSailProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeSailProvider.kt @@ -47,20 +47,18 @@ class AnimeSailProvider : MainAPI() { ) } - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = request(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/page/" to "Episode Terbaru", + "$mainUrl/movie-terbaru/page/" to "Movie Terbaru", + "$mainUrl/genres/donghua/page/" to "Donghua" + ) - val homePageList = ArrayList() - - document.select(".bixbox").forEach { block -> - val header = block.select(".releases > h3").text().trim() - val animes = block.select("article").map { - it.toSearchResult() - } - if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes)) + override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { + val document = request(request.data + page).document + val home = document.select("article").map { + it.toSearchResult() } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } private fun getProperAnimeLink(uri: String): String { diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GomunimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GomunimeProvider.kt index 742ed04b..66a9ee99 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GomunimeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GomunimeProvider.kt @@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.animeproviders import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer -import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.ExtractorLink @@ -41,51 +40,41 @@ class GomunimeProvider : MainAPI() { } } - private data class Response( - @JsonProperty("status") val status: Boolean, - @JsonProperty("html") val html: String + override val mainPage = mainPageOf( + "e" to "Episode Baru", + "c" to "Completed", + "la" to "Live Action", + "t" to "Trending" ) - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val urls = listOf( - Pair("e", "Episode Baru"), - Pair("c", "Completed"), - Pair("la", "Live Action"), - Pair("t", "Trending"), - ) - - val items = ArrayList() - - for ((payload, name) in urls) { - try { - val home = Jsoup.parse( - parseJson( - app.post( - url = "$mainUrl/wp-admin/admin-ajax.php/wp-admin/admin-ajax.php", - headers = mapOf("Referer" to mainUrl), - data = mapOf("action" to "home_ajax", "fungsi" to payload, "pag" to "1") - ).text - ).html - ).select("li").map { - val title = it.selectFirst("a.name")!!.text().trim() - val href = getProperAnimeLink(it.selectFirst("a")!!.attr("href")) - val posterUrl = it.selectFirst("img")!!.attr("src") - val type = getType(it.selectFirst(".taglist > span")!!.text().trim()) - val epNum = it.select(".tag.ep").text().replace(Regex("[^0-9]"), "").trim() - .toIntOrNull() - newAnimeSearchResponse(title, href, type) { - this.posterUrl = posterUrl - addSub(epNum) - } - } - items.add(HomePageList(name, home)) - } catch (e: Exception) { - logError(e) + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val home = Jsoup.parse( + (app.post( + url = "$mainUrl/wp-admin/admin-ajax.php/wp-admin/admin-ajax.php", + headers = mapOf("Referer" to mainUrl), + data = mapOf( + "action" to "home_ajax", + "fungsi" to request.data, + "pag" to "$page" + ) + ).parsedSafe()?.html ?: throw ErrorLoadingException("Invalid Json reponse")) + ).select("li").mapNotNull { + val title = it.selectFirst("a.name")?.text()?.trim() ?: return@mapNotNull null + val href = getProperAnimeLink(it.selectFirst("a")!!.attr("href")) + val posterUrl = it.selectFirst("img")?.attr("src") + val type = getType(it.selectFirst(".taglist > span")!!.text().trim()) + val epNum = it.select(".tag.ep").text().replace(Regex("[^0-9]"), "").trim() + .toIntOrNull() + newAnimeSearchResponse(title, href, type) { + this.posterUrl = posterUrl + addSub(epNum) } } - if (items.size <= 0) throw ErrorLoadingException() - return HomePageResponse(items) + return newHomePageResponse(request.name, home) } private fun getProperAnimeLink(uri: String): String { @@ -119,14 +108,6 @@ class GomunimeProvider : MainAPI() { } } - private data class EpisodeElement( - @JsonProperty("data-index") val dataIndex: Long?, - @JsonProperty("ep-num") val epNum: String?, - @JsonProperty("ep-title") val epTitle: String?, - @JsonProperty("ep-link") val epLink: String, - @JsonProperty("ep-date") val epDate: String? - ) - override suspend fun load(url: String): LoadResponse { val document = app.get(url).document @@ -164,12 +145,6 @@ class GomunimeProvider : MainAPI() { } } - data class MobiSource( - @JsonProperty("file") val file: String, - @JsonProperty("label") val label: String, - @JsonProperty("type") val type: String - ) - override suspend fun loadLinks( data: String, isCasting: Boolean, @@ -234,4 +209,24 @@ class GomunimeProvider : MainAPI() { return true } + + private data class Response( + @JsonProperty("status") val status: Boolean, + @JsonProperty("html") val html: String + ) + + data class MobiSource( + @JsonProperty("file") val file: String, + @JsonProperty("label") val label: String, + @JsonProperty("type") val type: String + ) + + private data class EpisodeElement( + @JsonProperty("data-index") val dataIndex: Long?, + @JsonProperty("ep-num") val epNum: String?, + @JsonProperty("ep-title") val epTitle: String?, + @JsonProperty("ep-link") val epLink: String, + @JsonProperty("ep-date") val epDate: String? + ) + } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KuramanimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KuramanimeProvider.kt index db87d158..4d2f3d46 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KuramanimeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KuramanimeProvider.kt @@ -2,11 +2,9 @@ package com.lagradost.cloudstream3.animeproviders import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall -import com.lagradost.cloudstream3.network.DdosGuardKiller import com.lagradost.cloudstream3.utils.ExtractorLink import org.jsoup.Jsoup import org.jsoup.nodes.Element -import java.util.* class KuramanimeProvider : MainAPI() { override var mainUrl = "https://kuramanime.com" @@ -38,28 +36,24 @@ class KuramanimeProvider : MainAPI() { } } - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/anime/ongoing?order_by=updated&page=" to "Sedang Tayang", + "$mainUrl/anime/finished?order_by=updated&page=" to "Selesai Tayang", + "$mainUrl/properties/season/summer-2022?order_by=most_viewed&page=" to "Dilihat Terbanyak Musim Ini", + "$mainUrl/anime/movie?order_by=updated&page=" to "Film Layar Lebar", + ) - val homePageList = ArrayList() + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document - document.select("div.trending__product").forEach { block -> - val header = block.selectFirst("h4")?.text().toString() - val animes = block.select("div.col-lg-4.col-md-6.col-sm-6").map { - it.toSearchResult() - } - if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes)) + val home = document.select("div.col-lg-4.col-md-6.col-sm-6").mapNotNull { + it.toSearchResult() } - document.select("div.product__sidebar__view").forEach { block -> - val header = block.selectFirst("h5")?.text().toString() - val animes = block.select("div.product__sidebar__comment__item").map { - it.toSearchResultView() - } - if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes)) - } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } private fun getProperAnimeLink(uri: String): String { @@ -70,9 +64,9 @@ class KuramanimeProvider : MainAPI() { } } - private fun Element.toSearchResult(): AnimeSearchResponse { + private fun Element.toSearchResult(): AnimeSearchResponse? { val href = getProperAnimeLink(fixUrl(this.selectFirst("a")!!.attr("href"))) - val title = this.selectFirst("h5 a")?.text().toString() + val title = this.selectFirst("h5 a")?.text() ?: return null val posterUrl = fixUrl(this.select("div.product__item__pic.set-bg").attr("data-setbg")) val episode = Regex("([0-9*])\\s?/").find( this.select("div.ep span").text() @@ -85,23 +79,6 @@ class KuramanimeProvider : MainAPI() { } - private fun Element.toSearchResultView(): AnimeSearchResponse { - val href = getProperAnimeLink(fixUrl(this.selectFirst("a")?.attr("href").toString())) - val title = this.selectFirst("h5")?.text()?.trim().toString() - val posterUrl = fixUrlNull( - this.selectFirst("div.product__sidebar__comment__item__pic.set-bg")?.attr("data-setbg") - ) - val episode = - this.selectFirst("h5")?.nextElementSibling()?.text()?.replace(Regex("[^0-9]"), "") - ?.toIntOrNull() - - return newAnimeSearchResponse(title, href, TvType.Anime) { - this.posterUrl = posterUrl - addSub(episode) - } - - } - override suspend fun search(query: String): List { val link = "$mainUrl/anime?search=$query&order_by=oldest" val document = app.get(link).document diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KuronimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KuronimeProvider.kt index e6498759..950799e1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KuronimeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KuronimeProvider.kt @@ -39,20 +39,23 @@ class KuronimeProvider : MainAPI() { } } - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/page/" to "New Episodes", + "$mainUrl/popular-anime/page/" to "Popular Anime", + "$mainUrl/movies/page/" to "Movies", + "$mainUrl/genres/donghua/page/" to "Donghua", + "$mainUrl/live-action/page/" to "Live Action", + ) - val homePageList = ArrayList() - - document.select(".bixbox").forEach { block -> - val header = block.select(".releases > h3").text().trim() - val animes = block.select("article").map { - it.toSearchResult() - } - if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes)) + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document + val home = document.select("article").map { + it.toSearchResult() } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } private fun getProperAnimeLink(uri: String): String { @@ -77,7 +80,10 @@ class KuronimeProvider : MainAPI() { private fun Element.toSearchResult(): AnimeSearchResponse { val href = getProperAnimeLink(fixUrlNull(this.selectFirst("a")?.attr("href")).toString()) val title = this.select(".bsuxtt, .tt > h4").text().trim() - val posterUrl = fixUrlNull(this.selectFirst("div.view,div.bt")?.nextElementSibling()?.select("img")?.attr("data-src")) + val posterUrl = fixUrlNull( + this.selectFirst("div.view,div.bt")?.nextElementSibling()?.select("img") + ?.attr("data-src") + ) val epNum = this.select(".ep").text().replace(Regex("[^0-9]"), "").trim().toIntOrNull() val tvType = getType(this.selectFirst(".bt > span")?.text().toString()) return newAnimeSearchResponse(title, href, tvType) { @@ -117,7 +123,8 @@ class KuronimeProvider : MainAPI() { val episodes = document.select("div.bixbox.bxcl > ul > li").map { val name = it.selectFirst("a")?.text()?.trim() - val episode = it.selectFirst("a")?.text()?.trim()?.replace("Episode", "")?.trim()?.toIntOrNull() + val episode = + it.selectFirst("a")?.text()?.trim()?.replace("Episode", "")?.trim()?.toIntOrNull() val link = it.selectFirst("a")!!.attr("href") Episode(link, name = name, episode = episode) }.reversed() diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NeonimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NeonimeProvider.kt index e7a05ddd..051c4cfd 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NeonimeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NeonimeProvider.kt @@ -40,20 +40,18 @@ class NeonimeProvider : MainAPI() { } } - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/episode/page/" to "Episode Terbaru", + "$mainUrl/tvshows/page/" to "Anime Terbaru", + "$mainUrl/movies/page/" to "Movie", + ) - val homePageList = ArrayList() - - document.select("div.item_1.items,div#slid01").forEach { block -> - val header = block.previousElementSibling()?.select("h1")?.text() ?: block.selectFirst("h3")?.text().toString() - val animes = block.select("div.item").map { + override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { + val document = app.get(request.data + page).document + val home = document.select("tbody tr,div.item").mapNotNull { it.toSearchResult() } - if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes)) - } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } private fun getProperAnimeLink(uri: String): String { @@ -80,11 +78,13 @@ class NeonimeProvider : MainAPI() { } } - private fun Element.toSearchResult(): AnimeSearchResponse { + private fun Element.toSearchResult(): AnimeSearchResponse? { + val title = this.selectFirst("td.bb a")?.ownText() ?: this.selectFirst("h2")?.text() ?: return null val href = getProperAnimeLink(fixUrl(this.select("a").attr("href"))) - val title = this.select("span.tt.title-episode,h2.title-episode-movie,span.ttps").text() val posterUrl = fixUrl(this.select("img").attr("data-src")) - val epNum = this.select(".fixyear > h2.text-center").text().replace(Regex("[^0-9]"), "").trim().toIntOrNull() + val epNum = this.selectFirst("td.bb span")?.text()?.let { eps -> + Regex("Episode\\s?([0-9]+)").find(eps)?.groupValues?.getOrNull(1)?.toIntOrNull() + } return newAnimeSearchResponse(title, href, TvType.Anime) { this.posterUrl = posterUrl diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NontonAnimeIDProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NontonAnimeIDProvider.kt index bc6033ea..9f518c66 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NontonAnimeIDProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NontonAnimeIDProvider.kt @@ -228,7 +228,7 @@ class NontonAnimeIDProvider : MainAPI() { val document = app.get(data).document val sources = ArrayList() - document.select(".container1 > ul > li").apmap { + document.select(".container1 > ul > li:not(.boxtab)").apmap { val dataPost = it.attr("data-post") val dataNume = it.attr("data-nume") val dataType = it.attr("data-type") @@ -240,7 +240,9 @@ class NontonAnimeIDProvider : MainAPI() { "post" to dataPost, "nume" to dataNume, "type" to dataType - ) + ), + referer = data, + headers = mapOf("X-Requested-With" to "XMLHttpRequest") ).document.select("iframe").attr("src") sources.add(fixUrl(iframe)) diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/OploverzProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/OploverzProvider.kt index 3afe213c..097f9125 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/OploverzProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/OploverzProvider.kt @@ -40,20 +40,21 @@ class OploverzProvider : MainAPI() { } } - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "&status=&type=&order=update" to "Episode Terbaru", + "&status=&type=&order=latest" to "Anime Terbaru", + "&sub=&order=popular" to "Popular Anime", + ) - val homePageList = ArrayList() - - document.select(".bixbox.bbnofrm").forEach { block -> - val header = block.selectFirst("h3")!!.text().trim() - val animes = block.select("article[itemscope=itemscope]").map { - it.toSearchResult() - } - if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes)) + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get("$mainUrl/anime/?page=$page${request.data}").document + val home = document.select("article[itemscope=itemscope]").mapNotNull { + it.toSearchResult() } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } private fun getProperAnimeLink(uri: String): String { @@ -68,7 +69,8 @@ class OploverzProvider : MainAPI() { )?.groupValues?.get(1).toString() (title.contains("-ova")) -> Regex("(.+)-ova").find(title)?.groupValues?.get(1) .toString() - (title.contains("-movie")) -> Regex("(.+)-subtitle").find(title)?.groupValues?.get(1).toString() + (title.contains("-movie")) -> Regex("(.+)-subtitle").find(title)?.groupValues?.get(1) + .toString() else -> Regex("(.+)-subtitle").find(title)?.groupValues?.get(1).toString() .replace(Regex("-\\d+"), "") } @@ -87,16 +89,14 @@ class OploverzProvider : MainAPI() { } - private fun Element.toSearchResult(): AnimeSearchResponse { + private fun Element.toSearchResult(): AnimeSearchResponse? { val href = getProperAnimeLink(this.selectFirst("a.tip")!!.attr("href")) - val title = this.selectFirst("h2[itemprop=headline]")?.text()?.trim() ?: "" + val title = this.selectFirst("h2[itemprop=headline]")?.text()?.trim() ?: return null val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src")) val type = getType(this.selectFirst(".eggtype, .typez")?.text()?.trim().toString()) - val epNum = this.selectFirst(".eggepisode, span.epx")?.text()?.replace(Regex("[^0-9]"), "")?.trim()?.toIntOrNull() return newAnimeSearchResponse(title, href, type) { this.posterUrl = posterUrl - addSub(epNum) } } @@ -144,7 +144,8 @@ class OploverzProvider : MainAPI() { val episodes = document.select(".eplister > ul > li").map { val header = it.select(".epl-title").text() - val name = Regex("(Episode\\s?[0-9]+)").find(header)?.groupValues?.getOrNull(0) ?: header + val name = + Regex("(Episode\\s?[0-9]+)").find(header)?.groupValues?.getOrNull(0) ?: header val link = fixUrl(it.select("a").attr("href")) Episode(link, name) }.reversed() diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/OtakudesuProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/OtakudesuProvider.kt index 560a5d1d..9ba17ca7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/OtakudesuProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/OtakudesuProvider.kt @@ -7,6 +7,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.loadExtractor import org.jsoup.Jsoup import org.jsoup.nodes.Element +import java.util.ArrayList class OtakudesuProvider : MainAPI() { override var mainUrl = "https://otakudesu.watch" @@ -37,24 +38,24 @@ class OtakudesuProvider : MainAPI() { } } - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/ongoing-anime/page/" to "Anime Ongoing", + "$mainUrl/complete-anime/page/" to "Anime Completed" + ) - val homePageList = ArrayList() - - document.select("div.rseries").forEach { block -> - val header = block.selectFirst("div.rvad > h1")!!.text().trim() - val items = block.select("div.venz > ul > li").map { - it.toSearchResult() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document + val home = document.select("div.venz > ul > li").mapNotNull { + it.toSearchResult() } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } - private fun Element.toSearchResult(): AnimeSearchResponse { - val title = this.selectFirst("h2.jdlflm")!!.text().trim() + private fun Element.toSearchResult(): AnimeSearchResponse? { + val title = this.selectFirst("h2.jdlflm")?.text()?.trim() ?: return null val href = this.selectFirst("a")!!.attr("href") val posterUrl = this.select("div.thumbz > img").attr("src").toString() val epNum = this.selectFirst("div.epz")?.ownText()?.replace(Regex("[^0-9]"), "")?.trim() @@ -103,7 +104,9 @@ class OtakudesuProvider : MainAPI() { val description = document.select("div.sinopc > p").text() val episodes = document.select("div.episodelist")[1].select("ul > li").mapNotNull { - val name = Regex("(Episode\\s?[0-9]+)").find(it.selectFirst("a")?.text().toString())?.groupValues?.getOrNull(0) ?: it.selectFirst("a")?.text() + val name = Regex("(Episode\\s?[0-9]+)").find( + it.selectFirst("a")?.text().toString() + )?.groupValues?.getOrNull(0) ?: it.selectFirst("a")?.text() val link = fixUrl(it.selectFirst("a")!!.attr("href")) Episode(link, name) }.reversed() @@ -180,7 +183,10 @@ class OtakudesuProvider : MainAPI() { ).select("iframe").attr("src") if (sources.startsWith("https://desustream.me")) { - if (!sources.contains("/arcg/") && !sources.contains("/odchan/") && !sources.contains("/desudrive/")) { + if (!sources.contains("/arcg/") && !sources.contains("/odchan/") && !sources.contains( + "/desudrive/" + ) + ) { sources = app.get(sources).document.select("iframe").attr("src") } if (sources.startsWith("https://yourupload.com")) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcofunProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcofunProvider.kt new file mode 100644 index 00000000..5a27a7ac --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcofunProvider.kt @@ -0,0 +1,172 @@ +package com.lagradost.cloudstream3.animeproviders + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import org.jsoup.Jsoup +import org.jsoup.nodes.Element + +class WcofunProvider : MainAPI() { + override var mainUrl = "https://www.wcofun.com" + override var name = "WCO Fun" + override val hasMainPage = true + override val hasDownloadSupport = true + + override val supportedTypes = setOf( + TvType.Anime, + TvType.AnimeMovie, + TvType.OVA + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(mainUrl).document + + val homePageList = ArrayList() + + document.select("div#sidebar_right,div#sidebar_right2").forEach { block -> + val header = block.previousElementSibling()?.ownText() ?: return@forEach + val animes = block.select("ul.items li").mapNotNull { + it.toSearchResult() + } + if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes)) + } + + return HomePageResponse(homePageList) + + } + + private fun getProperAnimeLink(uri: String): String { + return if (uri.contains("/anime/")) { + uri + } else { + var title = uri.substringAfter("$mainUrl/") + title = when { + (title.contains(Regex("-season-[0-9]+-episode"))) && title.contains("-dubbed") -> title.substringBefore("-season") + (title.contains(Regex("-season-[0-9]+-episode"))) && title.contains("-subbed") -> title.replace(Regex("-season-[0-9]+-episode-[0-9]+"), "") + title.contains("-subbed") -> title.replace(Regex("-episode-[0-9]+"), "") + title.contains("-dubbed") -> title.substringBefore("-episode") + else -> title + } + "$mainUrl/anime/$title" + } + } + + private fun Element.toSearchResult(): AnimeSearchResponse? { + val header = this.selectFirst("div.recent-release-episodes a")?.text() + val title = header?.trim() ?: return null + val href = getProperAnimeLink(this.selectFirst("a")!!.attr("href")) + val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src")) + val epNum = header.let { eps -> + Regex("Episode\\s?([0-9]+)").find(eps)?.groupValues?.getOrNull(1)?.toIntOrNull() + } + val isDub = header.contains("Dubbed") + val isSub = header.contains("Subbed") + return newAnimeSearchResponse(title, href, TvType.Anime) { + this.posterUrl = posterUrl + addDubStatus(isDub, isSub, epNum, epNum) + } + } + + override suspend fun search(query: String): List { + val document = app.post( + "$mainUrl/search", + referer = mainUrl, + data = mapOf("catara" to query, "konuara" to "series") + ).document + + return document.select("div#sidebar_right2 li").mapNotNull { + it.toSearchResult() + } + } + + override suspend fun load(url: String): LoadResponse? { + val document = app.get(url).document + val title = document.selectFirst("div.h1-tag a")?.text() ?: return null + val eps = document.select("div#sidebar_right3 div.cat-eps") + val type = if (eps.size == 1 || eps.first()?.text() + ?.contains(Regex("Episode\\s?[0-9]+")) != true + ) TvType.AnimeMovie else TvType.Anime + val episodes = eps.map { + val name = it.select("a").text() + val link = it.selectFirst("a")!!.attr("href") + Episode(link, name = name) + }.reversed() + + return newAnimeLoadResponse(title, url, type) { + posterUrl = fixUrlNull(document.selectFirst("img.img5")?.attr("src")) + addEpisodes(DubStatus.Subbed, episodes) + plot = document.select("div#sidebar_cat > p").text() + this.tags = document.select("div#sidebar_cat a").map { it.text() } + } + } + + private suspend fun getIframe(url: String): String? { + val document = app.get(url).document + val scriptData = + document.select("script").find { it.data().contains("= \"\";") }?.data() ?: return null + val subtractionNumber = + Regex("""(?<=\.replace\(/\\D/g,''\)\) - )\d+""").find(scriptData)?.value?.toInt() + ?: return null + val html = Regex("""(?<=\["|, ").+?(?=")""").findAll(scriptData).map { + val number = base64Decode(it.value).replace(Regex("\\D"), "").toInt() + (number - subtractionNumber).toChar() + }.joinToString("") + return Jsoup.parse(html).select("iframe").attr("src").let { fixUrl(it) } + } + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + + getIframe(data)?.let { iframe -> + val link = app.get(iframe, referer = data).text.let { + fixUrlNull( + Regex("\"(/inc/embed/getvidlink.php.*)\"").find(it)?.groupValues?.getOrNull( + 1 + ) + ) + } + app.get( + link ?: return@let, + referer = iframe, + headers = mapOf("x-requested-with" to "XMLHttpRequest") + ).parsedSafe()?.let { + listOf( + Pair(it.hd, "HD"), + Pair(it.enc, "SD") + ).map { source -> + suspendSafeApiCall { + callback.invoke( + ExtractorLink( + "${this.name} ${source.second}", + "${this.name} ${source.second}", + "${it.server}/getvid?evid=${source.first}", + mainUrl, + if (source.second == "HD") Qualities.P720.value else Qualities.P480.value + ) + ) + } + } + } + } + + return true + } + + data class Sources( + @JsonProperty("enc") val enc: String?, + @JsonProperty("server") val server: String?, + @JsonProperty("cdn") val cdn: String?, + @JsonProperty("hd") val hd: String?, + ) + + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt index 93466305..da3ef278 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt @@ -7,6 +7,10 @@ import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.M3u8Helper +class Ssbstream : StreamSB() { + override var mainUrl = "https://ssbstream.net" +} + class SBfull : StreamSB() { override var mainUrl = "https://sbfull.com" } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DramaidProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DramaidProvider.kt index 6a71d315..3a13e930 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DramaidProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DramaidProvider.kt @@ -8,7 +8,6 @@ import com.lagradost.cloudstream3.utils.getQualityFromName import com.lagradost.cloudstream3.utils.loadExtractor import org.jsoup.Jsoup import org.jsoup.nodes.Element -import java.util.ArrayList class DramaidProvider : MainAPI() { override var mainUrl = "https://185.224.83.103" @@ -30,20 +29,18 @@ class DramaidProvider : MainAPI() { } } - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "&status=&type=&order=update" to "Drama Terbaru", + "&order=latest" to "Baru Ditambahkan", + "&status=&type=&order=popular" to "Drama Popular", + ) - val homePageList = ArrayList() - - document.select(".bixbox").forEach { block -> - val header = block.selectFirst(".releases > h3")!!.text().trim() - val dramas = block.select("article[itemscope=itemscope]").mapNotNull { - it.toSearchResult() - } - if (dramas.isNotEmpty()) homePageList.add(HomePageList(header, dramas)) + override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { + val document = app.get("$mainUrl/series/?page=$page${request.data}").document + val home = document.select("article[itemscope=itemscope]").mapNotNull { + it.toSearchResult() } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } private fun getProperDramaLink(uri: String): String { @@ -55,10 +52,10 @@ class DramaidProvider : MainAPI() { } } - private fun Element.toSearchResult(): SearchResponse { + private fun Element.toSearchResult(): SearchResponse? { val href = getProperDramaLink(this.selectFirst("a.tip")!!.attr("href")) - val title = this.selectFirst("h2[itemprop=headline]")!!.text().trim() - val posterUrl = this.selectFirst(".limit > noscript > img")!!.attr("src") + val title = this.selectFirst("h2[itemprop=headline]")?.text()?.trim() ?: return null + val posterUrl = fixUrlNull(this.selectFirst(".limit > noscript > img")?.attr("src")) return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) { this.posterUrl = posterUrl diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DubokuProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DubokuProvider.kt new file mode 100644 index 00000000..ab89eba3 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DubokuProvider.kt @@ -0,0 +1,133 @@ +package com.lagradost.cloudstream3.movieproviders + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.LoadResponse.Companion.addActors +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper +import org.jsoup.nodes.Element + +class DubokuProvider : MainAPI() { + override var mainUrl = "https://www.duboku.tv" + override var name = "Duboku" + override val hasMainPage = true + override var lang = "zh" + override val hasDownloadSupport = true + override val supportedTypes = setOf( + TvType.Movie, + TvType.TvSeries, + TvType.AsianDrama, + ) + + override val mainPage = mainPageOf( + "$mainUrl/vodshow/2--time------" to "连续剧 时间", + "$mainUrl/vodshow/2--hits------" to "连续剧 人气", + "$mainUrl/vodshow/13--time------" to "陆剧 时间", + "$mainUrl/vodshow/13--hits------" to "陆剧 人气", + "$mainUrl/vodshow/15--time------" to "日韩剧 时间", + "$mainUrl/vodshow/15--hits------" to "日韩剧 人气", + "$mainUrl/vodshow/21--time------" to "短剧 时间", + "$mainUrl/vodshow/21--hits------" to "短剧 人气", + "$mainUrl/vodshow/16--time------" to "英美剧 时间", + "$mainUrl/vodshow/16--hits------" to "英美剧 人气", + "$mainUrl/vodshow/14--time------" to "台泰剧 时间", + "$mainUrl/vodshow/14--hits------" to "台泰剧 人气", + "$mainUrl/vodshow/20--time------" to "港剧 时间", + "$mainUrl/vodshow/20--hits------" to "港剧 人气", + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get("${request.data}$page---.html").document + val home = document.select("ul.myui-vodlist.clearfix li").mapNotNull { + it.toSearchResult() + } + return newHomePageResponse(request.name, home) + } + + private fun Element.toSearchResult(): SearchResponse? { + val title = this.selectFirst("h4.title a")?.text()?.trim() ?: return null + val href = fixUrl(this.selectFirst("a")?.attr("href").toString()) + val posterUrl = fixUrlNull(this.selectFirst("a")?.attr("data-original")) + val episode = this.selectFirst("span.pic-text.text-right")?.text()?.filter { it.isDigit() } + ?.toIntOrNull() + + return newAnimeSearchResponse(title, href, TvType.Movie) { + this.posterUrl = posterUrl + addSub(episode) + } + } + + override suspend fun search(query: String): List { + val document = app.get("$mainUrl/vodsearch/-------------.html?wd=$query&submit=").document + + return document.select("ul#searchList li").mapNotNull { + it.toSearchResult() + } + } + + override suspend fun load(url: String): LoadResponse? { + val document = app.get(url).document + + val title = document.selectFirst("h1.title")?.text()?.trim() ?: return null + val tvType = if (document.select("ul.myui-content__list li").size == 1 + ) TvType.Movie else TvType.TvSeries + val actors = document.select("p.data")[2].select("a").map { it.text() } + + val episodes = document.select("ul.myui-content__list li").map { + val href = fixUrl(it.select("a").attr("href")) + val name = it.select("a").text().trim() + Episode( + data = href, + name = name, + ) + } + return newTvSeriesLoadResponse(title, url, tvType, episodes) { + this.posterUrl = fixUrlNull( + document.selectFirst("a.myui-vodlist__thumb.picture img")?.attr("data-original") + ) + this.year = + document.select("p.data")[0].select("a").last()?.text()?.trim()?.toIntOrNull() + this.plot = document.selectFirst("span.sketch.content")?.text()?.trim() + this.tags = document.select("p.data")[0].select("a").map { it.text() } + this.rating = document.select("div#rating span.branch").text().toRatingInt() + addActors(actors) + } + + } + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + + app.get(data).document.select("script").map { script -> + if (script.data().contains("var player_data={")) { + val dataJson = + script.data().substringAfter("var player_data={").substringBefore("}") + tryParseJson("{$dataJson}")?.let { source -> + M3u8Helper.generateM3u8( + this.name, + source.url ?: return@map, + referer = "https://w.duboku.io/", + headers = mapOf("Origin" to "https://w.duboku.io") + ).forEach(callback) + } + } + } + + + return true + } + + data class Sources( + @JsonProperty("url") val url: String?, + ) + + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMovie5.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMovie5.kt index f17f3d11..c9ff743e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMovie5.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMovie5.kt @@ -6,6 +6,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.httpsify import com.lagradost.cloudstream3.utils.loadExtractor import org.jsoup.Jsoup +import org.jsoup.nodes.Element class HDMovie5 : MainAPI() { override var mainUrl = "https://hdmovie2.click" @@ -19,29 +20,27 @@ class HDMovie5 : MainAPI() { TvType.TvSeries, ) - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val doc = app.get(mainUrl).document.select("div.content") - val list = mapOf( - "Featured Movies" to "featured", - "Updated Movies" to "normal" - ) - return HomePageResponse(list.map { item -> - HomePageList(item.key, - doc.select("div.${item.value}>.item").map { - val data = it.select(".data") - val a = data.select("a") - MovieSearchResponse( - a.text(), - a.attr("href"), + override val mainPage = mainPageOf( + "$mainUrl/genre/tv-movie/page/" to "TV Movie", + "$mainUrl/genre/tv-show/page/" to "TV- Show", + "$mainUrl/genre/hindi-dubbed/page/" to "Hindi Dubbed", + "$mainUrl/genre/netflix/page/" to "NETFLIX", + ) - this.name, - TvType.Movie, - it.select("img").attr("src"), - data.select("span").text().toIntOrNull() - ) - } - ) - }) + override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { + val home = app.get(request.data + page).document.select("article.item").mapNotNull { + it.toSearchResult() + } + return newHomePageResponse(request.name, home) + } + + private fun Element.toSearchResult(): SearchResponse? { + val title = this.selectFirst("h3 > a")?.text()?.trim() ?: return null + val href = fixUrl(this.selectFirst("a")!!.attr("href")) + val posterUrl = this.selectFirst("img")?.attr("src") + return newMovieSearchResponse(title, href, TvType.Movie) { + addPoster(posterUrl) + } } private data class QuickSearchResponse( diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDrezkaProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDrezkaProvider.kt index 4fdd0dea..e88f86b9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDrezkaProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDrezkaProvider.kt @@ -28,27 +28,25 @@ class HDrezkaProvider : MainAPI() { TvType.AsianDrama ) - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { + override val mainPage = mainPageOf( + "$mainUrl/films/?filter=watching" to "фильмы", + "$mainUrl/series/?filter=watching" to "сериалы", + "$mainUrl/cartoons/?filter=watching" to "мультфильмы", + "$mainUrl/animation/?filter=watching" to "аниме", + ) - val items = ArrayList() - - listOf( - Pair("фильмы", "$mainUrl/films/?filter=watching"), - Pair("сериалы", "$mainUrl/series/?filter=watching"), - Pair("мультфильмы", "$mainUrl/cartoons/?filter=watching"), - Pair("аниме", "$mainUrl/animation/?filter=watching"), - ).apmap { (header, url) -> - safeApiCall { - val home = app.get(url).document.select( - "div.b-content__inline_items div.b-content__inline_item" - ).map { - it.toSearchResult() - } - items.add(HomePageList(fixTitle(header), home)) - } + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val url = request.data.split("?") + val home = app.get("${url.first()}page/$page/?${url.last()}").document.select( + "div.b-content__inline_items div.b-content__inline_item" + ).map { + it.toSearchResult() } - if (items.size <= 0) throw ErrorLoadingException() - return HomePageResponse(items) + + return newHomePageResponse(request.name, home) } private fun Element.toSearchResult(): SearchResponse { diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/IdlixProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/IdlixProvider.kt index fc5f6aa2..fe9aaa10 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/IdlixProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/IdlixProvider.kt @@ -22,22 +22,25 @@ class IdlixProvider : MainAPI() { TvType.TvSeries, ) - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/trending/page/?get=movies" to "Trending Movies", + "$mainUrl/trending/page/?get=tv" to "Trending TV Series", + "$mainUrl/movie/page/" to "Movie Terbaru", + "$mainUrl/tvseries/page/" to "TV Series Terbaru", + "$mainUrl/season/page/" to "Season Terbaru", + "$mainUrl/episode/page/" to "Episode Terbaru", + ) - val homePageList = ArrayList() - - document.select("div.items").forEach { block -> - val header = - fixTitle(block.previousElementSibling()?.previousElementSibling()?.select("header > h2") - ?.text()!!.trim()) - val items = block.select("article.item").mapNotNull { - it.toSearchResult() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val url = request.data.split("?") + val document = app.get("${url.first()}$page/?${url.lastOrNull()}").document + val home = document.select("article").mapNotNull { + it.toSearchResult() } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } private fun getProperLink(uri: String): String { @@ -75,7 +78,8 @@ class IdlixProvider : MainAPI() { val document = app.get(link).document return document.select("div.result-item").map { - val title = it.selectFirst("div.title > a")!!.text().replace(Regex("\\(\\d{4}\\)"), "").trim() + val title = + it.selectFirst("div.title > a")!!.text().replace(Regex("\\(\\d{4}\\)"), "").trim() val href = getProperLink(it.selectFirst("div.title > a")!!.attr("href")) val posterUrl = it.selectFirst("img")!!.attr("src").toString() newMovieSearchResponse(title, href, TvType.TvSeries) { @@ -87,7 +91,9 @@ class IdlixProvider : MainAPI() { override suspend fun load(url: String): LoadResponse { val document = app.get(url).document - val title = document.selectFirst("div.data > h1")?.text()?.replace(Regex("\\(\\d{4}\\)"), "")?.trim().toString() + val title = + document.selectFirst("div.data > h1")?.text()?.replace(Regex("\\(\\d{4}\\)"), "") + ?.trim().toString() val poster = document.select("div.poster > img").attr("src").toString() val tags = document.select("div.sgeneros > a").map { it.text() } @@ -157,7 +163,8 @@ class IdlixProvider : MainAPI() { private fun getLanguage(str: String): String { return when { - str.lowercase().contains("indonesia") || str.lowercase().contains("bahasa") -> "Indonesian" + str.lowercase().contains("indonesia") || str.lowercase() + .contains("bahasa") -> "Indonesian" else -> str } } @@ -203,7 +210,8 @@ class IdlixProvider : MainAPI() { document.select("script").map { script -> if (script.data().contains("eval(function(p,a,c,k,e,d)")) { - val subData = getAndUnpack(script.data()).substringAfter("\"tracks\":[").substringBefore("],") + val subData = + getAndUnpack(script.data()).substringAfter("\"tracks\":[").substringBefore("],") tryParseJson>("[$subData]")?.map { subtitle -> subCallback.invoke( SubtitleFile( diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/KisskhProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/KisskhProvider.kt new file mode 100644 index 00000000..b914dee8 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/KisskhProvider.kt @@ -0,0 +1,204 @@ +package com.lagradost.cloudstream3.movieproviders + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.mvvm.safeApiCall +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.AppUtils.toJson +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper +import com.lagradost.cloudstream3.utils.loadExtractor +import java.util.ArrayList + +class KisskhProvider : MainAPI() { + override var mainUrl = "https://kisskh.me" + override var name = "Kisskh" + override val hasMainPage = true + override val hasDownloadSupport = true + override val supportedTypes = setOf( + TvType.AsianDrama, + TvType.Anime + ) + + override val mainPage = mainPageOf( + "&type=2&sub=0&country=2&status=0&order=1" to "Movie Pupular", + "&type=2&sub=0&country=2&status=0&order=2" to "Movie Last Update", + "&type=1&sub=0&country=2&status=0&order=1" to "TVSeries Popular", + "&type=1&sub=0&country=2&status=0&order=2" to "TVSeries Last Update", + "&type=3&sub=0&country=0&status=0&order=1" to "Anime Popular", + "&type=3&sub=0&country=0&status=0&order=2" to "Anime Last Update", + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val home = app.get("$mainUrl/api/DramaList/List?page=$page${request.data}") + .parsedSafe()?.data + ?.mapNotNull { media -> + media.toSearchResponse() + } ?: throw ErrorLoadingException("Invalid Json reponse") + return newHomePageResponse(request.name, home) + } + + private fun Media.toSearchResponse(): SearchResponse? { + + return newAnimeSearchResponse( + title ?: return null, + "$title/$id", + TvType.TvSeries, + ) { + this.posterUrl = thumbnail + addSub(episodesCount) + } + } + + override suspend fun search(query: String): List { + val searchResponse = app.get("$mainUrl/api/DramaList/Search?q=$query&type=0", referer = "$mainUrl/").text + return tryParseJson>(searchResponse)?.mapNotNull { media -> + media.toSearchResponse() + } ?: throw ErrorLoadingException("Invalid Json reponse") + } + + private fun getTitle(str: String): String { + return str.replace(Regex("[^a-zA-Z0-9]"), "-") + } + + override suspend fun load(url: String): LoadResponse? { + val id = url.split("/") + val res = app.get( + "$mainUrl/api/DramaList/Drama/${id.last()}?isq=false", + referer = "$mainUrl/Drama/${ + getTitle(id.first()) + }?id=${id.last()}" + ).parsedSafe() + ?: throw ErrorLoadingException("Invalid Json reponse") + + val episodes = res.episodes?.map { eps -> + Episode( + data = Data(res.title, eps.number, res.id, eps.id).toJson(), + episode = eps.number + ) + } ?: throw ErrorLoadingException("No Episode") + + return newTvSeriesLoadResponse( + res.title ?: return null, + url, + if (res.type == "Movie" || episodes.size == 1) TvType.Movie else TvType.TvSeries, + episodes + ) { + this.posterUrl = res.thumbnail + this.year = res.releaseDate?.split("-")?.first()?.toIntOrNull() + this.plot = res.description + this.tags = listOf("${res.country}", "${res.status}", "${res.type}") + this.showStatus = when (res.status) { + "Completed" -> ShowStatus.Completed + "Ongoing" -> ShowStatus.Ongoing + else -> null + } + } + + } + + private fun getLanguage(str: String): String { + return when (str) { + "Indonesia" -> "Indonesian" + else -> str + } + } + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + + val loadData = parseJson(data) + + app.get( + "$mainUrl/api/DramaList/Episode/${loadData.epsId}.png?err=false&ts=&time=", + referer = "$mainUrl/Drama/${getTitle("${loadData.title}")}/Episode-${loadData.eps}?id=${loadData.id}&ep=${loadData.epsId}&page=0&pageSize=100" + ).parsedSafe()?.let { source -> + listOf(source.video, source.thirdParty).apmap { link -> + safeApiCall { + if (link?.contains(".m3u8") == true) { + M3u8Helper.generateM3u8( + this.name, + link, + referer = "$mainUrl/", + headers = mapOf("Origin" to mainUrl) + ).forEach(callback) + } else { + loadExtractor( + link?.substringBefore("=http") ?: return@safeApiCall, + "$mainUrl/", + subtitleCallback, + callback + ) + } + } + } + } + + app.get("$mainUrl/api/Sub/${loadData.epsId}").parsedSafe>()?.map { sub -> + subtitleCallback.invoke( + SubtitleFile( + getLanguage(sub.label ?: return@map), + sub.src ?: return@map + ) + ) + } + + return true + + } + + data class Data( + val title: String?, + val eps: Int?, + val id: Int?, + val epsId: Int?, + ) + + data class Sources( + @JsonProperty("Video") val video: String?, + @JsonProperty("ThirdParty") val thirdParty: String?, + ) + + data class Subtitle( + @JsonProperty("src") val src: String?, + @JsonProperty("label") val label: String?, + ) + + data class Responses( + @JsonProperty("data") val data: ArrayList? = arrayListOf(), + ) + + data class Media( + @JsonProperty("episodesCount") val episodesCount: Int?, + @JsonProperty("thumbnail") val thumbnail: String?, + @JsonProperty("id") val id: Int?, + @JsonProperty("title") val title: String?, + ) + + data class Episodes( + @JsonProperty("id") val id: Int?, + @JsonProperty("number") val number: Int?, + @JsonProperty("sub") val sub: Int?, + ) + + data class MediaDetail( + @JsonProperty("description") val description: String?, + @JsonProperty("releaseDate") val releaseDate: String?, + @JsonProperty("status") val status: String?, + @JsonProperty("type") val type: String?, + @JsonProperty("country") val country: String?, + @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), + @JsonProperty("thumbnail") val thumbnail: String?, + @JsonProperty("id") val id: Int?, + @JsonProperty("title") val title: String?, + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LayarKacaProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LayarKacaProvider.kt index acd96081..bf3c90f9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LayarKacaProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LayarKacaProvider.kt @@ -7,7 +7,6 @@ import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.loadExtractor import org.jsoup.Jsoup import org.jsoup.nodes.Element -import java.util.* class LayarKacaProvider : MainAPI() { override var mainUrl = "https://lk21.xn--6frz82g" @@ -21,90 +20,33 @@ class LayarKacaProvider : MainAPI() { TvType.AsianDrama ) - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/populer/page/" to "Film Terplopuler", + "$mainUrl/latest-series/page/" to "Series Terbaru", + "$mainUrl/series/asian/page/" to "Film Asian Terbaru", + "$mainUrl/latest/page/" to "Film Upload Terbaru", + ) - val homePageList = ArrayList() - - document.select("section.hot-block,section#newseries").forEach { block -> - val header = fixTitle(block.select("footer.load-more > a").text().trim()) - val items = block.select("div.slider-item").mapNotNull { - it.toTopSearchResult() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document + val home = document.select("article.mega-item").mapNotNull { + it.toSearchResult() } - - document.select("div#newest").forEach { block -> - val header = fixTitle(block.select(".header > h2 > a").text()) - val items = block.select("div.item").mapNotNull { - it.toMainSearchResult() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) - } - - document.select("section#recomendation,section#populer,section#seriespopuler") - .forEach { block -> - val header = fixTitle(block.select(".header > h2 > a").text()) - val items = block.select("div.item").mapNotNull { - it.toBottomSearchResult() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) - } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } - private fun Element.toTopSearchResult(): SearchResponse { - val title = this.selectFirst("h3.caption")!!.text().trim() - val href = this.selectFirst("a")!!.attr("href") - val posterUrl = fixUrl(this.selectFirst("a > img")?.attr("src").toString()) - val type = - if (this.select("div.quality-top").isNotEmpty()) TvType.Movie else TvType.TvSeries - return if (type == TvType.Movie) { - val quality = getQualityFromString(this.select("div.quality-top").text().trim()) - newMovieSearchResponse(title, href, TvType.Movie) { - this.posterUrl = posterUrl - this.quality = quality - } - } else { - val episode = this.select("div.last-episode > span").text().toIntOrNull() - newAnimeSearchResponse(title, href, TvType.TvSeries) { - this.posterUrl = posterUrl - addSub(episode) - } - } - - } - - private fun Element.toMainSearchResult(): SearchResponse { - val title = this.selectFirst("h3.caption")!!.text().trim() - val href = this.selectFirst("a")!!.attr("href") - val posterUrl = fixUrl(this.select("a > img").attr("src").toString()) - val quality = getQualityFromString(this.select("div.quality-top").text().trim()) + private fun Element.toSearchResult(): SearchResponse? { + val title = this.selectFirst("h1.grid-title > a")?.ownText()?.trim() ?: return null + val href = fixUrl(this.selectFirst("h1.grid-title > a")!!.attr("href")) + val posterUrl = fixUrlNull(this.selectFirst(".grid-poster > a > img")?.attr("src")) + val quality = this.select("div.quality").text().trim() return newMovieSearchResponse(title, href, TvType.Movie) { this.posterUrl = posterUrl - this.quality = quality + addQuality(quality) } - - } - - private fun Element.toBottomSearchResult(): SearchResponse { - val title = this.selectFirst("h1.grid-title > a")!!.ownText().trim() - val href = this.selectFirst("h1.grid-title > a")!!.attr("href") - val posterUrl = fixUrl(this.selectFirst(".grid-poster > a > img")?.attr("src").toString()) - val type = if (this.select("div.quality").isNotEmpty()) TvType.Movie else TvType.TvSeries - return if (type == TvType.Movie) { - val quality = getQualityFromString(this.select("div.quality").text().trim()) - return newMovieSearchResponse(title, href, TvType.Movie) { - this.posterUrl = posterUrl - this.quality = quality - } - } else { - newTvSeriesSearchResponse(title, href, TvType.TvSeries) { - this.posterUrl = posterUrl - } - } - } override suspend fun search(query: String): List { @@ -138,12 +80,14 @@ class LayarKacaProvider : MainAPI() { val trailer = document.selectFirst("div.action-player li > a.fancybox")?.attr("href") val rating = document.selectFirst("div.content > div:nth-child(6) > h3")?.text()?.toRatingInt() - val actors = document.select("div.col-xs-9.content > div:nth-child(3) > h3 > a").map { it.text() } + val actors = + document.select("div.col-xs-9.content > div:nth-child(3) > h3 > a").map { it.text() } val recommendations = document.select("div.row.item-media").map { val recName = it.selectFirst("h3")?.text()?.trim().toString() val recHref = it.selectFirst(".content-media > a")!!.attr("href") - val recPosterUrl = fixUrl(it.selectFirst(".poster-media > a > img")?.attr("src").toString()) + val recPosterUrl = + fixUrl(it.selectFirst(".poster-media > a > img")?.attr("src").toString()) newTvSeriesSearchResponse(recName, recHref, TvType.TvSeries) { this.posterUrl = recPosterUrl } @@ -172,8 +116,7 @@ class LayarKacaProvider : MainAPI() { this.recommendations = recommendations addTrailer(trailer) } - } - else { + } else { newMovieLoadResponse(title, url, TvType.Movie, url) { this.posterUrl = poster this.year = year @@ -196,10 +139,11 @@ class LayarKacaProvider : MainAPI() { val document = app.get(data).document - val sources = if(data.contains("-episode-")) { + val sources = if (data.contains("-episode-")) { document.select("script").mapNotNull { script -> - if(script.data().contains("var data =")) { - val scriptData = script.toString().substringAfter("var data = '").substringBefore("';") + if (script.data().contains("var data =")) { + val scriptData = + script.toString().substringAfter("var data = '").substringBefore("';") Jsoup.parse(scriptData).select("li").map { fixUrl(it.select("a").attr("href")) } @@ -214,7 +158,7 @@ class LayarKacaProvider : MainAPI() { } sources.apmap { - val link = if(it.startsWith("https://layarkacaxxi.icu")) { + val link = if (it.startsWith("https://layarkacaxxi.icu")) { it.substringBeforeLast("/") } else { it diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MultiplexProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MultiplexProvider.kt index 12729bc9..9d5a60c0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MultiplexProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MultiplexProvider.kt @@ -8,7 +8,6 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.getQualityFromName import org.jsoup.nodes.Element -import java.util.ArrayList class MultiplexProvider : MainAPI() { override var mainUrl = "https://146.19.24.137" @@ -22,45 +21,30 @@ class MultiplexProvider : MainAPI() { TvType.AsianDrama ) - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/genre/top-popular-movies/page/" to "Top Popolar Movies", + "$mainUrl/genre/series-ongoing/page/" to "Series Ongoing", + "$mainUrl/genre/series-barat/page/" to "Series Barat", + "$mainUrl/genre/series-korea/page/" to "Series Korea", + ) - val homePageList = ArrayList() - - document.select("div.col-md-12 > div.home-widget").forEach { block -> - val header = fixTitle(block.select("h3.homemodule-title").text()) - val items = block.select("div.col-md-125").mapNotNull { - it.toSearchResult() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document + val home = document.select("article.item").mapNotNull { + it.toSearchResult() } - - document.select("div.container.gmr-maincontent") - .forEach { block -> - val header = fixTitle(block.select("h3.homemodule-title").text()) - val items = block.select("article.item").mapNotNull { - it.toSearchResult() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) - } - - document.select("div#idmuvi-rp-2").forEach { block -> - val header = fixTitle(block.selectFirst("h3.widget-title")?.ownText()!!.trim()) - val items = block.select("div.idmuvi-rp ul li").mapNotNull { - it.toBottomSearchResult() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) - } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } - private fun Element.toSearchResult(): SearchResponse { - val title = this.selectFirst("h2.entry-title > a")!!.text().trim() - val href = this.selectFirst("a")!!.attr("href") - val posterUrl = fixUrl(this.selectFirst("a > img")?.attr("data-src").toString()) - val quality = getQualityFromString(this.select("div.gmr-quality-item > a").text().trim()) - return if (quality == null) { + private fun Element.toSearchResult(): SearchResponse? { + val title = this.selectFirst("h2.entry-title > a")?.text()?.trim() ?: return null + val href = fixUrl(this.selectFirst("a")!!.attr("href")) + val posterUrl = fixUrlNull(this.selectFirst("a > img")?.attr("data-src")) + val quality = this.select("div.gmr-quality-item > a").text().trim() + return if (quality.isEmpty()) { val episode = this.select("div.gmr-numbeps > span").text().toIntOrNull() newAnimeSearchResponse(title, href, TvType.TvSeries) { this.posterUrl = posterUrl @@ -69,27 +53,24 @@ class MultiplexProvider : MainAPI() { } else { newMovieSearchResponse(title, href, TvType.Movie) { this.posterUrl = posterUrl - this.quality = quality + addQuality(quality) } } - } - private fun Element.toBottomSearchResult(): SearchResponse { - val title = this.selectFirst("a > span.idmuvi-rp-title")!!.text().trim() + private fun Element.toBottomSearchResult(): SearchResponse? { + val title = this.selectFirst("a > span.idmuvi-rp-title")?.text()?.trim() ?: return null val href = this.selectFirst("a")!!.attr("href") val posterUrl = fixUrl(this.selectFirst("a > img")?.attr("data-src").toString()) return newMovieSearchResponse(title, href, TvType.Movie) { this.posterUrl = posterUrl } - } override suspend fun search(query: String): List { val link = "$mainUrl/?s=$query&post_type[]=post&post_type[]=tv" val document = app.get(link).document - - return document.select("div#gmr-main-load > article.item").map { + return document.select("article.item").mapNotNull { it.toSearchResult() } } @@ -112,9 +93,10 @@ class MultiplexProvider : MainAPI() { val rating = document.selectFirst("div.gmr-meta-rating > span[itemprop=ratingValue]")?.text() ?.toRatingInt() - val actors = document.select("div.gmr-moviedata").last()?.select("span[itemprop=actors]")?.map { it.select("a").text() } + val actors = document.select("div.gmr-moviedata").last()?.select("span[itemprop=actors]") + ?.map { it.select("a").text() } - val recommendations = document.select("div.idmuvi-rp ul li").map { + val recommendations = document.select("div.idmuvi-rp ul li").mapNotNull { it.toBottomSearchResult() } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PhimmoichillProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PhimmoichillProvider.kt index 10b02d4e..fc8be422 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PhimmoichillProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PhimmoichillProvider.kt @@ -23,20 +23,25 @@ class PhimmoichillProvider : MainAPI() { TvType.AsianDrama ) - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/genre/phim-chieu-rap/page-" to "Phim Chiếu Rạp", + "$mainUrl/list/phim-le/page-" to "Phim Lẻ", + "$mainUrl/list/phim-bo/page-" to "Phim Bộ", + "$mainUrl/genre/phim-hoat-hinh/page-" to "Phim Hoạt Hình", + "$mainUrl/country/phim-han-quoc/page-" to "Phim Hàn Quốc", + "$mainUrl/country/phim-trung-quoc/page-" to "Phim Trung Quốc", + "$mainUrl/country/phim-thai-lan/page-" to "Phim Thái Lan", + ) - val homePageList = ArrayList() - - document.select("div.container div.block").forEach { block -> - val header = fixTitle(block.selectFirst("h2")!!.text()) - val items = block.select("li.item").mapNotNull { - it.toSearchResult() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document + val home = document.select("li.item").mapNotNull { + it.toSearchResult() } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } private fun decode(input: String): String? = URLDecoder.decode(input, "utf-8") @@ -176,11 +181,11 @@ class PhimmoichillProvider : MainAPI() { } else { val playList = app.get(link, referer = "$mainUrl/") .parsedSafe()?.main?.segments?.map { segment -> - PlayListItem( - segment.link, - (segment.du.toFloat() * 1_000_000).toLong() - ) - } + PlayListItem( + segment.link, + (segment.du.toFloat() * 1_000_000).toLong() + ) + } callback.invoke( ExtractorLinkPlayList( diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/RebahinProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/RebahinProvider.kt index f85aac91..2ba1c78e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/RebahinProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/RebahinProvider.kt @@ -15,7 +15,7 @@ import org.jsoup.nodes.Element import java.net.URI class RebahinProvider : MainAPI() { - override var mainUrl = "http://167.88.14.149" + override var mainUrl = "http://104.237.198.194" override var name = "Rebahin" override val hasMainPage = true override var lang = "id" diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/UakinoProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/UakinoProvider.kt index 51573433..720b8d18 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/UakinoProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/UakinoProvider.kt @@ -23,20 +23,24 @@ class UakinoProvider : MainAPI() { TvType.Anime ) - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/filmy/page/" to "Фільми", + "$mainUrl/seriesss/page/" to "Серіали", + "$mainUrl/seriesss/doramy/page/" to "Дорами", + "$mainUrl/animeukr/page/" to "Аніме", + "$mainUrl/cartoon/page/" to "Мультфільми", + "$mainUrl/cartoon/cartoonseries/page/" to "Мультсеріали", + ) - val homePageList = ArrayList() - - document.select("div.main-section-inner").forEach { block -> - val header = block.selectFirst("p.sidebar-title")?.text()?.trim().toString() - val items = block.select("div.owl-item, div.movie-item").map { - it.toSearchResponse() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document + val home = document.select("div.owl-item, div.movie-item").map { + it.toSearchResponse() } - - return HomePageResponse(homePageList) + return newHomePageResponse(request.name, home) } private fun Element.toSearchResponse(): SearchResponse { @@ -70,7 +74,8 @@ class UakinoProvider : MainAPI() { val poster = fixUrl(document.selectFirst("div.film-poster img")?.attr("src").toString()) val tags = document.select("div.film-info > div:nth-child(4) a").map { it.text() } val year = document.select("div.film-info > div:nth-child(2) a").text().toIntOrNull() - val tvType = if (url.contains(Regex("(/anime-series)|(/seriesss)|(/cartoonseries)"))) TvType.TvSeries else TvType.Movie + val tvType = + if (url.contains(Regex("(/anime-series)|(/seriesss)|(/cartoonseries)"))) TvType.TvSeries else TvType.Movie val description = document.selectFirst("div[itemprop=description]")?.text()?.trim() val trailer = document.selectFirst("iframe#pre")?.attr("data-src") val rating = document.selectFirst("div.film-info > div:nth-child(8) div.fi-desc")?.text() @@ -83,21 +88,22 @@ class UakinoProvider : MainAPI() { return if (tvType == TvType.TvSeries) { val id = url.split("/").last().split("-").first() - val episodes = app.get("$mainUrl/engine/ajax/playlists.php?news_id=$id&xfield=playlist&time=${Date().time}") - .parsedSafe()?.response.let { - Jsoup.parse(it.toString()).select("ul > li").mapNotNull { eps -> - val href = fixUrl(eps.attr("data-file")) - val name = eps.text().trim() - if (href.isNotEmpty()) { - Episode( - href, - name, - ) - } else { - null + val episodes = + app.get("$mainUrl/engine/ajax/playlists.php?news_id=$id&xfield=playlist&time=${Date().time}") + .parsedSafe()?.response.let { + Jsoup.parse(it.toString()).select("ul > li").mapNotNull { eps -> + val href = fixUrl(eps.attr("data-file")) + val name = eps.text().trim() + if (href.isNotEmpty()) { + Episode( + href, + name, + ) + } else { + null + } } } - } newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) { this.posterUrl = poster this.year = year diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/YomoviesProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/YomoviesProvider.kt index ef465701..3b93f571 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/YomoviesProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/YomoviesProvider.kt @@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor import org.jsoup.nodes.Element class YomoviesProvider : MainAPI() { - override var mainUrl = "https://yomovies.vip" + override var mainUrl = "https://yomovies.skin" override var name = "Yomovies" override val hasMainPage = true override var lang = "hi" @@ -19,21 +19,25 @@ class YomoviesProvider : MainAPI() { TvType.TvSeries, ) - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val document = app.get(mainUrl).document + override val mainPage = mainPageOf( + "$mainUrl/most-favorites/page/" to "Most Viewed", + "$mainUrl/genre/web-series/page/" to "Web Series Movies", + "$mainUrl/genre/dual-audio/page/" to "Dual Audio Movies", + "$mainUrl/genre/bollywood/page/" to "Bollywood Movies", + "$mainUrl/genre/tv-shows/page/" to "TV Shows Movies", + "$mainUrl/genre/hollywood/page/" to "Hollywood Movies", + "$mainUrl/series/page/" to "All TV Series", + ) - val homePageList = ArrayList() - - document.select("div.movies-list-wrap.mlw-topview,div.movies-list-wrap.mlw-latestmovie") - .forEach { block -> - val header = fixTitle(block.selectFirst("div.ml-title span")?.text() ?: "") - val items = block.select("div.ml-item").mapNotNull { - it.toSearchResult() - } - if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) - } - - return HomePageResponse(homePageList) + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = 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? { @@ -63,8 +67,9 @@ class YomoviesProvider : MainAPI() { 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 - ) TvType.Movie else TvType.TvSeries + ?.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() @@ -74,14 +79,25 @@ class YomoviesProvider : MainAPI() { } return if (tvType == TvType.TvSeries) { - val episodes = document.select("div.les-content a").map { - val href = it.attr("href") - val name = it.text().trim() - Episode( - data = href, - name = name, - ) + 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(), + ) + } + } else { + document.select("div.les-content a").map { + Episode( + data = it.attr("href"), + name = it.text().trim(), + ) + } } + newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) { this.posterUrl = poster this.year = year @@ -113,26 +129,30 @@ class YomoviesProvider : MainAPI() { callback: (ExtractorLink) -> Unit ): Boolean { - 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) + 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/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt index 79275c50..a1f1ae25 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -232,6 +232,7 @@ val extractorApis: Array = arrayOf( SBfull(), // Streamhub(), cause Streamhub2() works Streamhub2(), + Ssbstream(), FEmbed(), FeHD(), diff --git a/docs/providers.json b/docs/providers.json index 32a48763..52fbe54d 100644 --- a/docs/providers.json +++ b/docs/providers.json @@ -177,6 +177,12 @@ "status": 1, "url": "https://bestdubbedanime.com" }, + "DubokuProvider": { + "language": "zh", + "name": "Duboku", + "status": 1, + "url": "https://www.duboku.tv" + }, "EgyBestProvider": { "language": "ar", "name": "EgyBest", @@ -308,6 +314,12 @@ "status": 1, "url": "https://kimcartoon.li" }, + "KisskhProvider": { + "language": "en", + "name": "Kisskh", + "status": 1, + "url": "https://kisskh.me" + }, "KuramanimeProvider": { "language": "id", "name": "Kuramanime", @@ -466,7 +478,7 @@ "language": "id", "name": "Rebahin", "status": 1, - "url": "http://167.88.14.149" + "url": "http://104.237.198.194" }, "SeriesflixProvider": { "language": "es", @@ -594,6 +606,12 @@ "status": 1, "url": "https://wcostream.cc" }, + "WcofunProvider": { + "language": "en", + "name": "WCO Fun", + "status": 1, + "url": "https://www.wcofun.com" + }, "XcineProvider": { "language": "de", "name": "Xcine", @@ -604,7 +622,7 @@ "language": "hi", "name": "Yomovies", "status": 1, - "url": "https://yomovies.vip" + "url": "https://yomovies.skin" }, "ZoroProvider": { "language": "en",