forked from recloudstream/cloudstream
		
	Added Inf home to some providers and new providers (#1377)
* The Boys!! * Prikitieww...
This commit is contained in:
		
							parent
							
								
									c5406acc1e
								
							
						
					
					
						commit
						df509dfe1b
					
				
					 25 changed files with 938 additions and 477 deletions
				
			
		|  | @ -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(), | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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()) | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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 { | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         for ((payload, name) in urls) { | ||||
|             try { | ||||
|                 val home = Jsoup.parse( | ||||
|                     parseJson<Response>( | ||||
|                         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<Response>()?.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? | ||||
|     ) | ||||
| 
 | ||||
| } | ||||
|  | @ -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<HomePageList>() | ||||
|     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<SearchResponse> { | ||||
|         val link = "$mainUrl/anime?search=$query&order_by=oldest" | ||||
|         val document = app.get(link).document | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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() | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
|          | ||||
|         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 | ||||
|  |  | |||
|  | @ -228,7 +228,7 @@ class NontonAnimeIDProvider : MainAPI() { | |||
|         val document = app.get(data).document | ||||
|         val sources = ArrayList<String>() | ||||
| 
 | ||||
|         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)) | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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() | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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")) { | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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<SearchResponse> { | ||||
|         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<Sources>()?.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?, | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -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" | ||||
| } | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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 | ||||
|  |  | |||
|  | @ -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<SearchResponse> { | ||||
|         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<Sources>("{$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?, | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -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( | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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 { | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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<List<Tracks>>("[$subData]")?.map { subtitle -> | ||||
|                     subCallback.invoke( | ||||
|                         SubtitleFile( | ||||
|  |  | |||
|  | @ -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<Responses>()?.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<SearchResponse> { | ||||
|         val searchResponse = app.get("$mainUrl/api/DramaList/Search?q=$query&type=0", referer = "$mainUrl/").text | ||||
|         return tryParseJson<ArrayList<Media>>(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<MediaDetail>() | ||||
|             ?: 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>(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<Sources>()?.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<List<Subtitle>>()?.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<Media>? = 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<Episodes>? = arrayListOf(), | ||||
|         @JsonProperty("thumbnail") val thumbnail: String?, | ||||
|         @JsonProperty("id") val id: Int?, | ||||
|         @JsonProperty("title") val title: String?, | ||||
|     ) | ||||
| 
 | ||||
| } | ||||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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<SearchResponse> { | ||||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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<SearchResponse> { | ||||
|         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() | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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<ResponseM3u>()?.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( | ||||
|  |  | |||
|  | @ -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" | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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<Responses>()?.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<Responses>()?.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 | ||||
|  |  | |||
|  | @ -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<HomePageList>() | ||||
| 
 | ||||
|         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 | ||||
|     } | ||||
|  |  | |||
|  | @ -232,6 +232,7 @@ val extractorApis: Array<ExtractorApi> = arrayOf( | |||
|     SBfull(), | ||||
|     // Streamhub(), cause Streamhub2() works | ||||
|     Streamhub2(), | ||||
|     Ssbstream(), | ||||
| 
 | ||||
|     FEmbed(), | ||||
|     FeHD(), | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue