2022-09-09 16:09:54 +00:00
|
|
|
package com.hexated
|
|
|
|
|
|
|
|
import com.lagradost.cloudstream3.*
|
|
|
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
|
|
|
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
|
|
|
import com.lagradost.cloudstream3.utils.*
|
|
|
|
import org.jsoup.nodes.Element
|
2023-10-21 09:18:16 +00:00
|
|
|
import java.net.URI
|
2022-09-09 16:09:54 +00:00
|
|
|
import java.net.URLDecoder
|
|
|
|
|
|
|
|
class PhimmoichillProvider : MainAPI() {
|
2023-10-21 09:18:16 +00:00
|
|
|
override var mainUrl = "https://phimmoichillh.net"
|
|
|
|
private var directUrl = mainUrl
|
2022-09-09 16:09:54 +00:00
|
|
|
override var name = "Phimmoichill"
|
|
|
|
override val hasMainPage = true
|
|
|
|
override var lang = "vi"
|
|
|
|
override val hasDownloadSupport = true
|
|
|
|
override val supportedTypes = setOf(
|
|
|
|
TvType.Movie,
|
|
|
|
TvType.TvSeries,
|
|
|
|
TvType.Anime,
|
|
|
|
TvType.AsianDrama
|
|
|
|
)
|
|
|
|
|
|
|
|
override val mainPage = mainPageOf(
|
|
|
|
"$mainUrl/genre/phim-chieu-rap/page-" to "Phim Chiếu Rạp",
|
|
|
|
"$mainUrl/list/phim-le/page-" to "Phim Lẻ",
|
|
|
|
"$mainUrl/list/phim-bo/page-" to "Phim Bộ",
|
|
|
|
"$mainUrl/genre/phim-hoat-hinh/page-" to "Phim Hoạt Hình",
|
2023-07-09 10:57:24 +00:00
|
|
|
"$mainUrl/genre/phim-anime/page-" to "Phim Anime",
|
2022-09-09 16:09:54 +00:00
|
|
|
"$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",
|
2023-07-09 10:57:24 +00:00
|
|
|
"$mainUrl/genre/phim-sap-chieu/page-" to "Phim Sắp Chiếu",
|
2022-09-09 16:09:54 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
override suspend fun getMainPage(
|
|
|
|
page: Int,
|
|
|
|
request: MainPageRequest
|
|
|
|
): HomePageResponse {
|
|
|
|
val document = app.get(request.data + page).document
|
|
|
|
val home = document.select("li.item").mapNotNull {
|
|
|
|
it.toSearchResult()
|
|
|
|
}
|
|
|
|
return newHomePageResponse(
|
|
|
|
list = HomePageList(
|
|
|
|
name = request.name,
|
|
|
|
list = home,
|
|
|
|
isHorizontalImages = true
|
|
|
|
),
|
|
|
|
hasNext = true
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun decode(input: String): String? = URLDecoder.decode(input, "utf-8")
|
|
|
|
|
|
|
|
private fun Element.toSearchResult(): SearchResponse {
|
|
|
|
val title = this.selectFirst("p,h3")?.text()?.trim().toString()
|
|
|
|
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
|
|
|
|
val posterUrl = decode(this.selectFirst("img")!!.attr("src").substringAfter("url="))
|
|
|
|
val temp = this.select("span.label").text()
|
|
|
|
return if (temp.contains(Regex("\\d"))) {
|
|
|
|
val episode = Regex("(\\((\\d+))|(\\s(\\d+))").find(temp)?.groupValues?.map { num ->
|
|
|
|
num.replace(Regex("\\(|\\s"), "")
|
|
|
|
}?.distinct()?.firstOrNull()?.toIntOrNull()
|
|
|
|
newAnimeSearchResponse(title, href, TvType.TvSeries) {
|
|
|
|
this.posterUrl = posterUrl
|
|
|
|
addSub(episode)
|
|
|
|
}
|
2023-07-09 10:57:24 +00:00
|
|
|
} else if (temp.contains(Regex("Trailer"))) {
|
|
|
|
newMovieSearchResponse(title, href, TvType.Movie) {
|
|
|
|
this.posterUrl = posterUrl
|
|
|
|
}
|
2022-09-09 16:09:54 +00:00
|
|
|
} else {
|
|
|
|
val quality =
|
|
|
|
temp.replace(Regex("(-.*)|(\\|.*)|(?i)(VietSub.*)|(?i)(Thuyết.*)"), "").trim()
|
|
|
|
newMovieSearchResponse(title, href, TvType.Movie) {
|
|
|
|
this.posterUrl = posterUrl
|
|
|
|
addQuality(quality)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override suspend fun search(query: String): List<SearchResponse> {
|
|
|
|
val link = "$mainUrl/tim-kiem/$query"
|
|
|
|
val document = app.get(link).document
|
|
|
|
|
|
|
|
return document.select("ul.list-film li").map {
|
|
|
|
it.toSearchResult()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-21 09:18:16 +00:00
|
|
|
override suspend fun load(url: String): LoadResponse {
|
|
|
|
val request = app.get(url)
|
|
|
|
directUrl = getBaseUrl(request.url)
|
|
|
|
val document = request.document
|
2022-09-09 16:09:54 +00:00
|
|
|
|
|
|
|
val title = document.selectFirst("h1[itemprop=name]")?.text()?.trim().toString()
|
|
|
|
val link = document.select("ul.list-button li:last-child a").attr("href")
|
|
|
|
val poster = document.selectFirst("div.image img[itemprop=image]")?.attr("src")
|
2023-10-21 09:18:16 +00:00
|
|
|
val tags = document.select("ul.entry-meta.block-film li:nth-child(4) a")
|
|
|
|
.map { it.text().substringAfter("Phim") }
|
2022-09-09 16:09:54 +00:00
|
|
|
val year = document.select("ul.entry-meta.block-film li:nth-child(2) a").text().trim()
|
|
|
|
.toIntOrNull()
|
|
|
|
val tvType = if (document.select("div.latest-episode").isNotEmpty()
|
|
|
|
) TvType.TvSeries else TvType.Movie
|
2023-10-21 09:18:16 +00:00
|
|
|
val description =
|
|
|
|
document.select("div#film-content").text().substringAfter("Full HD Vietsub Thuyết Minh")
|
|
|
|
.substringBefore("@phimmoi").trim()
|
2023-07-09 10:57:24 +00:00
|
|
|
val trailer = document.select("body script")
|
2023-10-21 09:18:16 +00:00
|
|
|
.find { it.data().contains("youtube.com") }?.data()?.substringAfterLast("file: \"")
|
|
|
|
?.substringBefore("\",")
|
2022-09-09 16:09:54 +00:00
|
|
|
val rating =
|
|
|
|
document.select("ul.entry-meta.block-film li:nth-child(7) span").text().toRatingInt()
|
|
|
|
val actors = document.select("ul.entry-meta.block-film li:last-child a").map { it.text() }
|
|
|
|
val recommendations = document.select("ul#list-film-realted li.item").map {
|
|
|
|
it.toSearchResult().apply {
|
2023-10-21 09:18:16 +00:00
|
|
|
this.posterUrl =
|
|
|
|
decode(it.selectFirst("img")!!.attr("data-src").substringAfter("url="))
|
2022-09-09 16:09:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return if (tvType == TvType.TvSeries) {
|
|
|
|
val docEpisodes = app.get(link).document
|
|
|
|
val episodes = docEpisodes.select("ul#list_episodes > li").map {
|
|
|
|
val href = it.select("a").attr("href")
|
|
|
|
val episode =
|
|
|
|
it.select("a").text().replace(Regex("[^0-9]"), "").trim().toIntOrNull()
|
|
|
|
val name = "Episode $episode"
|
|
|
|
Episode(
|
|
|
|
data = href,
|
|
|
|
name = name,
|
|
|
|
episode = episode,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
|
|
|
|
this.posterUrl = poster
|
|
|
|
this.year = year
|
|
|
|
this.plot = description
|
|
|
|
this.tags = tags
|
|
|
|
this.rating = rating
|
|
|
|
addActors(actors)
|
|
|
|
this.recommendations = recommendations
|
|
|
|
addTrailer(trailer)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
newMovieLoadResponse(title, url, TvType.Movie, link) {
|
|
|
|
this.posterUrl = poster
|
|
|
|
this.year = year
|
|
|
|
this.plot = description
|
|
|
|
this.tags = tags
|
|
|
|
this.rating = rating
|
|
|
|
addActors(actors)
|
|
|
|
this.recommendations = recommendations
|
|
|
|
addTrailer(trailer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-21 09:18:16 +00:00
|
|
|
|
2022-09-09 16:09:54 +00:00
|
|
|
override suspend fun loadLinks(
|
|
|
|
data: String,
|
|
|
|
isCasting: Boolean,
|
|
|
|
subtitleCallback: (SubtitleFile) -> Unit,
|
|
|
|
callback: (ExtractorLink) -> Unit
|
|
|
|
): Boolean {
|
|
|
|
val document = app.get(data).document
|
|
|
|
|
|
|
|
val key = document.select("div#content script")
|
|
|
|
.find { it.data().contains("filmInfo.episodeID =") }?.data()?.let { script ->
|
2023-10-21 09:18:16 +00:00
|
|
|
val id = script.substringAfter("parseInt('").substringBefore("'")
|
2022-09-09 16:09:54 +00:00
|
|
|
app.post(
|
2023-10-21 09:18:16 +00:00
|
|
|
url = "$directUrl/chillsplayer.php",
|
|
|
|
data = mapOf("qcao" to id),
|
2022-09-09 16:09:54 +00:00
|
|
|
referer = data,
|
|
|
|
headers = mapOf(
|
|
|
|
"X-Requested-With" to "XMLHttpRequest",
|
|
|
|
"Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8"
|
|
|
|
)
|
|
|
|
).text.substringAfterLast("iniPlayers(\"")
|
2023-10-21 09:18:16 +00:00
|
|
|
.substringBefore("\"")
|
2022-09-09 16:09:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
listOf(
|
2023-10-21 09:18:16 +00:00
|
|
|
Pair("https://sotrim.topphimmoi.org/raw/$key/index.m3u8", "PMFAST"),
|
2022-09-09 16:09:54 +00:00
|
|
|
Pair("https://dash.megacdn.xyz/raw/$key/index.m3u8", "PMHLS"),
|
2023-07-09 10:57:24 +00:00
|
|
|
Pair("https://so-trym.phimchill.net/dash/$key/index.m3u8", "PMPRO"),
|
2022-09-09 16:09:54 +00:00
|
|
|
Pair("https://dash.megacdn.xyz/dast/$key/index.m3u8", "PMBK")
|
2023-10-21 09:18:16 +00:00
|
|
|
).map { (link, source) ->
|
|
|
|
callback.invoke(
|
|
|
|
ExtractorLink(
|
|
|
|
source,
|
|
|
|
source,
|
|
|
|
link,
|
|
|
|
referer = "$directUrl/",
|
|
|
|
quality = Qualities.P1080.value,
|
|
|
|
INFER_TYPE,
|
2022-09-09 16:09:54 +00:00
|
|
|
)
|
2023-10-21 09:18:16 +00:00
|
|
|
)
|
2022-09-09 16:09:54 +00:00
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-10-21 09:18:16 +00:00
|
|
|
private fun getBaseUrl(url: String): String {
|
|
|
|
return URI(url).let {
|
|
|
|
"${it.scheme}://${it.host}"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-09 16:09:54 +00:00
|
|
|
}
|