fix(pt/animesdigital): Fix video extractor (#2892)
This commit is contained in:
parent
566b9e43f0
commit
a77dcad9cf
@ -3,6 +3,8 @@ package eu.kanade.tachiyomi.animeextension.pt.animesdigital
|
||||
import android.app.Application
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.animeextension.pt.animesdigital.extractors.ProtectorExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.pt.animesdigital.extractors.ScriptExtractor
|
||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
||||
@ -10,14 +12,12 @@ import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
||||
import eu.kanade.tachiyomi.lib.unpacker.Unpacker
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import eu.kanade.tachiyomi.util.parseAs
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.Request
|
||||
@ -27,7 +27,6 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class AnimesDigital : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
|
||||
@ -41,8 +40,6 @@ class AnimesDigital : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
|
||||
override fun headersBuilder() = super.headersBuilder().add("Referer", baseUrl)
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
private val preferences by lazy {
|
||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
}
|
||||
@ -126,7 +123,7 @@ class AnimesDigital : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun searchAnimeParse(response: Response): AnimesPage {
|
||||
return runCatching {
|
||||
val data = response.parseAs<SearchResponseDto>()
|
||||
val animes = data.results.map(Jsoup::parse)
|
||||
val animes = data.results.map(Jsoup::parseBodyFragment)
|
||||
.mapNotNull { it.selectFirst(searchAnimeSelector()) }
|
||||
.map(::searchAnimeFromElement)
|
||||
val hasNext = data.total_page > data.page
|
||||
@ -156,15 +153,15 @@ class AnimesDigital : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
else -> SAnime.UNKNOWN
|
||||
}
|
||||
|
||||
val infos = doc.selectFirst("div.crw > div.dados")!!
|
||||
with(doc.selectFirst("div.crw > div.dados")!!) {
|
||||
artist = getInfo("Estúdio")
|
||||
author = getInfo("Autor") ?: getInfo("Diretor")
|
||||
|
||||
artist = infos.getInfo("Estúdio")
|
||||
author = infos.getInfo("Autor") ?: infos.getInfo("Diretor")
|
||||
title = selectFirst("h1")!!.text()
|
||||
genre = select("div.genre a").eachText().joinToString()
|
||||
|
||||
title = infos.selectFirst("h1")!!.text()
|
||||
genre = infos.select("div.genre a").eachText().joinToString()
|
||||
|
||||
description = infos.selectFirst("div.sinopse")?.text()
|
||||
description = selectFirst("div.sinopse")?.text()
|
||||
}
|
||||
}
|
||||
|
||||
// ============================== Episodes ==============================
|
||||
@ -195,9 +192,9 @@ class AnimesDigital : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
episode_number = epname.substringAfterLast(" ").toFloatOrNull() ?: 1F
|
||||
name = buildString {
|
||||
append(epname)
|
||||
element.selectFirst("div.sub_title")?.text()?.let {
|
||||
element.selectFirst("div.sub_title")?.text()?.also {
|
||||
if (!it.contains("Ainda não tem um titulo oficial")) {
|
||||
append(" - $it")
|
||||
append(" - ", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -207,7 +204,9 @@ class AnimesDigital : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoListParse(response: Response): List<Video> {
|
||||
val player = response.asJsoup().selectFirst("div#player")!!
|
||||
return player.select("div.tab-video").flatMap { div ->
|
||||
div.select(videoListSelector()).flatMap { element ->
|
||||
val noComment = div.outerHtml().replace("<!--", "").replace("-->", "")
|
||||
val newDoc = Jsoup.parseBodyFragment(noComment)
|
||||
newDoc.select(videoListSelector()).ifEmpty { newDoc.select("a") }.flatMap { element ->
|
||||
runCatching {
|
||||
videosFromElement(element)
|
||||
}.onFailure { it.printStackTrace() }.getOrElse { emptyList() }
|
||||
@ -215,52 +214,28 @@ class AnimesDigital : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
}
|
||||
|
||||
private val protectorExtractor by lazy { ProtectorExtractor(client) }
|
||||
|
||||
private fun videosFromElement(element: Element): List<Video> {
|
||||
return when (element.tagName()) {
|
||||
"iframe" -> {
|
||||
val url = element.attr("data-lazy-src").ifEmpty { element.attr("src") }
|
||||
.let {
|
||||
when {
|
||||
it.startsWith("/") -> baseUrl + it
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
val url = element.absUrl("data-lazy-src").ifEmpty { element.absUrl("src") }
|
||||
|
||||
client.newCall(GET(url, headers)).execute()
|
||||
.asJsoup()
|
||||
.select(videoListSelector())
|
||||
.flatMap(::videosFromElement)
|
||||
}
|
||||
"script" -> {
|
||||
val scriptData = element.data().let {
|
||||
when {
|
||||
"eval(function" in it -> Unpacker.unpack(it)
|
||||
else -> it
|
||||
}
|
||||
}.ifEmpty { null }?.replace("\\", "")
|
||||
scriptData?.let(::videosFromScript).orEmpty()
|
||||
}
|
||||
"script" -> ScriptExtractor.videosFromScript(element.data(), headers)
|
||||
"a" -> protectorExtractor.videosFromUrl(element.attr("href"))
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun videosFromScript(script: String): List<Video> {
|
||||
return script.substringAfter("sources:").substringAfter(".src(")
|
||||
.substringBefore(")")
|
||||
.substringAfter("[")
|
||||
.substringBefore("]")
|
||||
.split("{")
|
||||
.drop(1)
|
||||
.map {
|
||||
val quality = it.substringAfter("label", "")
|
||||
.substringAfterKey()
|
||||
.ifEmpty { name }
|
||||
val url = it.substringAfter("file").substringAfter("src")
|
||||
.substringAfterKey()
|
||||
Video(url, quality, url, headers)
|
||||
}
|
||||
}
|
||||
private val scriptSelectors = listOf("eval", "player.src", "this.src", "sources:")
|
||||
.joinToString { "script:containsData($it):not(:containsData(/bg.mp4))" }
|
||||
|
||||
override fun videoListSelector() = "iframe, script:containsData(eval), script:containsData(player.src), script:containsData(this.src), script:containsData(sources:)"
|
||||
override fun videoListSelector() = "iframe, $scriptSelectors"
|
||||
|
||||
override fun videoFromElement(element: Element): Video {
|
||||
throw UnsupportedOperationException()
|
||||
@ -285,7 +260,7 @@ class AnimesDigital : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val entry = entryValues[index] as String
|
||||
preferences.edit().putString(key, entry).commit()
|
||||
}
|
||||
}.let(screen::addPreference)
|
||||
}.also(screen::addPreference)
|
||||
}
|
||||
|
||||
// ============================= Utilities ==============================
|
||||
@ -312,12 +287,6 @@ class AnimesDigital : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.substringAfterKey() = substringAfter(":")
|
||||
.substringAfter('"')
|
||||
.substringBefore('"')
|
||||
.substringAfter("'")
|
||||
.substringBefore("'")
|
||||
|
||||
companion object {
|
||||
const val PREFIX_SEARCH = "id:"
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
package eu.kanade.tachiyomi.animeextension.pt.animesdigital.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
private const val HOST = "https://sabornutritivo.com"
|
||||
|
||||
class ProtectorExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val fixedUrl = if (!url.startsWith("https")) "https:$url" else url
|
||||
val token = fixedUrl.toHttpUrl().queryParameter("token")!!
|
||||
val headers = Headers.headersOf("cookie", "token=$token;")
|
||||
val doc = client.newCall(GET("$HOST/social.php", headers)).execute().asJsoup()
|
||||
val videoHeaders = Headers.headersOf("referer", doc.location())
|
||||
val iframeUrl = doc.selectFirst("iframe")!!.attr("src").trim()
|
||||
return listOf(Video(iframeUrl, "Animes Digital", iframeUrl, videoHeaders))
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package eu.kanade.tachiyomi.animeextension.pt.animesdigital.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.lib.unpacker.Unpacker
|
||||
import okhttp3.Headers
|
||||
|
||||
object ScriptExtractor {
|
||||
fun videosFromScript(scriptData: String, headers: Headers): List<Video> {
|
||||
val script = when {
|
||||
"eval(function" in scriptData -> Unpacker.unpack(scriptData)
|
||||
else -> scriptData
|
||||
}.ifEmpty { null }?.replace("\\", "") ?: return emptyList()
|
||||
|
||||
return script.substringAfter("sources:").substringAfter(".src(")
|
||||
.substringBefore(")")
|
||||
.substringAfter("[")
|
||||
.substringBefore("]")
|
||||
.split("{")
|
||||
.drop(1)
|
||||
.map {
|
||||
val quality = it.substringAfter("label", "")
|
||||
.substringAfterKey()
|
||||
.trim()
|
||||
.ifEmpty { "Animes Digital" }
|
||||
val url = it.substringAfter("file").substringAfter("src")
|
||||
.substringAfterKey()
|
||||
.trim()
|
||||
Video(url, quality, url, headers)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.substringAfterKey() = substringAfter(':')
|
||||
.substringAfter('"')
|
||||
.substringBefore('"')
|
||||
.substringAfter("'")
|
||||
.substringBefore("'")
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user