From 5578344e19099f808179c660892b9b15987c520c Mon Sep 17 00:00:00 2001 From: Cuong-Tran <16017808+cuong-tran@users.noreply.github.com> Date: Wed, 12 Nov 2025 12:38:28 +0700 Subject: [PATCH] HentaiCube: update base URL (#11498) * HentaiCube: update base URL * Validate custom domain and apply directly * update base URL on redirect --- src/vi/hentaicube/build.gradle | 4 +- .../extension/vi/hentaicube/HentaiCB.kt | 85 ++++++++++++++++--- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/src/vi/hentaicube/build.gradle b/src/vi/hentaicube/build.gradle index 28a16ad3e..476ea1827 100644 --- a/src/vi/hentaicube/build.gradle +++ b/src/vi/hentaicube/build.gradle @@ -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 } diff --git a/src/vi/hentaicube/src/eu/kanade/tachiyomi/extension/vi/hentaicube/HentaiCB.kt b/src/vi/hentaicube/src/eu/kanade/tachiyomi/extension/vi/hentaicube/HentaiCB.kt index 8b755e3d1..0f690ff3b 100644 --- a/src/vi/hentaicube/src/eu/kanade/tachiyomi/extension/vi/hentaicube/HentaiCB.kt +++ b/src/vi/hentaicube/src/eu/kanade/tachiyomi/extension/vi/hentaicube/HentaiCB.kt @@ -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