Taiyo: Fix token (#6045)

Fix token
This commit is contained in:
Chopper 2024-11-14 03:37:26 -03:00 committed by Draff
parent dbfe27e7a3
commit f84ec7c418
No known key found for this signature in database
GPG Key ID: E8A89F3211677653
2 changed files with 74 additions and 26 deletions

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'Taiyō' extName = 'Taiyō'
extClass = '.Taiyo' extClass = '.Taiyo'
extVersionCode = 2 extVersionCode = 3
isNsfw = true isNsfw = true
} }

View File

@ -1,5 +1,7 @@
package eu.kanade.tachiyomi.extension.pt.taiyo package eu.kanade.tachiyomi.extension.pt.taiyo
import android.app.Application
import android.content.SharedPreferences
import eu.kanade.tachiyomi.extension.pt.taiyo.dto.AdditionalInfoDto import eu.kanade.tachiyomi.extension.pt.taiyo.dto.AdditionalInfoDto
import eu.kanade.tachiyomi.extension.pt.taiyo.dto.ChapterListDto import eu.kanade.tachiyomi.extension.pt.taiyo.dto.ChapterListDto
import eu.kanade.tachiyomi.extension.pt.taiyo.dto.MediaChapterDto import eu.kanade.tachiyomi.extension.pt.taiyo.dto.MediaChapterDto
@ -25,13 +27,19 @@ import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.put import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonObject import kotlinx.serialization.json.putJsonObject
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response import okhttp3.Response
import okhttp3.internal.http.HTTP_FORBIDDEN
import okhttp3.internal.http.HTTP_UNAUTHORIZED
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import rx.Observable import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
@ -47,41 +55,28 @@ class Taiyo : ParsedHttpSource() {
// The source doesn't show the title on the home page // The source doesn't show the title on the home page
override val supportsLatest = false override val supportsLatest = false
private val preferences: SharedPreferences =
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
private var bearerToken: String = preferences.getString(BEARER_TOKEN_PREF, "").toString()
override val client = network.client.newBuilder() override val client = network.client.newBuilder()
.rateLimitHost(baseUrl.toHttpUrl(), 2) .rateLimitHost(baseUrl.toHttpUrl(), 2)
.rateLimitHost(IMG_CDN.toHttpUrl(), 2) .rateLimitHost(IMG_CDN.toHttpUrl(), 2)
.addInterceptor(::authorizationInterceptor)
.build() .build()
private val json: Json by injectLazy() private val json: Json by injectLazy()
// ============================== Popular =============================== // ============================== Popular ===============================
var bearerToken = ""
override fun popularMangaRequest(page: Int): Request { override fun popularMangaRequest(page: Int) = searchMangaRequest(page, "", FilterList())
if (bearerToken.isBlank()) {
getBearerToken()
}
return searchMangaRequest(page, "", FilterList())
}
override fun popularMangaParse(response: Response) = searchMangaParse(response) override fun popularMangaParse(response: Response) = searchMangaParse(response)
override fun popularMangaSelector() = throw UnsupportedOperationException() override fun popularMangaSelector() = throw UnsupportedOperationException()
override fun popularMangaFromElement(element: Element) = throw UnsupportedOperationException() override fun popularMangaFromElement(element: Element) = throw UnsupportedOperationException()
override fun popularMangaNextPageSelector() = null override fun popularMangaNextPageSelector() = null
private fun getBearerToken() {
val scriptUrl = client.newCall(GET(baseUrl, headers))
.execute().asJsoup()
.selectFirst("script[src*=ee07d8437723d9f5]")
?.attr("src") ?: throw Exception("Não foi possivel localizar o token")
val script = client.newCall(GET("$baseUrl$scriptUrl", headers))
.execute().body.string()
bearerToken = TOKEN_REGEX.find(script)?.groups?.get("token")?.value
?: throw Exception("Não foi possivel extrair o token")
}
// =============================== Latest =============================== // =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException() override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException()
override fun latestUpdatesSelector() = throw UnsupportedOperationException() override fun latestUpdatesSelector() = throw UnsupportedOperationException()
@ -128,13 +123,13 @@ class Taiyo : ParsedHttpSource() {
val requestBody = json.encodeToString(jsonObj).toRequestBody(MEDIA_TYPE) val requestBody = json.encodeToString(jsonObj).toRequestBody(MEDIA_TYPE)
val apiHeaders = headers.newBuilder() return POST("https://meilisearch.${baseUrl.substringAfterLast("/")}/multi-search", getApiHeaders(), requestBody)
}
private fun getApiHeaders() = headers.newBuilder()
.set("Authorization", "Bearer $bearerToken") .set("Authorization", "Bearer $bearerToken")
.build() .build()
return POST("https://meilisearch.${baseUrl.substringAfterLast("/")}/multi-search", apiHeaders, requestBody)
}
override fun searchMangaParse(response: Response): MangasPage { override fun searchMangaParse(response: Response): MangasPage {
val obj = response.parseAs<SearchResultDto>() val obj = response.parseAs<SearchResultDto>()
val mangas = obj.mangas.map { item -> val mangas = obj.mangas.map { item ->
@ -290,10 +285,63 @@ class Taiyo : ParsedHttpSource() {
}.onFailure { it.printStackTrace() }.getOrNull() }.onFailure { it.printStackTrace() }.getOrNull()
} }
// ============================= Authorization ========================
private fun authorizationInterceptor(chain: Interceptor.Chain): Response {
val request = chain.request()
val response = chain.proceed(request)
return when (response.code) {
in arrayOf(HTTP_UNAUTHORIZED, HTTP_FORBIDDEN) -> updateTokenAndContinueRequest(request, chain)
else -> response
}
}
private fun updateTokenAndContinueRequest(request: Request, chain: Interceptor.Chain): Response {
bearerToken = getToken()
val req = request.newBuilder()
.headers(getApiHeaders())
.build()
return chain.proceed(req)
}
private fun getToken(): String {
return fetchBearerToken().also {
preferences.edit()
.putString(BEARER_TOKEN_PREF, it)
.apply()
}
}
private fun fetchBearerToken(): String {
val scripts = client.newCall(GET(baseUrl, headers))
.execute().asJsoup()
.select("script[src*=next]:not([nomodule]):not([src*=app])")
val script = getScriptContainingToken(scripts)
?: throw Exception("Não foi possivel localizar o token")
return TOKEN_REGEX.find(script)?.groups?.get("token")?.value
?: throw Exception("Não foi possivel extrair o token")
}
private fun getScriptContainingToken(scripts: Elements): String? {
val elements = scripts.toList().reversed()
for (element in elements) {
val scriptUrl = element.attr("src")
val script = client.newCall(GET("$baseUrl$scriptUrl", headers))
.execute().body.string()
if (TOKEN_REGEX.containsMatchIn(script)) {
return script
}
}
return null
}
companion object { companion object {
const val PREFIX_SEARCH = "id:" const val PREFIX_SEARCH = "id:"
val CHAPTER_REGEX = """(?<chapters>\{"chapters".+"totalPages":\d+\})""".toRegex() val CHAPTER_REGEX = """(?<chapters>\{"chapters".+"totalPages":\d+\})""".toRegex()
val TOKEN_REGEX = """NEXT_PUBLIC_MEILISEARCH_PUBLIC_KEY:(\s+)?"(?<token>[^"]+)""".toRegex() val TOKEN_REGEX = """NEXT_PUBLIC_MEILISEARCH_PUBLIC_KEY:(\s+)?"(?<token>[^"]+)""".toRegex()
const val BEARER_TOKEN_PREF = "TAIYO_BEARER_TOKEN"
private const val IMG_CDN = "https://cdn.taiyo.moe/medias" private const val IMG_CDN = "https://cdn.taiyo.moe/medias"