Skip to content

Commit

Permalink
fix(pt/animesdigital): Fix video extractor (#2892)
Browse files Browse the repository at this point in the history
  • Loading branch information
Claudemirovsky authored Feb 8, 2024
1 parent 566b9e4 commit a77dcad
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 57 deletions.
2 changes: 1 addition & 1 deletion src/pt/animesdigital/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ apply from: "$rootDir/common.gradle"

dependencies {
implementation(project(":lib:unpacker"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@ 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
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
Expand All @@ -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() {

Expand All @@ -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)
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -156,15 +153,15 @@ class AnimesDigital : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
else -> SAnime.UNKNOWN
}

val infos = doc.selectFirst("div.crw > div.dados")!!

artist = infos.getInfo("Estúdio")
author = infos.getInfo("Autor") ?: infos.getInfo("Diretor")
with(doc.selectFirst("div.crw > div.dados")!!) {
artist = getInfo("Estúdio")
author = getInfo("Autor") ?: getInfo("Diretor")

title = infos.selectFirst("h1")!!.text()
genre = infos.select("div.genre a").eachText().joinToString()
title = selectFirst("h1")!!.text()
genre = select("div.genre a").eachText().joinToString()

description = infos.selectFirst("div.sinopse")?.text()
description = selectFirst("div.sinopse")?.text()
}
}

// ============================== Episodes ==============================
Expand Down Expand Up @@ -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)
}
}
}
Expand All @@ -207,60 +204,38 @@ 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() }
}
}
}

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()
Expand All @@ -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 ==============================
Expand All @@ -312,12 +287,6 @@ class AnimesDigital : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
}
}

private fun String.substringAfterKey() = substringAfter(":")
.substringAfter('"')
.substringBefore('"')
.substringAfter("'")
.substringBefore("'")

companion object {
const val PREFIX_SEARCH = "id:"

Expand Down
Original file line number Diff line number Diff line change
@@ -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))
}
}
Original file line number Diff line number Diff line change
@@ -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("'")
}

0 comments on commit a77dcad

Please sign in to comment.