UHDMovies: Fix video extraction and some regex (#1455)

and lazy load current url
This commit is contained in:
Samfun75
2023-03-30 18:57:27 +03:00
committed by GitHub
parent a82204f80b
commit 042fffe5c4
2 changed files with 24 additions and 68 deletions

View File

@ -6,7 +6,7 @@ ext {
extName = 'UHD Movies' extName = 'UHD Movies'
pkgNameSuffix = 'en.uhdmovies' pkgNameSuffix = 'en.uhdmovies'
extClass = '.UHDMovies' extClass = '.UHDMovies'
extVersionCode = 11 extVersionCode = 12
libVersion = '13' libVersion = '13'
} }

View File

@ -12,7 +12,6 @@ import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
@ -24,11 +23,8 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString 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.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.jsoup.Jsoup
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
@ -55,12 +51,10 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
} }
private var currentBaseUrl: String private val currentBaseUrl by lazy {
init {
runBlocking { runBlocking {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
currentBaseUrl = client.newBuilder() client.newBuilder()
.followRedirects(false) .followRedirects(false)
.build() .build()
.newCall(GET("$baseUrl/")).execute().let { resp -> .newCall(GET("$baseUrl/")).execute().let { resp ->
@ -135,7 +129,7 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> { override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> {
val resp = client.newCall(GET(currentBaseUrl + anime.url)).execute().asJsoup() val resp = client.newCall(GET(currentBaseUrl + anime.url)).execute().asJsoup()
val episodeList = mutableListOf<SEpisode>() val episodeList = mutableListOf<SEpisode>()
val episodeElements = resp.select("p:has(a[href*=?id]):has(a[class*=maxbutton])[style*=center],p:has(a[href*=?id]):has(span.maxbutton-1-center)") val episodeElements = resp.select("p:has(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) ||
@ -144,17 +138,26 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
) { ) {
episodeElements.map { row -> episodeElements.map { row ->
val prevP = row.previousElementSibling()!! val prevP = row.previousElementSibling()!!
val seasonRegex = "[ .]S(?:eason)?[ .]?(\\d{1,2})[ .]".toRegex(RegexOption.IGNORE_CASE) val seasonRegex = "[ .]?S(?:eason)?[ .]?(\\d{1,2})[ .]?".toRegex(RegexOption.IGNORE_CASE)
val partRegex = "Part ?(\\d{1,2})".toRegex(RegexOption.IGNORE_CASE)
val result = seasonRegex.find(prevP.text()) val result = seasonRegex.find(prevP.text())
var part = ""
val season = ( val season = (
result?.groups?.get(1)?.value ?: let { result?.groups?.get(1)?.value?.also {
part = partRegex.find(prevP.text())?.groups?.get(1)?.value ?: ""
} ?: 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 ?: let { preResult?.groups?.get(1)?.value?.also {
part = partRegex.find(prevPre.first()!!.text())?.groups?.get(1)?.value ?: ""
} ?: let {
val title = resp.select("h1.entry-title") val title = resp.select("h1.entry-title")
val titleResult = "[ .\\[(]S(?:eason)?[ .]?(\\d{1,2})[ .\\])]".toRegex(RegexOption.IGNORE_CASE).find(title.text()) val titleResult = "[ .\\[(]?S(?:eason)?[ .]?(\\d{1,2})[ .\\])]?"
titleResult?.groups?.get(1)?.value ?: "-1" .toRegex(RegexOption.IGNORE_CASE)
.find(title.text())
titleResult?.groups?.get(1)?.value?.also {
part = partRegex.find(title.text())?.groups?.get(1)?.value ?: ""
} ?: "-1"
} }
} }
).replaceFirst("^0+(?!$)".toRegex(), "") ).replaceFirst("^0+(?!$)".toRegex(), "")
@ -174,13 +177,14 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
?.replace("Episode", "", true) ?.replace("Episode", "", true)
?.trim()?.toIntOrNull() ?: (index + 1) ?.trim()?.toIntOrNull() ?: (index + 1)
Triple( Triple(
season + "_$episode", season + "_$episode" + "_$part",
linkElement.attr("href") ?: return@mapIndexed null, linkElement.attr("href") ?: return@mapIndexed null,
quality, quality,
) )
}.filterNotNull() }.filterNotNull()
}.flatten().groupBy { it.first }.map { group -> }.flatten().groupBy { it.first }.map { group ->
val (season, episode) = group.key.split("_") val (season, episode, part) = group.key.split("_")
val partText = if (part.isBlank()) "" else " Pt $part"
episodeList.add( episodeList.add(
SEpisode.create().apply { SEpisode.create().apply {
url = EpLinks( url = EpLinks(
@ -188,7 +192,7 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
EpUrl(url = it.second, quality = it.third) EpUrl(url = it.second, quality = it.third)
}, },
).toJson() ).toJson()
name = "Season $season Ep $episode" name = "Season $season$partText Ep $episode"
episode_number = episode.toFloat() episode_number = episode.toFloat()
}, },
) )
@ -284,31 +288,7 @@ 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 postLink = epUrl.url.substringBefore("?id=").substringAfter("/?") val mediaResponse = client.newCall(GET(epUrl.url)).execute()
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 (longC, catC, _) = getCookiesDetail(response)
val cookieHeader = Headers.headersOf("Cookie", "$longC; $catC")
val parsedSoup = Jsoup.parse(response)
val link = parsedSoup.selectFirst("center > a")!!.attr("href")
val response2 = client.newCall(GET(link, cookieHeader)).execute().body.string()
val (longC2, _, postC) = getCookiesDetail(response2)
val cookieHeader2 = Headers.headersOf("Cookie", "$catC; $longC2; $postC")
val parsedSoup2 = Jsoup.parse(response2)
val link2 = parsedSoup2.selectFirst("center > a")!!.attr("href")
val tokenResp = client.newCall(GET(link2, cookieHeader2)).execute().body.string()
val goToken = tokenResp.substringAfter("?go=").substringBefore("\"")
val tokenUrl = "$postLink?go=$goToken"
val newLongC = "$goToken=" + longC2.substringAfter("=")
val tokenCookie = Headers.headersOf("Cookie", "$catC; rdst_post=; $newLongC")
val noRedirectClient = client.newBuilder().followRedirects(false).build()
val tokenResponse = noRedirectClient.newCall(GET(tokenUrl, tokenCookie)).execute().asJsoup()
val redirectUrl = tokenResponse.select("meta[http-equiv=refresh]").attr("content")
.substringAfter("url=").substringBefore("\"")
val mediaResponse = noRedirectClient.newCall(GET(redirectUrl)).execute()
val path = mediaResponse.body.string().substringAfter("replace(\"").substringBefore("\"") val path = mediaResponse.body.string().substringAfter("replace(\"").substringBefore("\"")
if (path == "/404") return Pair(emptyList(), "") if (path == "/404") return Pair(emptyList(), "")
val mediaUrl = "https://" + mediaResponse.request.url.host + path val mediaUrl = "https://" + mediaResponse.request.url.host + path
@ -322,30 +302,6 @@ class UHDMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
return Pair(videoList, mediaUrl) return Pair(videoList, mediaUrl)
} }
private fun getCookiesDetail(page: String): Triple<String, String, String> {
val cat = "rdst_cat"
val post = "rdst_post"
val longC = page.substringAfter(".setTime")
.substringAfter("document.cookie = \"")
.substringBefore("\"")
.substringBefore(";")
val catC = if (page.contains("$cat=")) {
page.substringAfterLast("$cat=")
.substringBefore(";").let {
"$cat=$it"
}
} else { "" }
val postC = if (page.contains("$post=")) {
page.substringAfterLast("$post=")
.substringBefore(";").let {
"$post=$it"
}
} else { "" }
return Triple(longC, catC, postC)
}
private val sizeRegex = "\\[((?:.(?!\\[))+)] *\$".toRegex(RegexOption.IGNORE_CASE) private val sizeRegex = "\\[((?:.(?!\\[))+)] *\$".toRegex(RegexOption.IGNORE_CASE)
private fun extractWorkerLinks(mediaUrl: String, quality: String, type: Int): List<Video> { private fun extractWorkerLinks(mediaUrl: String, quality: String, type: Int): List<Video> {