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'
|
extName = 'Animes House'
|
||||||
pkgNameSuffix = 'pt.animeshouse'
|
pkgNameSuffix = 'pt.animeshouse'
|
||||||
extClass = '.AnimesHouse'
|
extClass = '.AnimesHouse'
|
||||||
extVersionCode = 1
|
extVersionCode = 2
|
||||||
libVersion = '13'
|
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.JsUnpacker
|
||||||
import eu.kanade.tachiyomi.animeextension.pt.animeshouse.extractors.McpExtractor
|
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.MpFourDooExtractor
|
||||||
|
import eu.kanade.tachiyomi.animeextension.pt.animeshouse.extractors.RedplayBypasser
|
||||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
||||||
@ -119,7 +120,11 @@ class AnimesHouse : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
.execute()
|
.execute()
|
||||||
.asJsoup()
|
.asJsoup()
|
||||||
val iframe = doc.selectFirst("iframe")
|
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> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
@ -128,7 +133,9 @@ class AnimesHouse : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
val videoList = mutableListOf<Video>()
|
val videoList = mutableListOf<Video>()
|
||||||
players.forEach { player ->
|
players.forEach { player ->
|
||||||
val url = getPlayerUrl(player)
|
val url = getPlayerUrl(player)
|
||||||
videoList.addAll(getPlayerVideos(url))
|
val videos = runCatching { getPlayerVideos(url) }
|
||||||
|
.getOrNull() ?: emptyList<Video>()
|
||||||
|
videoList.addAll(videos)
|
||||||
}
|
}
|
||||||
return videoList
|
return videoList
|
||||||
}
|
}
|
||||||
@ -143,7 +150,7 @@ class AnimesHouse : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
"embed.php?" in url ->
|
"embed.php?" in url ->
|
||||||
EmbedExtractor(headers).getVideoList(url, iframeBody)
|
EmbedExtractor(headers).getVideoList(url, iframeBody)
|
||||||
"edifier" in url ->
|
"edifier" in url ->
|
||||||
EdifierExtractor(client, headers).getVideoList(url, iframeBody)
|
EdifierExtractor(client, headers).getVideoList(url)
|
||||||
"mp4doo" in url ->
|
"mp4doo" in url ->
|
||||||
MpFourDooExtractor(headers).getVideoList(unpackedBody)
|
MpFourDooExtractor(headers).getVideoList(unpackedBody)
|
||||||
"clp-new" in url || "gcloud" in url ->
|
"clp-new" in url || "gcloud" in url ->
|
||||||
@ -241,7 +248,7 @@ class AnimesHouse : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
anime.genre = sheader.select("div.data > div.sgeneros > a")
|
anime.genre = sheader.select("div.data > div.sgeneros > a")
|
||||||
.joinToString(", ") { it.text() }
|
.joinToString(", ") { it.text() }
|
||||||
val info = doc.selectFirst("div#info")
|
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("Título")?.let { description += "$it" }
|
||||||
info.getInfo("Ano")?.let { description += "$it" }
|
info.getInfo("Ano")?.let { description += "$it" }
|
||||||
info.getInfo("Temporadas")?.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 REGEX_EDIFIER = Regex(""""file":"(.*?)","label":"(\S+?)"""")
|
||||||
private val PLAYER_NAME = "EDIFIER"
|
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 apiUrl = url.replace("/v/", "/api/source/")
|
||||||
val req = client.newCall(POST(apiUrl)).execute()
|
val req = client.newCall(POST(apiUrl)).execute()
|
||||||
val body = req.body?.string().orEmpty()
|
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