HentaiCube: update base URL (#11498)

* HentaiCube: update base URL

* Validate custom domain and apply directly

* update base URL on redirect
This commit is contained in:
Cuong-Tran 2025-11-12 12:38:28 +07:00 committed by Draff
parent 4c73cc5e75
commit 5578344e19
Signed by: Draff
GPG Key ID: E8A89F3211677653
2 changed files with 77 additions and 12 deletions

View File

@ -2,8 +2,8 @@ ext {
extName = 'CBHentai'
extClass = '.HentaiCB'
themePkg = 'madara'
baseUrl = 'https://hentaicb.help'
overrideVersionCode = 20
baseUrl = 'https://hentaicb.live'
overrideVersionCode = 21
isNsfw = true
}

View File

@ -1,7 +1,9 @@
package eu.kanade.tachiyomi.extension.vi.hentaicube
import android.content.SharedPreferences
import android.widget.Toast
import android.text.Editable
import android.text.TextWatcher
import android.widget.Button
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.multisrc.madara.Madara
@ -25,7 +27,7 @@ import java.util.Locale
class HentaiCB :
Madara(
"CBHentai",
"https://hentaicb.help",
"https://hentaicb.live",
"vi",
SimpleDateFormat("dd/MM/yyyy", Locale("vi")),
),
@ -35,9 +37,39 @@ class HentaiCB :
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.rateLimit(3)
.followRedirects(false)
.addInterceptor { chain ->
val maxRedirects = 5
var request = chain.request()
var response = chain.proceed(request)
var redirectCount = 0
while (response.isRedirect && redirectCount < maxRedirects) {
val newUrl = response.header("Location") ?: break
val newUrlHttp = newUrl.toHttpUrl()
val redirectedDomain = newUrlHttp.run { "$scheme://$host" }
if (redirectedDomain != baseUrl) {
synchronized(prefsLock) {
preferences.edit().putString(BASE_URL_PREF, redirectedDomain).commit()
}
}
response.close()
request = request.newBuilder()
.url(newUrlHttp)
.build()
response = chain.proceed(request)
redirectCount++
}
if (redirectCount >= maxRedirects) {
response.close()
throw java.io.IOException("Too many redirects: $maxRedirects")
}
response
}
.build()
private val preferences: SharedPreferences = getPreferences()
private val prefsLock = Any()
init {
preferences.getString(DEFAULT_BASE_URL_PREF, null).let { prefDefaultBaseUrl ->
@ -49,9 +81,12 @@ class HentaiCB :
}
}
}
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, super.baseUrl)!!
private fun getPrefBaseUrl(): String = synchronized(prefsLock) {
preferences.getString(BASE_URL_PREF, super.baseUrl)!!
}
override val baseUrl by lazy { getPrefBaseUrl() }
override val baseUrl: String
get() = getPrefBaseUrl().ifBlank { super.baseUrl }
override val filterNonMangaItems = false
@ -114,24 +149,54 @@ class HentaiCB :
EditTextPreference(screen.context).apply {
key = BASE_URL_PREF
title = BASE_URL_PREF_TITLE
summary = BASE_URL_PREF_SUMMARY
summary = "$BASE_URL_PREF_SUMMARY${getPrefBaseUrl()}"
setDefaultValue(super.baseUrl)
dialogTitle = BASE_URL_PREF_TITLE
dialogMessage = "Default: ${super.baseUrl}"
setOnPreferenceChangeListener { _, _ ->
Toast.makeText(screen.context, RESTART_APP, Toast.LENGTH_LONG).show()
true
val validate = { str: String ->
if (str.isBlank()) {
true
} else {
runCatching { str.toHttpUrl() }.isSuccess && domainRegex.matchEntire(str) != null
}
}
setOnBindEditTextListener { editText ->
editText.addTextChangedListener(
object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(editable: Editable?) {
editable ?: return
val text = editable.toString()
val valid = validate(text)
editText.error = if (!valid) "https://example.com" else null
editText.rootView.findViewById<Button>(android.R.id.button1)?.isEnabled = editText.error == null
}
},
)
}
setOnPreferenceChangeListener { _, newValue ->
val isValid = validate(newValue as String)
if (isValid) {
summary = "$BASE_URL_PREF_SUMMARY$newValue"
}
isValid
}
}.let(screen::addPreference)
}
companion object {
private const val DEFAULT_BASE_URL_PREF = "defaultBaseUrl"
private const val RESTART_APP = "Khởi chạy lại ứng dụng để áp dụng thay đổi."
private const val BASE_URL_PREF_TITLE = "Ghi đè URL cơ sở"
private const val BASE_URL_PREF = "overrideBaseUrl"
private const val BASE_URL_PREF_SUMMARY =
"Dành cho sử dụng tạm thời, cập nhật tiện ích sẽ xóa cài đặt."
"Dành cho sử dụng tạm thời, cập nhật tiện ích sẽ xóa cài đặt.\n" +
"Để trống để sử dụng URL mặc định.\n" +
"Hiện tại sử dụng: "
private val domainRegex = Regex("""^https?://(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9]{1,6}$""")
}
}