GocTruyenTranhVui: Allows getting token for login in webview (#10887)
* GocTruyenTranhVui: Allows to get token. Support login Instead of always saving tokens in code. * Lines 118 to 143 move to getToken(), and not use postDelayed * Support enter token manually Support Suwayomi users who can't log in can still enter token manually
This commit is contained in:
parent
5ef2e36997
commit
a4c4090301
@ -1,7 +1,7 @@
|
|||||||
ext {
|
ext {
|
||||||
extName = 'Goc Truyen Tranh Vui'
|
extName = 'Goc Truyen Tranh Vui'
|
||||||
extClass = '.GocTruyenTranhVui'
|
extClass = '.GocTruyenTranhVui'
|
||||||
extVersionCode = 3
|
extVersionCode = 4
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,18 @@
|
|||||||
package eu.kanade.tachiyomi.extension.vi.goctruyentranhvui
|
package eu.kanade.tachiyomi.extension.vi.goctruyentranhvui
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.webkit.WebView
|
||||||
|
import android.webkit.WebViewClient
|
||||||
|
import androidx.preference.EditTextPreference
|
||||||
|
import androidx.preference.PreferenceScreen
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||||
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
@ -10,6 +20,7 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import keiyoushi.utils.getPreferences
|
||||||
import keiyoushi.utils.parseAs
|
import keiyoushi.utils.parseAs
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
@ -17,8 +28,12 @@ import okhttp3.HttpUrl.Companion.toHttpUrl
|
|||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class GocTruyenTranhVui : HttpSource() {
|
class GocTruyenTranhVui : HttpSource(), ConfigurableSource {
|
||||||
override val lang = "vi"
|
override val lang = "vi"
|
||||||
|
|
||||||
override val baseUrl = "https://goctruyentranhvui17.com"
|
override val baseUrl = "https://goctruyentranhvui17.com"
|
||||||
@ -29,6 +44,8 @@ class GocTruyenTranhVui : HttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest: Boolean = true
|
override val supportsLatest: Boolean = true
|
||||||
|
|
||||||
|
private val preferences: SharedPreferences = getPreferences()
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||||
.rateLimit(3)
|
.rateLimit(3)
|
||||||
.build()
|
.build()
|
||||||
@ -76,12 +93,12 @@ class GocTruyenTranhVui : HttpSource() {
|
|||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
|
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
title = document.selectFirst(".v-card-title")!!.text()
|
title = document.select(".v-card-title").text()
|
||||||
genre = document.select(".group-content > .v-chip-link").joinToString { it.text() }
|
genre = document.select(".group-content > .v-chip-link").joinToString { it.text() }
|
||||||
thumbnail_url = document.selectFirst("img.image")!!.absUrl("src")
|
thumbnail_url = document.selectFirst("img.image")?.absUrl("src")
|
||||||
status = parseStatus(document.selectFirst(".mb-1:contains(Trạng thái:) span")!!.text())
|
status = parseStatus(document.selectFirst(".mb-1:contains(Trạng thái:) span")?.text())
|
||||||
author = document.selectFirst(".mb-1:contains(Tác giả:) span")!!.text()
|
author = document.selectFirst(".mb-1:contains(Tác giả:) span")?.text()
|
||||||
description = document.selectFirst(".v-card-text")!!.text()
|
description = document.select(".v-card-text").joinToString { it.wholeText() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseStatus(status: String?) = when {
|
private fun parseStatus(status: String?) = when {
|
||||||
@ -103,8 +120,11 @@ class GocTruyenTranhVui : HttpSource() {
|
|||||||
val mangaId = matchId.groups[1]!!.value
|
val mangaId = matchId.groups[1]!!.value
|
||||||
val nameEn = response.request.url.toString().substringAfter("/truyen/").substringBefore("/")
|
val nameEn = response.request.url.toString().substringAfter("/truyen/").substringBefore("/")
|
||||||
val chapterNumber = response.request.url.toString().substringAfterLast("chuong-")
|
val chapterNumber = response.request.url.toString().substringAfterLast("chuong-")
|
||||||
val body = FormBody.Builder().add("comicId", mangaId)
|
val body = FormBody.Builder()
|
||||||
.add("chapterNumber", chapterNumber).add("nameEn", nameEn).build()
|
.add("comicId", mangaId)
|
||||||
|
.add("chapterNumber", chapterNumber)
|
||||||
|
.add("nameEn", nameEn)
|
||||||
|
.build()
|
||||||
val request = POST("$baseUrl/api/chapter/auth", pageHeaders, body)
|
val request = POST("$baseUrl/api/chapter/auth", pageHeaders, body)
|
||||||
client.newCall(request).execute().parseAs<ResultDto<ImageListDto>>().result.data
|
client.newCall(request).execute().parseAs<ResultDto<ImageListDto>>().result.data
|
||||||
} else {
|
} else {
|
||||||
@ -116,10 +136,49 @@ class GocTruyenTranhVui : HttpSource() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private val pageHeaders by lazy {
|
private val pageHeaders by lazy {
|
||||||
headersBuilder()
|
getToken()?.let {
|
||||||
.add("X-Requested-With", "XMLHttpRequest")
|
headersBuilder()
|
||||||
.add("Authorization", TOKEN_KEY)
|
.add("X-Requested-With", "XMLHttpRequest")
|
||||||
.build()
|
.add("Authorization", it)
|
||||||
|
.build()
|
||||||
|
} ?: throw Exception("Vui lòng đăng nhập trong WebView")
|
||||||
|
}
|
||||||
|
private var _token: String? = null
|
||||||
|
|
||||||
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
|
private fun getToken(): String? {
|
||||||
|
_token?.also { return it }
|
||||||
|
val handler = Handler(Looper.getMainLooper())
|
||||||
|
val latch = CountDownLatch(1)
|
||||||
|
val customToken = preferences.getString("custom_token", null)
|
||||||
|
if (!customToken.isNullOrBlank()) {
|
||||||
|
return customToken
|
||||||
|
}
|
||||||
|
if (_token != null) return _token
|
||||||
|
|
||||||
|
handler.post {
|
||||||
|
val webview = WebView(Injekt.get<Application>())
|
||||||
|
with(webview.settings) {
|
||||||
|
javaScriptEnabled = true
|
||||||
|
domStorageEnabled = true
|
||||||
|
databaseEnabled = true
|
||||||
|
blockNetworkImage = true
|
||||||
|
}
|
||||||
|
webview.webViewClient = object : WebViewClient() {
|
||||||
|
override fun onPageFinished(view: WebView?, url: String?) {
|
||||||
|
// Get token
|
||||||
|
view!!.evaluateJavascript("window.localStorage.getItem('Authorization')") { token ->
|
||||||
|
_token = token.takeUnless { it == "null" }?.removeSurrounding("\"")
|
||||||
|
latch.countDown()
|
||||||
|
webview.destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
webview.loadDataWithBaseURL(baseUrl, " ", "text/html", "UTF-8", null)
|
||||||
|
}
|
||||||
|
|
||||||
|
latch.await(10, TimeUnit.SECONDS)
|
||||||
|
return _token
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException()
|
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException()
|
||||||
@ -150,5 +209,15 @@ class GocTruyenTranhVui : HttpSource() {
|
|||||||
SortByList(getSortByList()),
|
SortByList(getSortByList()),
|
||||||
GenreList(getGenreList()),
|
GenreList(getGenreList()),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
|
val tokenPref = EditTextPreference(screen.context).apply {
|
||||||
|
key = "custom_token"
|
||||||
|
title = "Authorization Token"
|
||||||
|
summary = "Enter token manually"
|
||||||
|
dialogTitle = "Authorization Token"
|
||||||
|
dialogMessage = "Token: ${getToken()}"
|
||||||
|
}
|
||||||
|
screen.addPreference(tokenPref)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private const val TOKEN_KEY = "Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJEcmFrZW4iLCJjb21pY0lkcyI6W10sInJvbGVJZCI6bnVsbCwiZ3JvdXBJZCI6bnVsbCwiYWRtaW4iOmZhbHNlLCJyYW5rIjowLCJwZXJtaXNzaW9uIjpbXSwiaWQiOiIwMDAxMTE1OTg2IiwidGVhbSI6ZmFsc2UsImlhdCI6MTc1NzU5NjQxMSwiZW1haWwiOiJudWxsIn0.VcGDaVQvyowtvja04CTUpfCP5XiC5qIdPmANZL0Gjz2kjz__PJ8LATQ9s44FpNohMpgLgPQO0TVs67D_YFlLNw"
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user