UHDMovies: update video extractor (#1649)
This commit is contained in:
@ -6,7 +6,7 @@ ext {
|
|||||||
extName = 'UHD Movies'
|
extName = 'UHD Movies'
|
||||||
pkgNameSuffix = 'en.uhdmovies'
|
pkgNameSuffix = 'en.uhdmovies'
|
||||||
extClass = '.UHDMovies'
|
extClass = '.UHDMovies'
|
||||||
extVersionCode = 14
|
extVersionCode = 15
|
||||||
libVersion = '13'
|
libVersion = '13'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,13 +21,13 @@ import kotlinx.coroutines.runBlocking
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
@ -121,8 +121,8 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
override fun animeDetailsParse(document: Document): SAnime {
|
override fun animeDetailsParse(document: Document): SAnime {
|
||||||
return SAnime.create().apply {
|
return SAnime.create().apply {
|
||||||
initialized = true
|
initialized = true
|
||||||
title = document.selectFirst(".entry-title")!!.text()
|
title = document.selectFirst(".entry-title")?.text()
|
||||||
.replace("Download", "", true).trim()
|
?.replace("Download", "", true)?.trim() ?: "Movie"
|
||||||
status = SAnime.COMPLETED
|
status = SAnime.COMPLETED
|
||||||
description = document.selectFirst("pre:contains(plot)")?.text()
|
description = document.selectFirst("pre:contains(plot)")?.text()
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
val episodeList = mutableListOf<SEpisode>()
|
val episodeList = mutableListOf<SEpisode>()
|
||||||
val episodeElements = resp.select("p:has(a[href*=?id=],a[href*=r?key=]):has(a[class*=maxbutton])[style*=center]")
|
val episodeElements = resp.select("p:has(a[href*=?id=],a[href*=r?key=]):has(a[class*=maxbutton])[style*=center]")
|
||||||
val qualityRegex = "\\d{3,4}p".toRegex(RegexOption.IGNORE_CASE)
|
val qualityRegex = "\\d{3,4}p".toRegex(RegexOption.IGNORE_CASE)
|
||||||
val firstText = episodeElements.first()!!.text()
|
val firstText = episodeElements.first()?.text() ?: ""
|
||||||
if (firstText.contains("Episode", true) ||
|
if (firstText.contains("Episode", true) ||
|
||||||
firstText.contains("Zip", true) ||
|
firstText.contains("Zip", true) ||
|
||||||
firstText.contains("Pack", true)
|
firstText.contains("Pack", true)
|
||||||
@ -151,9 +151,9 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
part = partRegex.find(prevP.text())?.groups?.get(1)?.value ?: ""
|
part = partRegex.find(prevP.text())?.groups?.get(1)?.value ?: ""
|
||||||
} ?: let {
|
} ?: let {
|
||||||
val prevPre = row.previousElementSiblings().prev("pre,div.mks_separator")
|
val prevPre = row.previousElementSiblings().prev("pre,div.mks_separator")
|
||||||
val preResult = seasonRegex.find(prevPre.first()!!.text())
|
val preResult = seasonRegex.find(prevPre.first()?.text() ?: "")
|
||||||
preResult?.groups?.get(1)?.value?.also {
|
preResult?.groups?.get(1)?.value?.also {
|
||||||
part = partRegex.find(prevPre.first()!!.text())?.groups?.get(1)?.value ?: ""
|
part = partRegex.find(prevPre.first()?.text() ?: "")?.groups?.get(1)?.value ?: ""
|
||||||
} ?: let {
|
} ?: let {
|
||||||
val title = resp.select("h1.entry-title")
|
val title = resp.select("h1.entry-title")
|
||||||
val titleResult = "[ .\\[(]?S(?:eason)?[ .]?(\\d{1,2})[ .\\])]?"
|
val titleResult = "[ .\\[(]?S(?:eason)?[ .]?(\\d{1,2})[ .\\])]?"
|
||||||
@ -182,7 +182,7 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
?.trim()?.toIntOrNull() ?: (index + 1)
|
?.trim()?.toIntOrNull() ?: (index + 1)
|
||||||
Triple(
|
Triple(
|
||||||
season + "_$episode" + "_$part",
|
season + "_$episode" + "_$part",
|
||||||
linkElement.attr("href") ?: return@mapIndexed null,
|
linkElement?.attr("href") ?: return@mapIndexed null,
|
||||||
quality,
|
quality,
|
||||||
)
|
)
|
||||||
}.filterNotNull()
|
}.filterNotNull()
|
||||||
@ -292,8 +292,18 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
|
|
||||||
private fun extractVideo(epUrl: EpUrl): Pair<List<Video>, String> {
|
private fun extractVideo(epUrl: EpUrl): Pair<List<Video>, String> {
|
||||||
|
val noRedirectClient = client.newBuilder().followRedirects(false).build()
|
||||||
val mediaResponse = if (epUrl.url.contains("?id=")) {
|
val mediaResponse = if (epUrl.url.contains("?id=")) {
|
||||||
val postLink = epUrl.url.substringBefore("?id=").substringAfter("/?")
|
val postLink = epUrl.url.substringBefore("?id=").substringAfter("/?")
|
||||||
|
val initailUrl = epUrl.url.substringAfter("/?http").let {
|
||||||
|
if (it.startsWith("http")) {
|
||||||
|
it
|
||||||
|
} else {
|
||||||
|
"http$it"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val initialResp = noRedirectClient.newCall(GET(initailUrl)).execute().asJsoup()
|
||||||
|
val (tokenUrl, tokenCookie) = if (initialResp.selectFirst("form#landing input[name=_wp_http_c]") != null) {
|
||||||
val formData = FormBody.Builder().add("_wp_http_c", epUrl.url.substringAfter("?id=")).build()
|
val formData = FormBody.Builder().add("_wp_http_c", epUrl.url.substringAfter("?id=")).build()
|
||||||
val response = client.newCall(POST(postLink, body = formData)).execute().body.string()
|
val response = client.newCall(POST(postLink, body = formData)).execute().body.string()
|
||||||
val (longC, catC, _) = getCookiesDetail(response)
|
val (longC, catC, _) = getCookiesDetail(response)
|
||||||
@ -306,14 +316,22 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
val cookieHeader2 = Headers.headersOf("Cookie", "$catC; $longC2; $postC")
|
val cookieHeader2 = Headers.headersOf("Cookie", "$catC; $longC2; $postC")
|
||||||
val parsedSoup2 = Jsoup.parse(response2)
|
val parsedSoup2 = Jsoup.parse(response2)
|
||||||
val link2 = parsedSoup2.selectFirst("center > a")!!.attr("href")
|
val link2 = parsedSoup2.selectFirst("center > a")!!.attr("href")
|
||||||
|
|
||||||
val tokenResp = client.newCall(GET(link2, cookieHeader2)).execute().body.string()
|
val tokenResp = client.newCall(GET(link2, cookieHeader2)).execute().body.string()
|
||||||
val goToken = tokenResp.substringAfter("?go=").substringBefore("\"")
|
val goToken = tokenResp.substringAfter("?go=").substringBefore("\"")
|
||||||
val tokenUrl = "$postLink?go=$goToken"
|
val tokenUrl = "$postLink?go=$goToken"
|
||||||
val newLongC = "$goToken=" + longC2.substringAfter("=")
|
val newLongC = "$goToken=" + longC2.substringAfter("=")
|
||||||
val tokenCookie = Headers.headersOf("Cookie", "$catC; rdst_post=; $newLongC")
|
val tokenCookie = Headers.headersOf("Cookie", "$catC; rdst_post=; $newLongC")
|
||||||
|
Pair(tokenUrl, tokenCookie)
|
||||||
|
} else {
|
||||||
|
val secondResp = initialResp.getNextResp().asJsoup()
|
||||||
|
val thirdResp = secondResp.getNextResp().body.string()
|
||||||
|
val goToken = thirdResp.substringAfter("?go=").substringBefore("\"")
|
||||||
|
val tokenUrl = "$postLink?go=$goToken"
|
||||||
|
val cookie = secondResp.selectFirst("form#landing input[name=_wp_http2]")?.attr("value")
|
||||||
|
val tokenCookie = Headers.headersOf("Cookie", "$goToken=$cookie")
|
||||||
|
Pair(tokenUrl, tokenCookie)
|
||||||
|
}
|
||||||
|
|
||||||
val noRedirectClient = client.newBuilder().followRedirects(false).build()
|
|
||||||
val tokenResponse = noRedirectClient.newCall(GET(tokenUrl, tokenCookie)).execute().asJsoup()
|
val tokenResponse = noRedirectClient.newCall(GET(tokenUrl, tokenCookie)).execute().asJsoup()
|
||||||
val redirectUrl = tokenResponse.select("meta[http-equiv=refresh]").attr("content")
|
val redirectUrl = tokenResponse.select("meta[http-equiv=refresh]").attr("content")
|
||||||
.substringAfter("url=").substringBefore("\"")
|
.substringAfter("url=").substringBefore("\"")
|
||||||
@ -335,6 +353,19 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
return Pair(videoList, mediaUrl)
|
return Pair(videoList, mediaUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Document.getNextResp(): Response {
|
||||||
|
val form = this.selectFirst("form#landing") ?: throw Exception("Failed to find form")
|
||||||
|
val postLink = form.attr("action")
|
||||||
|
val formData = FormBody.Builder().let { fd ->
|
||||||
|
form.select("input").map {
|
||||||
|
fd.add(it.attr("name"), it.attr("value"))
|
||||||
|
}
|
||||||
|
fd.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.newCall(POST(postLink, body = formData)).execute()
|
||||||
|
}
|
||||||
|
|
||||||
private fun getCookiesDetail(page: String): Triple<String, String, String> {
|
private fun getCookiesDetail(page: String): Triple<String, String, String> {
|
||||||
val cat = "rdst_cat"
|
val cat = "rdst_cat"
|
||||||
val post = "rdst_post"
|
val post = "rdst_post"
|
||||||
@ -395,7 +426,7 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
val size = sizeMatch?.groups?.get(1)?.value?.let { " - $it" } ?: ""
|
val size = sizeMatch?.groups?.get(1)?.value?.let { " - $it" } ?: ""
|
||||||
val gdResponse = client.newCall(GET(gdLink)).execute().asJsoup()
|
val gdResponse = client.newCall(GET(gdLink)).execute().asJsoup()
|
||||||
val link = gdResponse.select("form#download-form")
|
val link = gdResponse.select("form#download-form")
|
||||||
return if (link.isNullOrEmpty()) {
|
return if (link.isEmpty()) {
|
||||||
listOf()
|
listOf()
|
||||||
} else {
|
} else {
|
||||||
val realLink = link.attr("action")
|
val realLink = link.attr("action")
|
||||||
|
Reference in New Issue
Block a user