Hiperdex: add regex to clean title (#11163)

* feat(Hiperdex): add preferences to remove title regex

* feat(Hiperdex): add preferences to remove title regex

* add original title to description

* make companion

* custom regex verification

* verify regex

* Revert "Revert "switch to checkbox""

This reverts commit 491fd17282fad18a04b3ff1570784954fde2703f.

* add real-time validation for custom regex input & update summary on change

* Fix version

* Also clean title while browsing/searching
This commit is contained in:
Cuong-Tran 2025-10-22 12:28:04 +07:00 committed by Draff
parent ad03299e49
commit 6824183cf1
Signed by: Draff
GPG Key ID: E8A89F3211677653
2 changed files with 110 additions and 1 deletions

View File

@ -3,7 +3,7 @@ ext {
extClass = '.Hiperdex'
themePkg = 'madara'
baseUrl = 'https://hiperdex.com'
overrideVersionCode = 20
overrideVersionCode = 21
isNsfw = true
}

View File

@ -1,6 +1,10 @@
package eu.kanade.tachiyomi.extension.en.hiperdex
import android.text.Editable
import android.text.TextWatcher
import android.widget.Button
import android.widget.Toast
import androidx.preference.CheckBoxPreference
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.lib.randomua.addRandomUAPreferenceToScreen
@ -10,7 +14,10 @@ import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.SManga
import keiyoushi.utils.getPreferences
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
@ -53,12 +60,109 @@ class Hiperdex :
}
}.also { screen.addPreference(it) }
CheckBoxPreference(screen.context).apply {
key = "${REMOVE_TITLE_VERSION_PREF}_$lang"
title = "Remove version information from entry titles"
summary = "This removes version tags like '(Official)' or '(Uncensored)' from entry titles " +
"and helps identify duplicate entries in your library. " +
"To update existing entries, remove them from your library (unfavorite) and refresh manually. " +
"You might also want to clear the database in advanced settings."
setDefaultValue(false)
}.also { screen.addPreference(it) }
EditTextPreference(screen.context).apply {
key = "${REMOVE_TITLE_CUSTOM_PREF}_$lang"
title = "Custom regex to be removed from title"
summary = customRemoveTitle()
setDefaultValue("")
val validate = { str: String ->
runCatching { Regex(str) }
.map { true to "" }
.getOrElse { false to it.message }
}
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.first) valid.second else null
editText.rootView.findViewById<Button>(android.R.id.button1)?.isEnabled = editText.error == null
}
},
)
}
setOnPreferenceChangeListener { _, newValue ->
val (isValid, message) = validate(newValue as String)
if (isValid) {
summary = newValue
} else {
Toast.makeText(screen.context, message, Toast.LENGTH_LONG).show()
}
isValid
}
}.also { screen.addPreference(it) }
addRandomUAPreferenceToScreen(screen)
}
override fun popularMangaFromElement(element: Element): SManga {
return super.popularMangaFromElement(element).apply {
title = title.cleanTitleIfNeeded()
}
}
override fun latestUpdatesFromElement(element: Element): SManga {
return super.latestUpdatesFromElement(element).apply {
title = title.cleanTitleIfNeeded()
}
}
override fun searchMangaFromElement(element: Element): SManga {
return super.searchMangaFromElement(element).apply {
title = title.cleanTitleIfNeeded()
}
}
override fun searchMangaSelector() = "#loop-content div.page-listing-item"
override fun mangaDetailsParse(document: Document): SManga {
return super.mangaDetailsParse(document).apply {
val cleanedTitle = title.cleanTitleIfNeeded()
if (cleanedTitle != title.trim()) {
description = listOfNotNull(title, description)
.joinToString("\n\n")
title = cleanedTitle
}
}
}
private fun String.cleanTitleIfNeeded(): String {
var tempTitle = this
customRemoveTitle().takeIf { it.isNotEmpty() }?.let { customRegex ->
runCatching {
tempTitle = tempTitle.replace(Regex(customRegex), "")
}
}
if (isRemoveTitleVersion()) {
tempTitle = tempTitle.replace(titleRegex, "")
}
return tempTitle.trim()
}
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, super.baseUrl)!!
private fun isRemoveTitleVersion(): Boolean {
return preferences.getBoolean("${REMOVE_TITLE_VERSION_PREF}_$lang", false)
}
private fun customRemoveTitle(): String =
preferences.getString("${REMOVE_TITLE_CUSTOM_PREF}_$lang", "")!!
init {
preferences.getString(DEFAULT_BASE_URL_PREF, null).let { defaultBaseUrl ->
@ -77,5 +181,10 @@ class Hiperdex :
private const val BASE_URL_PREF_SUMMARY = "The default settings will be applied when the extension is next updated"
private const val DEFAULT_BASE_URL_PREF = "defaultBaseUrl"
private const val RESTART_APP_MESSAGE = "Restart app to apply new setting."
private const val REMOVE_TITLE_VERSION_PREF = "REMOVE_TITLE_VERSION"
private const val REMOVE_TITLE_CUSTOM_PREF = "REMOVE_TITLE_CUSTOM"
private val titleRegex: Regex =
Regex("\\([^()]*\\)|\\{[^{}]*\\}|\\[(?:(?!]).)*]|«[^»]*»|〘[^〙]*〙|「[^」]*」|『[^』]*』|≪[^≫]*≫|﹛[^﹜]*﹜|〖[^〖〗]*〗|\uD81A\uDD0D.+?\uD81A\uDD0D|《[^》]*》|⌜.+?⌝|⟨[^⟩]*⟩|/Official|/ Official", RegexOption.IGNORE_CASE)
}
}