mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge branch 'master' of https://github.com/LagradOst/CloudStream-3
This commit is contained in:
commit
8076bc0332
26 changed files with 958 additions and 479 deletions
|
@ -109,7 +109,8 @@ object APIHolder {
|
||||||
PhimmoichillProvider(),
|
PhimmoichillProvider(),
|
||||||
HDrezkaProvider(),
|
HDrezkaProvider(),
|
||||||
YomoviesProvider(),
|
YomoviesProvider(),
|
||||||
|
DubokuProvider(),
|
||||||
|
KisskhProvider(),
|
||||||
|
|
||||||
// Metadata providers
|
// Metadata providers
|
||||||
//TmdbProvider(),
|
//TmdbProvider(),
|
||||||
|
@ -148,6 +149,7 @@ object APIHolder {
|
||||||
AnimeIndoProvider(),
|
AnimeIndoProvider(),
|
||||||
AnimeSailProvider(),
|
AnimeSailProvider(),
|
||||||
TocanimeProvider(),
|
TocanimeProvider(),
|
||||||
|
WcofunProvider(),
|
||||||
//MultiAnimeProvider(),
|
//MultiAnimeProvider(),
|
||||||
NginxProvider(),
|
NginxProvider(),
|
||||||
OlgplyProvider(),
|
OlgplyProvider(),
|
||||||
|
|
|
@ -62,20 +62,20 @@ class AnimeIndoProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = request(mainUrl).document
|
"$mainUrl/anime-terbaru/page/" to "Anime Terbaru",
|
||||||
|
"$mainUrl/donghua-terbaru/page/" to "Donghua Terbaru"
|
||||||
|
)
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
document.select("div.widget_senction").forEach { block ->
|
request: MainPageRequest
|
||||||
val header = block.selectFirst("div.widget-title > h3")!!.text().trim()
|
): HomePageResponse {
|
||||||
val items = block.select("div.post-show > article").map {
|
val document = request(request.data + page).document
|
||||||
|
val home = document.select("div.post-show > article").mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (items.isNotEmpty()) homePageList.add(HomePageList(header, items))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
|
||||||
|
|
||||||
return HomePageResponse(homePageList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getProperAnimeLink(uri: String): String {
|
private fun getProperAnimeLink(uri: String): String {
|
||||||
|
@ -96,8 +96,8 @@ class AnimeIndoProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Element.toSearchResult(): AnimeSearchResponse {
|
private fun Element.toSearchResult(): AnimeSearchResponse? {
|
||||||
val title = this.selectFirst("div.title")!!.text().trim()
|
val title = this.selectFirst("div.title")?.text()?.trim() ?: return null
|
||||||
val href = getProperAnimeLink(this.selectFirst("a")!!.attr("href"))
|
val href = getProperAnimeLink(this.selectFirst("a")!!.attr("href"))
|
||||||
val posterUrl = this.select("img[itemprop=image]").attr("src").toString()
|
val posterUrl = this.select("img[itemprop=image]").attr("src").toString()
|
||||||
val type = getType(this.select("div.type").text().trim())
|
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 {
|
override val mainPage = mainPageOf(
|
||||||
val document = request(mainUrl).document
|
"$mainUrl/page/" to "Episode Terbaru",
|
||||||
|
"$mainUrl/movie-terbaru/page/" to "Movie Terbaru",
|
||||||
|
"$mainUrl/genres/donghua/page/" to "Donghua"
|
||||||
|
)
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||||
|
val document = request(request.data + page).document
|
||||||
document.select(".bixbox").forEach { block ->
|
val home = document.select("article").map {
|
||||||
val header = block.select(".releases > h3").text().trim()
|
|
||||||
val animes = block.select("article").map {
|
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
|
||||||
|
|
||||||
return HomePageResponse(homePageList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getProperAnimeLink(uri: String): String {
|
private fun getProperAnimeLink(uri: String): String {
|
||||||
|
|
|
@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.animeproviders
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
|
||||||
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
@ -41,35 +40,31 @@ class GomunimeProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class Response(
|
override val mainPage = mainPageOf(
|
||||||
@JsonProperty("status") val status: Boolean,
|
"e" to "Episode Baru",
|
||||||
@JsonProperty("html") val html: String
|
"c" to "Completed",
|
||||||
|
"la" to "Live Action",
|
||||||
|
"t" to "Trending"
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override suspend fun getMainPage(
|
||||||
val urls = listOf(
|
page: Int,
|
||||||
Pair("e", "Episode Baru"),
|
request: MainPageRequest
|
||||||
Pair("c", "Completed"),
|
): HomePageResponse {
|
||||||
Pair("la", "Live Action"),
|
|
||||||
Pair("t", "Trending"),
|
|
||||||
)
|
|
||||||
|
|
||||||
val items = ArrayList<HomePageList>()
|
|
||||||
|
|
||||||
for ((payload, name) in urls) {
|
|
||||||
try {
|
|
||||||
val home = Jsoup.parse(
|
val home = Jsoup.parse(
|
||||||
parseJson<Response>(
|
(app.post(
|
||||||
app.post(
|
|
||||||
url = "$mainUrl/wp-admin/admin-ajax.php/wp-admin/admin-ajax.php",
|
url = "$mainUrl/wp-admin/admin-ajax.php/wp-admin/admin-ajax.php",
|
||||||
headers = mapOf("Referer" to mainUrl),
|
headers = mapOf("Referer" to mainUrl),
|
||||||
data = mapOf("action" to "home_ajax", "fungsi" to payload, "pag" to "1")
|
data = mapOf(
|
||||||
).text
|
"action" to "home_ajax",
|
||||||
).html
|
"fungsi" to request.data,
|
||||||
).select("li").map {
|
"pag" to "$page"
|
||||||
val title = it.selectFirst("a.name")!!.text().trim()
|
)
|
||||||
|
).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 href = getProperAnimeLink(it.selectFirst("a")!!.attr("href"))
|
||||||
val posterUrl = it.selectFirst("img")!!.attr("src")
|
val posterUrl = it.selectFirst("img")?.attr("src")
|
||||||
val type = getType(it.selectFirst(".taglist > span")!!.text().trim())
|
val type = getType(it.selectFirst(".taglist > span")!!.text().trim())
|
||||||
val epNum = it.select(".tag.ep").text().replace(Regex("[^0-9]"), "").trim()
|
val epNum = it.select(".tag.ep").text().replace(Regex("[^0-9]"), "").trim()
|
||||||
.toIntOrNull()
|
.toIntOrNull()
|
||||||
|
@ -78,14 +73,8 @@ class GomunimeProvider : MainAPI() {
|
||||||
addSub(epNum)
|
addSub(epNum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
items.add(HomePageList(name, home))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items.size <= 0) throw ErrorLoadingException()
|
return newHomePageResponse(request.name, home)
|
||||||
return HomePageResponse(items)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getProperAnimeLink(uri: String): String {
|
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 {
|
override suspend fun load(url: String): LoadResponse {
|
||||||
val document = app.get(url).document
|
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(
|
override suspend fun loadLinks(
|
||||||
data: String,
|
data: String,
|
||||||
isCasting: Boolean,
|
isCasting: Boolean,
|
||||||
|
@ -234,4 +209,24 @@ class GomunimeProvider : MainAPI() {
|
||||||
|
|
||||||
return true
|
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.*
|
||||||
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
||||||
import com.lagradost.cloudstream3.network.DdosGuardKiller
|
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class KuramanimeProvider : MainAPI() {
|
class KuramanimeProvider : MainAPI() {
|
||||||
override var mainUrl = "https://kuramanime.com"
|
override var mainUrl = "https://kuramanime.com"
|
||||||
|
@ -38,28 +36,24 @@ class KuramanimeProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"$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 home = document.select("div.col-lg-4.col-md-6.col-sm-6").mapNotNull {
|
||||||
val header = block.selectFirst("h4")?.text().toString()
|
|
||||||
val animes = block.select("div.col-lg-4.col-md-6.col-sm-6").map {
|
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes))
|
|
||||||
}
|
|
||||||
|
|
||||||
document.select("div.product__sidebar__view").forEach { block ->
|
return newHomePageResponse(request.name, home)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getProperAnimeLink(uri: String): String {
|
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 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 posterUrl = fixUrl(this.select("div.product__item__pic.set-bg").attr("data-setbg"))
|
||||||
val episode = Regex("([0-9*])\\s?/").find(
|
val episode = Regex("([0-9*])\\s?/").find(
|
||||||
this.select("div.ep span").text()
|
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> {
|
override suspend fun search(query: String): List<SearchResponse> {
|
||||||
val link = "$mainUrl/anime?search=$query&order_by=oldest"
|
val link = "$mainUrl/anime?search=$query&order_by=oldest"
|
||||||
val document = app.get(link).document
|
val document = app.get(link).document
|
||||||
|
|
|
@ -39,20 +39,23 @@ class KuronimeProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"$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>()
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
document.select(".bixbox").forEach { block ->
|
request: MainPageRequest
|
||||||
val header = block.select(".releases > h3").text().trim()
|
): HomePageResponse {
|
||||||
val animes = block.select("article").map {
|
val document = app.get(request.data + page).document
|
||||||
|
val home = document.select("article").map {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
|
||||||
|
|
||||||
return HomePageResponse(homePageList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getProperAnimeLink(uri: String): String {
|
private fun getProperAnimeLink(uri: String): String {
|
||||||
|
@ -77,7 +80,10 @@ class KuronimeProvider : MainAPI() {
|
||||||
private fun Element.toSearchResult(): AnimeSearchResponse {
|
private fun Element.toSearchResult(): AnimeSearchResponse {
|
||||||
val href = getProperAnimeLink(fixUrlNull(this.selectFirst("a")?.attr("href")).toString())
|
val href = getProperAnimeLink(fixUrlNull(this.selectFirst("a")?.attr("href")).toString())
|
||||||
val title = this.select(".bsuxtt, .tt > h4").text().trim()
|
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 epNum = this.select(".ep").text().replace(Regex("[^0-9]"), "").trim().toIntOrNull()
|
||||||
val tvType = getType(this.selectFirst(".bt > span")?.text().toString())
|
val tvType = getType(this.selectFirst(".bt > span")?.text().toString())
|
||||||
return newAnimeSearchResponse(title, href, tvType) {
|
return newAnimeSearchResponse(title, href, tvType) {
|
||||||
|
@ -117,7 +123,8 @@ class KuronimeProvider : MainAPI() {
|
||||||
|
|
||||||
val episodes = document.select("div.bixbox.bxcl > ul > li").map {
|
val episodes = document.select("div.bixbox.bxcl > ul > li").map {
|
||||||
val name = it.selectFirst("a")?.text()?.trim()
|
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")
|
val link = it.selectFirst("a")!!.attr("href")
|
||||||
Episode(link, name = name, episode = episode)
|
Episode(link, name = name, episode = episode)
|
||||||
}.reversed()
|
}.reversed()
|
||||||
|
|
|
@ -40,20 +40,18 @@ class NeonimeProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"$mainUrl/episode/page/" to "Episode Terbaru",
|
||||||
|
"$mainUrl/tvshows/page/" to "Anime Terbaru",
|
||||||
|
"$mainUrl/movies/page/" to "Movie",
|
||||||
|
)
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||||
|
val document = app.get(request.data + page).document
|
||||||
document.select("div.item_1.items,div#slid01").forEach { block ->
|
val home = document.select("tbody tr,div.item").mapNotNull {
|
||||||
val header = block.previousElementSibling()?.select("h1")?.text() ?: block.selectFirst("h3")?.text().toString()
|
|
||||||
val animes = block.select("div.item").map {
|
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
|
||||||
|
|
||||||
return HomePageResponse(homePageList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getProperAnimeLink(uri: String): String {
|
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 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 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) {
|
return newAnimeSearchResponse(title, href, TvType.Anime) {
|
||||||
this.posterUrl = posterUrl
|
this.posterUrl = posterUrl
|
||||||
|
|
|
@ -228,7 +228,7 @@ class NontonAnimeIDProvider : MainAPI() {
|
||||||
val document = app.get(data).document
|
val document = app.get(data).document
|
||||||
val sources = ArrayList<String>()
|
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 dataPost = it.attr("data-post")
|
||||||
val dataNume = it.attr("data-nume")
|
val dataNume = it.attr("data-nume")
|
||||||
val dataType = it.attr("data-type")
|
val dataType = it.attr("data-type")
|
||||||
|
@ -240,7 +240,9 @@ class NontonAnimeIDProvider : MainAPI() {
|
||||||
"post" to dataPost,
|
"post" to dataPost,
|
||||||
"nume" to dataNume,
|
"nume" to dataNume,
|
||||||
"type" to dataType
|
"type" to dataType
|
||||||
)
|
),
|
||||||
|
referer = data,
|
||||||
|
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
|
||||||
).document.select("iframe").attr("src")
|
).document.select("iframe").attr("src")
|
||||||
|
|
||||||
sources.add(fixUrl(iframe))
|
sources.add(fixUrl(iframe))
|
||||||
|
|
|
@ -40,20 +40,21 @@ class OploverzProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"&status=&type=&order=update" to "Episode Terbaru",
|
||||||
|
"&status=&type=&order=latest" to "Anime Terbaru",
|
||||||
|
"&sub=&order=popular" to "Popular Anime",
|
||||||
|
)
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
document.select(".bixbox.bbnofrm").forEach { block ->
|
request: MainPageRequest
|
||||||
val header = block.selectFirst("h3")!!.text().trim()
|
): HomePageResponse {
|
||||||
val animes = block.select("article[itemscope=itemscope]").map {
|
val document = app.get("$mainUrl/anime/?page=$page${request.data}").document
|
||||||
|
val home = document.select("article[itemscope=itemscope]").mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
|
||||||
|
|
||||||
return HomePageResponse(homePageList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getProperAnimeLink(uri: String): String {
|
private fun getProperAnimeLink(uri: String): String {
|
||||||
|
@ -68,7 +69,8 @@ class OploverzProvider : MainAPI() {
|
||||||
)?.groupValues?.get(1).toString()
|
)?.groupValues?.get(1).toString()
|
||||||
(title.contains("-ova")) -> Regex("(.+)-ova").find(title)?.groupValues?.get(1)
|
(title.contains("-ova")) -> Regex("(.+)-ova").find(title)?.groupValues?.get(1)
|
||||||
.toString()
|
.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()
|
else -> Regex("(.+)-subtitle").find(title)?.groupValues?.get(1).toString()
|
||||||
.replace(Regex("-\\d+"), "")
|
.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 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 posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
|
||||||
val type = getType(this.selectFirst(".eggtype, .typez")?.text()?.trim().toString())
|
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) {
|
return newAnimeSearchResponse(title, href, type) {
|
||||||
this.posterUrl = posterUrl
|
this.posterUrl = posterUrl
|
||||||
addSub(epNum)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,8 @@ class OploverzProvider : MainAPI() {
|
||||||
|
|
||||||
val episodes = document.select(".eplister > ul > li").map {
|
val episodes = document.select(".eplister > ul > li").map {
|
||||||
val header = it.select(".epl-title").text()
|
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"))
|
val link = fixUrl(it.select("a").attr("href"))
|
||||||
Episode(link, name)
|
Episode(link, name)
|
||||||
}.reversed()
|
}.reversed()
|
||||||
|
|
|
@ -7,6 +7,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
class OtakudesuProvider : MainAPI() {
|
class OtakudesuProvider : MainAPI() {
|
||||||
override var mainUrl = "https://otakudesu.watch"
|
override var mainUrl = "https://otakudesu.watch"
|
||||||
|
@ -37,24 +38,24 @@ class OtakudesuProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"$mainUrl/ongoing-anime/page/" to "Anime Ongoing",
|
||||||
|
"$mainUrl/complete-anime/page/" to "Anime Completed"
|
||||||
|
)
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
document.select("div.rseries").forEach { block ->
|
request: MainPageRequest
|
||||||
val header = block.selectFirst("div.rvad > h1")!!.text().trim()
|
): HomePageResponse {
|
||||||
val items = block.select("div.venz > ul > li").map {
|
val document = app.get(request.data + page).document
|
||||||
|
val home = document.select("div.venz > ul > li").mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (items.isNotEmpty()) homePageList.add(HomePageList(header, items))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
}
|
||||||
|
|
||||||
return HomePageResponse(homePageList)
|
private fun Element.toSearchResult(): AnimeSearchResponse? {
|
||||||
}
|
val title = this.selectFirst("h2.jdlflm")?.text()?.trim() ?: return null
|
||||||
|
|
||||||
private fun Element.toSearchResult(): AnimeSearchResponse {
|
|
||||||
val title = this.selectFirst("h2.jdlflm")!!.text().trim()
|
|
||||||
val href = this.selectFirst("a")!!.attr("href")
|
val href = this.selectFirst("a")!!.attr("href")
|
||||||
val posterUrl = this.select("div.thumbz > img").attr("src").toString()
|
val posterUrl = this.select("div.thumbz > img").attr("src").toString()
|
||||||
val epNum = this.selectFirst("div.epz")?.ownText()?.replace(Regex("[^0-9]"), "")?.trim()
|
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 description = document.select("div.sinopc > p").text()
|
||||||
|
|
||||||
val episodes = document.select("div.episodelist")[1].select("ul > li").mapNotNull {
|
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"))
|
val link = fixUrl(it.selectFirst("a")!!.attr("href"))
|
||||||
Episode(link, name)
|
Episode(link, name)
|
||||||
}.reversed()
|
}.reversed()
|
||||||
|
@ -180,7 +183,10 @@ class OtakudesuProvider : MainAPI() {
|
||||||
).select("iframe").attr("src")
|
).select("iframe").attr("src")
|
||||||
|
|
||||||
if (sources.startsWith("https://desustream.me")) {
|
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")
|
sources = app.get(sources).document.select("iframe").attr("src")
|
||||||
}
|
}
|
||||||
if (sources.startsWith("https://yourupload.com")) {
|
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.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||||
|
|
||||||
|
class Ssbstream : StreamSB() {
|
||||||
|
override var mainUrl = "https://ssbstream.net"
|
||||||
|
}
|
||||||
|
|
||||||
class SBfull : StreamSB() {
|
class SBfull : StreamSB() {
|
||||||
override var mainUrl = "https://sbfull.com"
|
override var mainUrl = "https://sbfull.com"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import java.util.ArrayList
|
|
||||||
|
|
||||||
class DramaidProvider : MainAPI() {
|
class DramaidProvider : MainAPI() {
|
||||||
override var mainUrl = "https://185.224.83.103"
|
override var mainUrl = "https://185.224.83.103"
|
||||||
|
@ -30,20 +29,18 @@ class DramaidProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"&status=&type=&order=update" to "Drama Terbaru",
|
||||||
|
"&order=latest" to "Baru Ditambahkan",
|
||||||
|
"&status=&type=&order=popular" to "Drama Popular",
|
||||||
|
)
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||||
|
val document = app.get("$mainUrl/series/?page=$page${request.data}").document
|
||||||
document.select(".bixbox").forEach { block ->
|
val home = document.select("article[itemscope=itemscope]").mapNotNull {
|
||||||
val header = block.selectFirst(".releases > h3")!!.text().trim()
|
|
||||||
val dramas = block.select("article[itemscope=itemscope]").mapNotNull {
|
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (dramas.isNotEmpty()) homePageList.add(HomePageList(header, dramas))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
|
||||||
|
|
||||||
return HomePageResponse(homePageList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getProperDramaLink(uri: String): String {
|
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 href = getProperDramaLink(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 = this.selectFirst(".limit > noscript > img")!!.attr("src")
|
val posterUrl = fixUrlNull(this.selectFirst(".limit > noscript > img")?.attr("src"))
|
||||||
|
|
||||||
return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
|
return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
|
||||||
this.posterUrl = posterUrl
|
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.httpsify
|
||||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
class HDMovie5 : MainAPI() {
|
class HDMovie5 : MainAPI() {
|
||||||
override var mainUrl = "https://hdmovie2.click"
|
override var mainUrl = "https://hdmovie2.click"
|
||||||
|
@ -19,29 +20,27 @@ class HDMovie5 : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val doc = app.get(mainUrl).document.select("div.content")
|
"$mainUrl/genre/tv-movie/page/" to "TV Movie",
|
||||||
val list = mapOf(
|
"$mainUrl/genre/tv-show/page/" to "TV- Show",
|
||||||
"Featured Movies" to "featured",
|
"$mainUrl/genre/hindi-dubbed/page/" to "Hindi Dubbed",
|
||||||
"Updated Movies" to "normal"
|
"$mainUrl/genre/netflix/page/" to "NETFLIX",
|
||||||
)
|
)
|
||||||
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"),
|
|
||||||
|
|
||||||
this.name,
|
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||||
TvType.Movie,
|
val home = app.get(request.data + page).document.select("article.item").mapNotNull {
|
||||||
it.select("img").attr("src"),
|
it.toSearchResult()
|
||||||
data.select("span").text().toIntOrNull()
|
}
|
||||||
)
|
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(
|
private data class QuickSearchResponse(
|
||||||
|
|
|
@ -28,27 +28,25 @@ class HDrezkaProvider : MainAPI() {
|
||||||
TvType.AsianDrama
|
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>()
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
listOf(
|
request: MainPageRequest
|
||||||
Pair("фильмы", "$mainUrl/films/?filter=watching"),
|
): HomePageResponse {
|
||||||
Pair("сериалы", "$mainUrl/series/?filter=watching"),
|
val url = request.data.split("?")
|
||||||
Pair("мультфильмы", "$mainUrl/cartoons/?filter=watching"),
|
val home = app.get("${url.first()}page/$page/?${url.last()}").document.select(
|
||||||
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"
|
"div.b-content__inline_items div.b-content__inline_item"
|
||||||
).map {
|
).map {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
items.add(HomePageList(fixTitle(header), home))
|
|
||||||
}
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
|
||||||
if (items.size <= 0) throw ErrorLoadingException()
|
|
||||||
return HomePageResponse(items)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Element.toSearchResult(): SearchResponse {
|
private fun Element.toSearchResult(): SearchResponse {
|
||||||
|
|
|
@ -22,22 +22,25 @@ class IdlixProvider : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"$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>()
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
document.select("div.items").forEach { block ->
|
request: MainPageRequest
|
||||||
val header =
|
): HomePageResponse {
|
||||||
fixTitle(block.previousElementSibling()?.previousElementSibling()?.select("header > h2")
|
val url = request.data.split("?")
|
||||||
?.text()!!.trim())
|
val document = app.get("${url.first()}$page/?${url.lastOrNull()}").document
|
||||||
val items = block.select("article.item").mapNotNull {
|
val home = document.select("article").mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (items.isNotEmpty()) homePageList.add(HomePageList(header, items))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
|
||||||
|
|
||||||
return HomePageResponse(homePageList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getProperLink(uri: String): String {
|
private fun getProperLink(uri: String): String {
|
||||||
|
@ -75,7 +78,8 @@ class IdlixProvider : MainAPI() {
|
||||||
val document = app.get(link).document
|
val document = app.get(link).document
|
||||||
|
|
||||||
return document.select("div.result-item").map {
|
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 href = getProperLink(it.selectFirst("div.title > a")!!.attr("href"))
|
||||||
val posterUrl = it.selectFirst("img")!!.attr("src").toString()
|
val posterUrl = it.selectFirst("img")!!.attr("src").toString()
|
||||||
newMovieSearchResponse(title, href, TvType.TvSeries) {
|
newMovieSearchResponse(title, href, TvType.TvSeries) {
|
||||||
|
@ -87,7 +91,9 @@ class IdlixProvider : MainAPI() {
|
||||||
override suspend fun load(url: String): LoadResponse {
|
override suspend fun load(url: String): LoadResponse {
|
||||||
val document = app.get(url).document
|
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 poster = document.select("div.poster > img").attr("src").toString()
|
||||||
val tags = document.select("div.sgeneros > a").map { it.text() }
|
val tags = document.select("div.sgeneros > a").map { it.text() }
|
||||||
|
|
||||||
|
@ -157,7 +163,8 @@ class IdlixProvider : MainAPI() {
|
||||||
|
|
||||||
private fun getLanguage(str: String): String {
|
private fun getLanguage(str: String): String {
|
||||||
return when {
|
return when {
|
||||||
str.lowercase().contains("indonesia") || str.lowercase().contains("bahasa") -> "Indonesian"
|
str.lowercase().contains("indonesia") || str.lowercase()
|
||||||
|
.contains("bahasa") -> "Indonesian"
|
||||||
else -> str
|
else -> str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +210,8 @@ class IdlixProvider : MainAPI() {
|
||||||
|
|
||||||
document.select("script").map { script ->
|
document.select("script").map { script ->
|
||||||
if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
|
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 ->
|
tryParseJson<List<Tracks>>("[$subData]")?.map { subtitle ->
|
||||||
subCallback.invoke(
|
subCallback.invoke(
|
||||||
SubtitleFile(
|
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 com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class LayarKacaProvider : MainAPI() {
|
class LayarKacaProvider : MainAPI() {
|
||||||
override var mainUrl = "https://lk21.xn--6frz82g"
|
override var mainUrl = "https://lk21.xn--6frz82g"
|
||||||
|
@ -21,90 +20,33 @@ class LayarKacaProvider : MainAPI() {
|
||||||
TvType.AsianDrama
|
TvType.AsianDrama
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"$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>()
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
document.select("section.hot-block,section#newseries").forEach { block ->
|
request: MainPageRequest
|
||||||
val header = fixTitle(block.select("footer.load-more > a").text().trim())
|
): HomePageResponse {
|
||||||
val items = block.select("div.slider-item").mapNotNull {
|
val document = app.get(request.data + page).document
|
||||||
it.toTopSearchResult()
|
val home = document.select("article.mega-item").mapNotNull {
|
||||||
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (items.isNotEmpty()) homePageList.add(HomePageList(header, items))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
}
|
||||||
|
|
||||||
document.select("div#newest").forEach { block ->
|
private fun Element.toSearchResult(): SearchResponse? {
|
||||||
val header = fixTitle(block.select(".header > h2 > a").text())
|
val title = this.selectFirst("h1.grid-title > a")?.ownText()?.trim() ?: return null
|
||||||
val items = block.select("div.item").mapNotNull {
|
val href = fixUrl(this.selectFirst("h1.grid-title > a")!!.attr("href"))
|
||||||
it.toMainSearchResult()
|
val posterUrl = fixUrlNull(this.selectFirst(".grid-poster > a > img")?.attr("src"))
|
||||||
}
|
val quality = this.select("div.quality").text().trim()
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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())
|
|
||||||
return newMovieSearchResponse(title, href, TvType.Movie) {
|
return newMovieSearchResponse(title, href, TvType.Movie) {
|
||||||
this.posterUrl = posterUrl
|
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> {
|
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 trailer = document.selectFirst("div.action-player li > a.fancybox")?.attr("href")
|
||||||
val rating =
|
val rating =
|
||||||
document.selectFirst("div.content > div:nth-child(6) > h3")?.text()?.toRatingInt()
|
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 recommendations = document.select("div.row.item-media").map {
|
||||||
val recName = it.selectFirst("h3")?.text()?.trim().toString()
|
val recName = it.selectFirst("h3")?.text()?.trim().toString()
|
||||||
val recHref = it.selectFirst(".content-media > a")!!.attr("href")
|
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) {
|
newTvSeriesSearchResponse(recName, recHref, TvType.TvSeries) {
|
||||||
this.posterUrl = recPosterUrl
|
this.posterUrl = recPosterUrl
|
||||||
}
|
}
|
||||||
|
@ -172,8 +116,7 @@ class LayarKacaProvider : MainAPI() {
|
||||||
this.recommendations = recommendations
|
this.recommendations = recommendations
|
||||||
addTrailer(trailer)
|
addTrailer(trailer)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
newMovieLoadResponse(title, url, TvType.Movie, url) {
|
newMovieLoadResponse(title, url, TvType.Movie, url) {
|
||||||
this.posterUrl = poster
|
this.posterUrl = poster
|
||||||
this.year = year
|
this.year = year
|
||||||
|
@ -196,10 +139,11 @@ class LayarKacaProvider : MainAPI() {
|
||||||
|
|
||||||
val document = app.get(data).document
|
val document = app.get(data).document
|
||||||
|
|
||||||
val sources = if(data.contains("-episode-")) {
|
val sources = if (data.contains("-episode-")) {
|
||||||
document.select("script").mapNotNull { script ->
|
document.select("script").mapNotNull { script ->
|
||||||
if(script.data().contains("var data =")) {
|
if (script.data().contains("var data =")) {
|
||||||
val scriptData = script.toString().substringAfter("var data = '").substringBefore("';")
|
val scriptData =
|
||||||
|
script.toString().substringAfter("var data = '").substringBefore("';")
|
||||||
Jsoup.parse(scriptData).select("li").map {
|
Jsoup.parse(scriptData).select("li").map {
|
||||||
fixUrl(it.select("a").attr("href"))
|
fixUrl(it.select("a").attr("href"))
|
||||||
}
|
}
|
||||||
|
@ -214,7 +158,7 @@ class LayarKacaProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
sources.apmap {
|
sources.apmap {
|
||||||
val link = if(it.startsWith("https://layarkacaxxi.icu")) {
|
val link = if (it.startsWith("https://layarkacaxxi.icu")) {
|
||||||
it.substringBeforeLast("/")
|
it.substringBeforeLast("/")
|
||||||
} else {
|
} else {
|
||||||
it
|
it
|
||||||
|
|
|
@ -8,7 +8,6 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import java.util.ArrayList
|
|
||||||
|
|
||||||
class MultiplexProvider : MainAPI() {
|
class MultiplexProvider : MainAPI() {
|
||||||
override var mainUrl = "https://146.19.24.137"
|
override var mainUrl = "https://146.19.24.137"
|
||||||
|
@ -22,45 +21,30 @@ class MultiplexProvider : MainAPI() {
|
||||||
TvType.AsianDrama
|
TvType.AsianDrama
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"$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>()
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
document.select("div.col-md-12 > div.home-widget").forEach { block ->
|
request: MainPageRequest
|
||||||
val header = fixTitle(block.select("h3.homemodule-title").text())
|
): HomePageResponse {
|
||||||
val items = block.select("div.col-md-125").mapNotNull {
|
val document = app.get(request.data + page).document
|
||||||
|
val home = document.select("article.item").mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (items.isNotEmpty()) homePageList.add(HomePageList(header, items))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
}
|
||||||
|
|
||||||
document.select("div.container.gmr-maincontent")
|
private fun Element.toSearchResult(): SearchResponse? {
|
||||||
.forEach { block ->
|
val title = this.selectFirst("h2.entry-title > a")?.text()?.trim() ?: return null
|
||||||
val header = fixTitle(block.select("h3.homemodule-title").text())
|
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
|
||||||
val items = block.select("article.item").mapNotNull {
|
val posterUrl = fixUrlNull(this.selectFirst("a > img")?.attr("data-src"))
|
||||||
it.toSearchResult()
|
val quality = this.select("div.gmr-quality-item > a").text().trim()
|
||||||
}
|
return if (quality.isEmpty()) {
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
val episode = this.select("div.gmr-numbeps > span").text().toIntOrNull()
|
val episode = this.select("div.gmr-numbeps > span").text().toIntOrNull()
|
||||||
newAnimeSearchResponse(title, href, TvType.TvSeries) {
|
newAnimeSearchResponse(title, href, TvType.TvSeries) {
|
||||||
this.posterUrl = posterUrl
|
this.posterUrl = posterUrl
|
||||||
|
@ -69,27 +53,24 @@ class MultiplexProvider : MainAPI() {
|
||||||
} else {
|
} else {
|
||||||
newMovieSearchResponse(title, href, TvType.Movie) {
|
newMovieSearchResponse(title, href, TvType.Movie) {
|
||||||
this.posterUrl = posterUrl
|
this.posterUrl = posterUrl
|
||||||
this.quality = quality
|
addQuality(quality)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
private fun Element.toBottomSearchResult(): SearchResponse? {
|
||||||
|
val title = this.selectFirst("a > span.idmuvi-rp-title")?.text()?.trim() ?: return null
|
||||||
private fun Element.toBottomSearchResult(): SearchResponse {
|
|
||||||
val title = this.selectFirst("a > span.idmuvi-rp-title")!!.text().trim()
|
|
||||||
val href = this.selectFirst("a")!!.attr("href")
|
val href = this.selectFirst("a")!!.attr("href")
|
||||||
val posterUrl = fixUrl(this.selectFirst("a > img")?.attr("data-src").toString())
|
val posterUrl = fixUrl(this.selectFirst("a > img")?.attr("data-src").toString())
|
||||||
return newMovieSearchResponse(title, href, TvType.Movie) {
|
return newMovieSearchResponse(title, href, TvType.Movie) {
|
||||||
this.posterUrl = posterUrl
|
this.posterUrl = posterUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun search(query: String): List<SearchResponse> {
|
override suspend fun search(query: String): List<SearchResponse> {
|
||||||
val link = "$mainUrl/?s=$query&post_type[]=post&post_type[]=tv"
|
val link = "$mainUrl/?s=$query&post_type[]=post&post_type[]=tv"
|
||||||
val document = app.get(link).document
|
val document = app.get(link).document
|
||||||
|
return document.select("article.item").mapNotNull {
|
||||||
return document.select("div#gmr-main-load > article.item").map {
|
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,9 +93,10 @@ class MultiplexProvider : MainAPI() {
|
||||||
val rating =
|
val rating =
|
||||||
document.selectFirst("div.gmr-meta-rating > span[itemprop=ratingValue]")?.text()
|
document.selectFirst("div.gmr-meta-rating > span[itemprop=ratingValue]")?.text()
|
||||||
?.toRatingInt()
|
?.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()
|
it.toBottomSearchResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,20 +23,25 @@ class PhimmoichillProvider : MainAPI() {
|
||||||
TvType.AsianDrama
|
TvType.AsianDrama
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"$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>()
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
document.select("div.container div.block").forEach { block ->
|
request: MainPageRequest
|
||||||
val header = fixTitle(block.selectFirst("h2")!!.text())
|
): HomePageResponse {
|
||||||
val items = block.select("li.item").mapNotNull {
|
val document = app.get(request.data + page).document
|
||||||
|
val home = document.select("li.item").mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (items.isNotEmpty()) homePageList.add(HomePageList(header, items))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
|
||||||
|
|
||||||
return HomePageResponse(homePageList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun decode(input: String): String? = URLDecoder.decode(input, "utf-8")
|
private fun decode(input: String): String? = URLDecoder.decode(input, "utf-8")
|
||||||
|
|
|
@ -15,7 +15,7 @@ import org.jsoup.nodes.Element
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
class RebahinProvider : MainAPI() {
|
class RebahinProvider : MainAPI() {
|
||||||
override var mainUrl = "http://167.88.14.149"
|
override var mainUrl = "http://104.237.198.194"
|
||||||
override var name = "Rebahin"
|
override var name = "Rebahin"
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
override var lang = "id"
|
override var lang = "id"
|
||||||
|
|
|
@ -23,20 +23,24 @@ class UakinoProvider : MainAPI() {
|
||||||
TvType.Anime
|
TvType.Anime
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"$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>()
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
document.select("div.main-section-inner").forEach { block ->
|
request: MainPageRequest
|
||||||
val header = block.selectFirst("p.sidebar-title")?.text()?.trim().toString()
|
): HomePageResponse {
|
||||||
val items = block.select("div.owl-item, div.movie-item").map {
|
val document = app.get(request.data + page).document
|
||||||
|
val home = document.select("div.owl-item, div.movie-item").map {
|
||||||
it.toSearchResponse()
|
it.toSearchResponse()
|
||||||
}
|
}
|
||||||
if (items.isNotEmpty()) homePageList.add(HomePageList(header, items))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
|
||||||
|
|
||||||
return HomePageResponse(homePageList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Element.toSearchResponse(): SearchResponse {
|
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 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 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 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 description = document.selectFirst("div[itemprop=description]")?.text()?.trim()
|
||||||
val trailer = document.selectFirst("iframe#pre")?.attr("data-src")
|
val trailer = document.selectFirst("iframe#pre")?.attr("data-src")
|
||||||
val rating = document.selectFirst("div.film-info > div:nth-child(8) div.fi-desc")?.text()
|
val rating = document.selectFirst("div.film-info > div:nth-child(8) div.fi-desc")?.text()
|
||||||
|
@ -83,7 +88,8 @@ class UakinoProvider : MainAPI() {
|
||||||
|
|
||||||
return if (tvType == TvType.TvSeries) {
|
return if (tvType == TvType.TvSeries) {
|
||||||
val id = url.split("/").last().split("-").first()
|
val id = url.split("/").last().split("-").first()
|
||||||
val episodes = app.get("$mainUrl/engine/ajax/playlists.php?news_id=$id&xfield=playlist&time=${Date().time}")
|
val episodes =
|
||||||
|
app.get("$mainUrl/engine/ajax/playlists.php?news_id=$id&xfield=playlist&time=${Date().time}")
|
||||||
.parsedSafe<Responses>()?.response.let {
|
.parsedSafe<Responses>()?.response.let {
|
||||||
Jsoup.parse(it.toString()).select("ul > li").mapNotNull { eps ->
|
Jsoup.parse(it.toString()).select("ul > li").mapNotNull { eps ->
|
||||||
val href = fixUrl(eps.attr("data-file"))
|
val href = fixUrl(eps.attr("data-file"))
|
||||||
|
|
|
@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
class YomoviesProvider : MainAPI() {
|
class YomoviesProvider : MainAPI() {
|
||||||
override var mainUrl = "https://yomovies.vip"
|
override var mainUrl = "https://yomovies.skin"
|
||||||
override var name = "Yomovies"
|
override var name = "Yomovies"
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
override var lang = "hi"
|
override var lang = "hi"
|
||||||
|
@ -19,21 +19,25 @@ class YomoviesProvider : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val document = app.get(mainUrl).document
|
"$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>()
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
document.select("div.movies-list-wrap.mlw-topview,div.movies-list-wrap.mlw-latestmovie")
|
request: MainPageRequest
|
||||||
.forEach { block ->
|
): HomePageResponse {
|
||||||
val header = fixTitle(block.selectFirst("div.ml-title span")?.text() ?: "")
|
val document = app.get(request.data + page).document
|
||||||
val items = block.select("div.ml-item").mapNotNull {
|
val home = document.select("div.ml-item").mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
if (items.isNotEmpty()) homePageList.add(HomePageList(header, items))
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
|
||||||
|
|
||||||
return HomePageResponse(homePageList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Element.toSearchResult(): SearchResponse? {
|
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()
|
val year = document.select("div.mvici-right p:nth-child(3) a").text().trim()
|
||||||
.toIntOrNull()
|
.toIntOrNull()
|
||||||
val tvType = if (document.selectFirst("div.les-content")
|
val tvType = if (document.selectFirst("div.les-content")
|
||||||
?.select("a")?.size!! <= 1
|
?.select("a")?.size!! > 1 || document.selectFirst("ul.idTabs li strong")?.text()
|
||||||
) TvType.Movie else TvType.TvSeries
|
?.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 description = document.selectFirst("p.f-desc")?.text()?.trim()
|
||||||
val trailer = fixUrlNull(document.select("iframe#iframe-trailer").attr("src"))
|
val trailer = fixUrlNull(document.select("iframe#iframe-trailer").attr("src"))
|
||||||
val rating = document.select("div.mvici-right > div.imdb_r span").text().toRatingInt()
|
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) {
|
return if (tvType == TvType.TvSeries) {
|
||||||
val episodes = document.select("div.les-content a").map {
|
val episodes = if (document.selectFirst("div.les-title strong")?.text().toString()
|
||||||
val href = it.attr("href")
|
.contains(Regex("(?i)EP\\s?[0-9]+|Episode\\s?[0-9]+"))
|
||||||
val name = it.text().trim()
|
) {
|
||||||
|
document.select("ul.idTabs li").map {
|
||||||
|
val id = it.select("a").attr("href")
|
||||||
Episode(
|
Episode(
|
||||||
data = href,
|
data = fixUrl(document.select("div$id iframe").attr("src")),
|
||||||
name = name,
|
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) {
|
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
|
||||||
this.posterUrl = poster
|
this.posterUrl = poster
|
||||||
this.year = year
|
this.year = year
|
||||||
|
@ -113,6 +129,7 @@ class YomoviesProvider : MainAPI() {
|
||||||
callback: (ExtractorLink) -> Unit
|
callback: (ExtractorLink) -> Unit
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
|
||||||
|
if (data.startsWith(mainUrl)) {
|
||||||
app.get(data).document.select("div.movieplay iframe").map { fixUrl(it.attr("src")) }
|
app.get(data).document.select("div.movieplay iframe").map { fixUrl(it.attr("src")) }
|
||||||
.apmap { source ->
|
.apmap { source ->
|
||||||
safeApiCall {
|
safeApiCall {
|
||||||
|
@ -133,6 +150,9 @@ class YomoviesProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
loadExtractor(data, "$mainUrl/", subtitleCallback, callback)
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,6 +232,7 @@ val extractorApis: Array<ExtractorApi> = arrayOf(
|
||||||
SBfull(),
|
SBfull(),
|
||||||
// Streamhub(), cause Streamhub2() works
|
// Streamhub(), cause Streamhub2() works
|
||||||
Streamhub2(),
|
Streamhub2(),
|
||||||
|
Ssbstream(),
|
||||||
|
|
||||||
FEmbed(),
|
FEmbed(),
|
||||||
FeHD(),
|
FeHD(),
|
||||||
|
|
|
@ -177,6 +177,12 @@
|
||||||
"status": 1,
|
"status": 1,
|
||||||
"url": "https://bestdubbedanime.com"
|
"url": "https://bestdubbedanime.com"
|
||||||
},
|
},
|
||||||
|
"DubokuProvider": {
|
||||||
|
"language": "zh",
|
||||||
|
"name": "Duboku",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://www.duboku.tv"
|
||||||
|
},
|
||||||
"EgyBestProvider": {
|
"EgyBestProvider": {
|
||||||
"language": "ar",
|
"language": "ar",
|
||||||
"name": "EgyBest",
|
"name": "EgyBest",
|
||||||
|
@ -308,6 +314,12 @@
|
||||||
"status": 1,
|
"status": 1,
|
||||||
"url": "https://kimcartoon.li"
|
"url": "https://kimcartoon.li"
|
||||||
},
|
},
|
||||||
|
"KisskhProvider": {
|
||||||
|
"language": "en",
|
||||||
|
"name": "Kisskh",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://kisskh.me"
|
||||||
|
},
|
||||||
"KuramanimeProvider": {
|
"KuramanimeProvider": {
|
||||||
"language": "id",
|
"language": "id",
|
||||||
"name": "Kuramanime",
|
"name": "Kuramanime",
|
||||||
|
@ -466,7 +478,7 @@
|
||||||
"language": "id",
|
"language": "id",
|
||||||
"name": "Rebahin",
|
"name": "Rebahin",
|
||||||
"status": 1,
|
"status": 1,
|
||||||
"url": "http://167.88.14.149"
|
"url": "http://104.237.198.194"
|
||||||
},
|
},
|
||||||
"SeriesflixProvider": {
|
"SeriesflixProvider": {
|
||||||
"language": "es",
|
"language": "es",
|
||||||
|
@ -594,6 +606,12 @@
|
||||||
"status": 1,
|
"status": 1,
|
||||||
"url": "https://wcostream.cc"
|
"url": "https://wcostream.cc"
|
||||||
},
|
},
|
||||||
|
"WcofunProvider": {
|
||||||
|
"language": "en",
|
||||||
|
"name": "WCO Fun",
|
||||||
|
"status": 1,
|
||||||
|
"url": "https://www.wcofun.com"
|
||||||
|
},
|
||||||
"XcineProvider": {
|
"XcineProvider": {
|
||||||
"language": "de",
|
"language": "de",
|
||||||
"name": "Xcine",
|
"name": "Xcine",
|
||||||
|
@ -604,7 +622,7 @@
|
||||||
"language": "hi",
|
"language": "hi",
|
||||||
"name": "Yomovies",
|
"name": "Yomovies",
|
||||||
"status": 1,
|
"status": 1,
|
||||||
"url": "https://yomovies.vip"
|
"url": "https://yomovies.skin"
|
||||||
},
|
},
|
||||||
"ZoroProvider": {
|
"ZoroProvider": {
|
||||||
"language": "en",
|
"language": "en",
|
||||||
|
|
Loading…
Reference in a new issue