AnimesHouse: Fix NPE and video extractor operation (#864)
* AnimesHouse: Fix NPE when fetching anime details * AnimesHouse: Remove useless parameter on EdifierExtractor * AnimesHouse: Bump version * AnimesHouse: Add bypasser to redplay video protector * AnimesHouse: Ignore errors when fetching videos
This commit is contained in:
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'Animes House'
|
||||
pkgNameSuffix = 'pt.animeshouse'
|
||||
extClass = '.AnimesHouse'
|
||||
extVersionCode = 1
|
||||
extVersionCode = 2
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.animeextension.pt.animeshouse.extractors.GenericExtra
|
||||
import eu.kanade.tachiyomi.animeextension.pt.animeshouse.extractors.JsUnpacker
|
||||
import eu.kanade.tachiyomi.animeextension.pt.animeshouse.extractors.McpExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.pt.animeshouse.extractors.MpFourDooExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.pt.animeshouse.extractors.RedplayBypasser
|
||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
||||
@ -119,7 +120,11 @@ class AnimesHouse : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
.execute()
|
||||
.asJsoup()
|
||||
val iframe = doc.selectFirst("iframe")
|
||||
return iframe.attr("src")
|
||||
return iframe.attr("src").let {
|
||||
if (it.startsWith("/redplay"))
|
||||
RedplayBypasser(client, headers).fromUrl(baseUrl + it)
|
||||
else it
|
||||
}
|
||||
}
|
||||
|
||||
override fun videoListParse(response: Response): List<Video> {
|
||||
@ -128,7 +133,9 @@ class AnimesHouse : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val videoList = mutableListOf<Video>()
|
||||
players.forEach { player ->
|
||||
val url = getPlayerUrl(player)
|
||||
videoList.addAll(getPlayerVideos(url))
|
||||
val videos = runCatching { getPlayerVideos(url) }
|
||||
.getOrNull() ?: emptyList<Video>()
|
||||
videoList.addAll(videos)
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
@ -143,7 +150,7 @@ class AnimesHouse : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
"embed.php?" in url ->
|
||||
EmbedExtractor(headers).getVideoList(url, iframeBody)
|
||||
"edifier" in url ->
|
||||
EdifierExtractor(client, headers).getVideoList(url, iframeBody)
|
||||
EdifierExtractor(client, headers).getVideoList(url)
|
||||
"mp4doo" in url ->
|
||||
MpFourDooExtractor(headers).getVideoList(unpackedBody)
|
||||
"clp-new" in url || "gcloud" in url ->
|
||||
@ -241,7 +248,7 @@ class AnimesHouse : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
anime.genre = sheader.select("div.data > div.sgeneros > a")
|
||||
.joinToString(", ") { it.text() }
|
||||
val info = doc.selectFirst("div#info")
|
||||
var description = info.selectFirst("p").text() + "\n"
|
||||
var description = info.selectFirst("p")?.let { it.text() + "\n" } ?: ""
|
||||
info.getInfo("Título")?.let { description += "$it" }
|
||||
info.getInfo("Ano")?.let { description += "$it" }
|
||||
info.getInfo("Temporadas")?.let { description += "$it" }
|
||||
|
@ -13,7 +13,7 @@ class EdifierExtractor(
|
||||
private val REGEX_EDIFIER = Regex(""""file":"(.*?)","label":"(\S+?)"""")
|
||||
private val PLAYER_NAME = "EDIFIER"
|
||||
|
||||
fun getVideoList(url: String, iframeBody: String): List<Video> {
|
||||
fun getVideoList(url: String): List<Video> {
|
||||
val apiUrl = url.replace("/v/", "/api/source/")
|
||||
val req = client.newCall(POST(apiUrl)).execute()
|
||||
val body = req.body?.string().orEmpty()
|
||||
|
@ -0,0 +1,57 @@
|
||||
package eu.kanade.tachiyomi.animeextension.pt.animeshouse.extractors
|
||||
|
||||
import android.util.Base64
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
class RedplayBypasser(
|
||||
private val client: OkHttpClient,
|
||||
private val headers: Headers
|
||||
) {
|
||||
|
||||
fun fromUrl(url: String): String {
|
||||
val firstDoc = client.newCall(GET(url, headers)).execute().asJsoup()
|
||||
val next = firstDoc.selectFirst("a").attr("href")
|
||||
var nextPage = client.newCall(GET(next, headers)).execute()
|
||||
var iframeUrl = ""
|
||||
var formUrl = next
|
||||
while (iframeUrl == "") {
|
||||
val nextDoc = nextPage.asJsoup(decodeAtob(nextPage.body!!.string()))
|
||||
val iframe = nextDoc.selectFirst("iframe")
|
||||
if (iframe != null)
|
||||
iframeUrl = iframe.attr("src")
|
||||
else {
|
||||
val newHeaders = headers.newBuilder()
|
||||
.set("Referer", formUrl)
|
||||
.build()
|
||||
val formBody = FormBody.Builder()
|
||||
formUrl = nextDoc.selectFirst("form").attr("action")
|
||||
nextDoc.select("input[name]").forEach {
|
||||
formBody.add(it.attr("name"), it.attr("value"))
|
||||
}
|
||||
nextPage = client.newCall(POST(formUrl, newHeaders, formBody.build()))
|
||||
.execute()
|
||||
}
|
||||
}
|
||||
return iframeUrl
|
||||
}
|
||||
|
||||
private fun decodeAtob(html: String): String {
|
||||
val atobContent = html.substringAfter("atob(\"").substringBefore("\"));")
|
||||
val hexAtob = atobContent.replace("\\x", "").decodeHex()
|
||||
val decoded = Base64.decode(hexAtob, Base64.DEFAULT)
|
||||
return String(decoded)
|
||||
}
|
||||
|
||||
// Stolen from AnimixPlay(EN) / GogoCdnExtractor
|
||||
private fun String.decodeHex(): ByteArray {
|
||||
check(length % 2 == 0) { "Must have an even length" }
|
||||
return chunked(2)
|
||||
.map { it.toInt(16).toByte() }
|
||||
.toByteArray()
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user