From 36a21da8c95a01455c36d54c25ff6be154ecbbd6 Mon Sep 17 00:00:00 2001 From: WebDitto Date: Sat, 8 Mar 2025 15:57:51 -0300 Subject: [PATCH] fix(pt/anitube): Fixed pt/Anitube source (#799) (fix #728) --- src/pt/anitube/build.gradle | 2 +- .../pt/anitube/extractors/AnitubeExtractor.kt | 166 ++++++++++++------ 2 files changed, 115 insertions(+), 53 deletions(-) diff --git a/src/pt/anitube/build.gradle b/src/pt/anitube/build.gradle index d20560a0..9f22f339 100644 --- a/src/pt/anitube/build.gradle +++ b/src/pt/anitube/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'Anitube' extClass = '.Anitube' - extVersionCode = 23 + extVersionCode = 24 } apply from: "$rootDir/common.gradle" diff --git a/src/pt/anitube/src/eu/kanade/tachiyomi/animeextension/pt/anitube/extractors/AnitubeExtractor.kt b/src/pt/anitube/src/eu/kanade/tachiyomi/animeextension/pt/anitube/extractors/AnitubeExtractor.kt index ddf1dcb4..1736832d 100644 --- a/src/pt/anitube/src/eu/kanade/tachiyomi/animeextension/pt/anitube/extractors/AnitubeExtractor.kt +++ b/src/pt/anitube/src/eu/kanade/tachiyomi/animeextension/pt/anitube/extractors/AnitubeExtractor.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.animeextension.pt.anitube.extractors import android.content.SharedPreferences +import android.util.Base64 import android.util.Log import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.network.GET @@ -14,6 +15,9 @@ import okhttp3.OkHttpClient import okhttp3.Request import org.jsoup.nodes.Document import java.net.ProtocolException +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale class AnitubeExtractor( private val headers: Headers, @@ -132,32 +136,86 @@ class AnitubeExtractor( return "https://widgets.outbrain.com/outbrain.js" } - private fun getAuthCode(serverUrl: String, thumbUrl: String, link: String): String { - var authCode = preferences.getString(PREF_AUTHCODE_KEY, "")!! + private fun getAuthCode(serverUrl: String, thumbUrl: String, link: String): String? { + try { + var authCode = preferences.getString(PREF_AUTHCODE_KEY, "")!! - if (authCode.isNotBlank()) { - Log.d(tag, "AuthCode found in preferences") + if (authCode.isNotBlank()) { + 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) { - Log.d(tag, "AuthCode is OK") + 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") + return authCode + } + Log.d(tag, "AuthCode is invalid") + } + + Log.d(tag, "Fetching new authCode") + + val adsUrl = getAdsUrl(serverUrl, thumbUrl, link, headers) + + val adsContent = client.newCall(GET(adsUrl)).execute().body.string() + + val body = FormBody.Builder() + .add("category", "client") + .add("type", "premium") + .add("ad", adsContent) + .build() + + 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() + + authCode = + client.newCall(POST(ADS_URL, headers = newHeaders, body = body)) + .execute() + .body.string() + .substringAfter("\"publicidade\"") + .substringAfter('"') + .substringBefore('"') + + if (authCode.startsWith("?wmsAuthSign=")) { + Log.d(tag, "Auth code fetched successfully") + preferences.edit().putString(PREF_AUTHCODE_KEY, authCode).commit() return authCode } - Log.d(tag, "AuthCode is invalid") + + Log.e( + tag, + "Failed to fetch \"publicidade\" code, the current response: $authCode", + ) + } catch (e: Exception) { + Log.e(tag, e.toString()) } - Log.d(tag, "Fetching new authCode") + preferences.edit().putString(PREF_AUTHCODE_KEY, "").commit() - val adsUrl = getAdsUrl(serverUrl, thumbUrl, link, headers) + return null + } - val adsContent = client.newCall(GET(adsUrl)).execute().body.string() - - val body = FormBody.Builder() - .add("category", "client") - .add("type", "premium") - .add("ad", adsContent) - .build() + private fun getVideoToken(videoUrl: String, authCode: String?): String { + val token = authCode ?: "undefined" val newHeaders = headers.newBuilder() .set("Referer", "https://${SITE_URL.toHttpUrl().host}/") @@ -170,27 +228,10 @@ class AnitubeExtractor( .add("Sec-Fetch-Site", "same-site") .build() - val publicidade = - client.newCall(POST(ADS_URL, headers = newHeaders, body = body)) - .execute() - .body.string() - .substringAfter("\"publicidade\"") - .substringAfter('"') - .substringBefore('"') - - if (publicidade.isBlank()) { - Log.e( - tag, - "Failed to fetch \"publicidade\" code, the current response: $publicidade", - ) - - throw Exception("Por favor, abra o vĂ­deo uma vez no navegador para liberar o IP") - } - - authCode = + val videoToken = client.newCall( GET( - "$ADS_URL?token=$publicidade", + "$ADS_URL?token=$token&url=$videoUrl", headers = newHeaders, ), ) @@ -200,25 +241,25 @@ class AnitubeExtractor( .substringAfter('"') .substringBefore('"') - if (authCode.startsWith("?")) { - Log.d(tag, "Auth code fetched successfully") - preferences.edit().putString(PREF_AUTHCODE_KEY, authCode).commit() - } else { - Log.e( - tag, - "Failed to fetch auth code, the current response: $authCode", - ) + if (videoToken.startsWith("?")) { + Log.d(tag, "Video token fetched successfully") + return videoToken } - return authCode + Log.e( + tag, + "Failed to fetch video token, the current response: $videoToken", + ) + + return "" } fun getVideoList(doc: Document): List