fix(pt/anitube): Fixed pt/Anitube source (#799) (fix #728)

This commit is contained in:
WebDitto 2025-03-08 15:57:51 -03:00 committed by GitHub
parent 8f42c60765
commit 36a21da8c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 115 additions and 53 deletions

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Anitube' extName = 'Anitube'
extClass = '.Anitube' extClass = '.Anitube'
extVersionCode = 23 extVersionCode = 24
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.animeextension.pt.anitube.extractors package eu.kanade.tachiyomi.animeextension.pt.anitube.extractors
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Base64
import android.util.Log import android.util.Log
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
@ -14,6 +15,9 @@ import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import java.net.ProtocolException import java.net.ProtocolException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class AnitubeExtractor( class AnitubeExtractor(
private val headers: Headers, private val headers: Headers,
@ -132,15 +136,28 @@ class AnitubeExtractor(
return "https://widgets.outbrain.com/outbrain.js" return "https://widgets.outbrain.com/outbrain.js"
} }
private fun getAuthCode(serverUrl: String, thumbUrl: String, link: String): String { private fun getAuthCode(serverUrl: String, thumbUrl: String, link: String): String? {
try {
var authCode = preferences.getString(PREF_AUTHCODE_KEY, "")!! var authCode = preferences.getString(PREF_AUTHCODE_KEY, "")!!
if (authCode.isNotBlank()) { if (authCode.isNotBlank()) {
Log.d(tag, "AuthCode found in preferences") Log.d(tag, "AuthCode found in preferences")
val response = checkVideoExists("${serverUrl}$authCode") val authArgs = Base64.decode(authCode.substringAfter("="), Base64.DEFAULT).let(::String)
val url = "$serverUrl?$authArgs".toHttpUrl()
if (response.exists || response.code == 500) { val serverTime =
SimpleDateFormat("M/d/yyyy h:m:s a", Locale.ENGLISH).parse(
url.queryParameter("server_time") ?: "",
)
val calendar = Calendar.getInstance()
serverTime?.let { calendar.setTime(it) }
url.queryParameter("validminutes")?.toInt()
?.let { calendar.add(Calendar.MINUTE, it) }
if (Calendar.getInstance() < calendar) {
Log.d(tag, "AuthCode is OK") Log.d(tag, "AuthCode is OK")
return authCode return authCode
} }
@ -170,7 +187,7 @@ class AnitubeExtractor(
.add("Sec-Fetch-Site", "same-site") .add("Sec-Fetch-Site", "same-site")
.build() .build()
val publicidade = authCode =
client.newCall(POST(ADS_URL, headers = newHeaders, body = body)) client.newCall(POST(ADS_URL, headers = newHeaders, body = body))
.execute() .execute()
.body.string() .body.string()
@ -178,19 +195,43 @@ class AnitubeExtractor(
.substringAfter('"') .substringAfter('"')
.substringBefore('"') .substringBefore('"')
if (publicidade.isBlank()) { if (authCode.startsWith("?wmsAuthSign=")) {
Log.e( Log.d(tag, "Auth code fetched successfully")
tag, preferences.edit().putString(PREF_AUTHCODE_KEY, authCode).commit()
"Failed to fetch \"publicidade\" code, the current response: $publicidade", return authCode
)
throw Exception("Por favor, abra o vídeo uma vez no navegador para liberar o IP")
} }
authCode = Log.e(
tag,
"Failed to fetch \"publicidade\" code, the current response: $authCode",
)
} catch (e: Exception) {
Log.e(tag, e.toString())
}
preferences.edit().putString(PREF_AUTHCODE_KEY, "").commit()
return null
}
private fun getVideoToken(videoUrl: String, authCode: String?): String {
val token = authCode ?: "undefined"
val newHeaders = headers.newBuilder()
.set("Referer", "https://${SITE_URL.toHttpUrl().host}/")
.add("Accept", "*/*")
.add("Cache-Control", "no-cache")
.add("Pragma", "no-cache")
.add("Connection", "keep-alive")
.add("Sec-Fetch-Dest", "empty")
.add("Sec-Fetch-Mode", "cors")
.add("Sec-Fetch-Site", "same-site")
.build()
val videoToken =
client.newCall( client.newCall(
GET( GET(
"$ADS_URL?token=$publicidade", "$ADS_URL?token=$token&url=$videoUrl",
headers = newHeaders, headers = newHeaders,
), ),
) )
@ -200,25 +241,25 @@ class AnitubeExtractor(
.substringAfter('"') .substringAfter('"')
.substringBefore('"') .substringBefore('"')
if (authCode.startsWith("?")) { if (videoToken.startsWith("?")) {
Log.d(tag, "Auth code fetched successfully") Log.d(tag, "Video token fetched successfully")
preferences.edit().putString(PREF_AUTHCODE_KEY, authCode).commit() return videoToken
} else {
Log.e(
tag,
"Failed to fetch auth code, the current response: $authCode",
)
} }
return authCode Log.e(
tag,
"Failed to fetch video token, the current response: $videoToken",
)
return ""
} }
fun getVideoList(doc: Document): List<Video> { fun getVideoList(doc: Document): List<Video> {
Log.d(tag, "Starting to fetch video list")
val hasFHD = doc.selectFirst("div.abaItem:contains(FULLHD)") != null val hasFHD = doc.selectFirst("div.abaItem:contains(FULLHD)") != null
val serverUrl = doc.selectFirst("meta[itemprop=contentURL]")!! val serverUrl = doc.selectFirst("meta[itemprop=contentURL]")!!
.attr("content") .attr("content")
.replace("cdn1", "cdn3")
.replace("cdn80", "cdn8")
val thumbUrl = doc.selectFirst("meta[itemprop=thumbnailUrl]")!! val thumbUrl = doc.selectFirst("meta[itemprop=thumbnailUrl]")!!
.attr("content") .attr("content")
val type = serverUrl.split("/").get(3) val type = serverUrl.split("/").get(3)
@ -231,6 +272,8 @@ class AnitubeExtractor(
} }
} + listOf("appfullhd") } + listOf("appfullhd")
Log.d(tag, "Found ${paths.size} videos")
val firstLink = val firstLink =
doc.selectFirst("div.video_container > a, div.playerContainer > a")!!.attr("href") doc.selectFirst("div.video_container > a, div.playerContainer > a")!!.attr("href")
@ -240,17 +283,36 @@ class AnitubeExtractor(
.mapIndexed { index, quality -> .mapIndexed { index, quality ->
object { object {
var path = paths[index] var path = paths[index]
var url = serverUrl.replace(type, path) + authCode var url = serverUrl.replace(type, path)
var quality = "$quality - Anitube" var quality = "$quality - Anitube"
} }
} }
.parallelCatchingFlatMapBlocking { .parallelCatchingFlatMapBlocking {
if (!checkVideoExists(it.url).exists) { if (!authCode.isNullOrBlank() && checkVideoExists(it.url + authCode).exists) {
return@parallelCatchingFlatMapBlocking listOf(
Video(
it.url + authCode,
it.quality,
it.url + authCode,
headers = headers,
),
)
}
val videoToken = getVideoToken(it.url, authCode)
if (videoToken.isNotBlank() && checkVideoExists(it.url + videoToken).exists) {
return@parallelCatchingFlatMapBlocking listOf(
Video(
it.url + videoToken,
it.quality,
it.url + videoToken,
headers = headers,
),
)
}
Log.d(tag, "Video not exists: ${it.url.substringBefore("?")}") Log.d(tag, "Video not exists: ${it.url.substringBefore("?")}")
return@parallelCatchingFlatMapBlocking emptyList() return@parallelCatchingFlatMapBlocking emptyList()
} }
listOf(Video(it.url, it.quality, it.url, headers = headers))
}
.reversed() .reversed()
} }