Comx: add ability to change domains (#9328)

* Comx: add ability to change domains

* Add auto update of current domain if default domain has changed
This commit is contained in:
Maxim Molochkov 2025-06-21 14:53:23 +04:00 committed by Draff
parent 9fb63b4f72
commit 30e8ccc669
Signed by: Draff
GPG Key ID: E8A89F3211677653
2 changed files with 98 additions and 17 deletions

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'Com-X' extName = 'Com-X'
extClass = '.ComX' extClass = '.ComX'
extVersionCode = 30 extVersionCode = 31
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -1,10 +1,14 @@
package eu.kanade.tachiyomi.extension.ru.comx package eu.kanade.tachiyomi.extension.ru.comx
import android.content.SharedPreferences
import android.webkit.CookieManager import android.webkit.CookieManager
import android.widget.Toast
import androidx.preference.EditTextPreference
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.asObservable import eu.kanade.tachiyomi.network.asObservable
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.Filter import eu.kanade.tachiyomi.source.model.Filter
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
@ -13,6 +17,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.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import keiyoushi.utils.getPreferencesLazy
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
@ -27,7 +32,6 @@ import okhttp3.FormBody
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.Jsoup import org.jsoup.Jsoup
@ -40,19 +44,24 @@ import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class ComX : ParsedHttpSource() { class ComX : ParsedHttpSource(), ConfigurableSource {
private val json: Json by injectLazy() private val json: Json by injectLazy()
override val id = 1114173092141608635
override val name = "Com-X" override val name = "Com-X"
override val baseUrl = "https://com-x.life" private val preferences: SharedPreferences by getPreferencesLazy()
override val baseUrl = preferences.getString(DOMAIN_PREF, DOMAIN_DEFAULT)!!
override val lang = "ru" override val lang = "ru"
override val supportsLatest = true override val supportsLatest = true
private val cookieManager by lazy { CookieManager.getInstance() } private val cookieManager by lazy { CookieManager.getInstance() }
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
override val client = network.cloudflareClient.newBuilder()
.connectTimeout(10, TimeUnit.SECONDS) .connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS)
.rateLimit(3) .rateLimit(3)
@ -337,16 +346,21 @@ class ComX : ParsedHttpSource() {
throw Exception("Комикс 18+ (что-то сломалось)") throw Exception("Комикс 18+ (что-то сломалось)")
} }
val baseImgUrl = "https://img.com-x.life/comix/" val imageUrl = preferences.getString(FORCE_IMG_DOMAIN_PREF, null)?.ifBlank { null }
?: IMG_DOMAIN_REGEX.find(html)?.groupValues?.get(1)?.let { "https://$it" }
if (imageUrl.isNullOrBlank()) {
throw Exception("Не удалось определить домен картинок. Попробуйте задать вручную в настройках")
}
val beginTag = "\"images\":[" val beginTag = "\"images\":["
val beginIndex = html.indexOf(beginTag) val beginIndex = html.indexOf(beginTag)
val endIndex = html.indexOf("]", beginIndex) val endIndex = html.indexOf("]", beginIndex)
val urls: List<String> = html.substring(beginIndex + beginTag.length, endIndex) val urls = html.substring(beginIndex + beginTag.length, endIndex)
.split(',').map { .split(',').map {
val img = it.replace("\\", "").replace("\"", "") val img = it.replace("\\", "").replace("\"", "")
baseImgUrl + img "$imageUrl/comix/$img"
} }
val pages = mutableListOf<Page>() val pages = mutableListOf<Page>()
@ -399,18 +413,18 @@ class ComX : ParsedHttpSource() {
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
OrderBy(), OrderBy(),
PubList(getPubList()), PubList(pubList),
GenreList(getGenreList()), GenreList(genreList),
TypeList(getTypeList()), TypeList(typeList),
AgeList(getAgeList()), AgeList(ageList),
) )
private fun getAgeList() = listOf( private val ageList = listOf(
CheckFilter("Для всех", "1"), CheckFilter("Для всех", "1"),
CheckFilter("18+", "2"), CheckFilter("18+", "2"),
) )
private fun getTypeList() = listOf( private val typeList = listOf(
CheckFilter("События в комиксах", "1"), CheckFilter("События в комиксах", "1"),
CheckFilter("Аннуалы", "3"), CheckFilter("Аннуалы", "3"),
CheckFilter("Артбук", "4"), CheckFilter("Артбук", "4"),
@ -430,7 +444,7 @@ class ComX : ParsedHttpSource() {
CheckFilter("Энциклопедия", "36"), CheckFilter("Энциклопедия", "36"),
) )
private fun getPubList() = listOf( private val pubList = listOf(
CheckFilter("Манга", "3"), CheckFilter("Манга", "3"),
CheckFilter("Маньхуа", "45"), CheckFilter("Маньхуа", "45"),
CheckFilter("Манхва", "44"), CheckFilter("Манхва", "44"),
@ -453,7 +467,7 @@ class ComX : ParsedHttpSource() {
CheckFilter("Zenescope", "51"), CheckFilter("Zenescope", "51"),
) )
private fun getGenreList() = listOf( private val genreList = listOf(
CheckFilter("Автобиографическая новелла", "9"), CheckFilter("Автобиографическая новелла", "9"),
CheckFilter("Альтернативная история", "10"), CheckFilter("Альтернативная история", "10"),
CheckFilter("Антиутопия", "11"), CheckFilter("Антиутопия", "11"),
@ -557,7 +571,74 @@ class ComX : ParsedHttpSource() {
CheckFilter("Ёнкома", "121"), CheckFilter("Ёнкома", "121"),
) )
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
EditTextPreference(screen.context).apply {
key = DOMAIN_PREF
title = "Домен"
summary = baseUrl
setDefaultValue(DOMAIN_DEFAULT)
setOnPreferenceChangeListener { _, newValue ->
try {
val res =
preferences.edit().putString(DOMAIN_PREF, newValue as String).commit()
Toast.makeText(
screen.context,
"Для смены домена необходимо перезапустить приложение с полной остановкой.",
Toast.LENGTH_LONG,
).show()
res
} catch (e: Exception) {
e.printStackTrace()
false
}
}
}.let(screen::addPreference)
EditTextPreference(screen.context).apply {
key = FORCE_IMG_DOMAIN_PREF
title = "Домен картинок"
summary = "Переопределение домена картинок"
setDefaultValue("")
setOnPreferenceChangeListener { _, newValue ->
try {
val res =
preferences.edit().putString(FORCE_IMG_DOMAIN_PREF, newValue as String).commit()
Toast.makeText(
screen.context,
"Для смены домена необходимо перезапустить приложение с полной остановкой.",
Toast.LENGTH_LONG,
).show()
res
} catch (e: Exception) {
e.printStackTrace()
false
}
}
}.let(screen::addPreference)
}
init {
preferences.getString(DEFAULT_DOMAIN_PREF, null).let { prefDefaultDomain ->
if (prefDefaultDomain != DOMAIN_DEFAULT) {
preferences.edit()
.putString(DOMAIN_PREF, DOMAIN_DEFAULT)
.putString(DEFAULT_DOMAIN_PREF, DOMAIN_DEFAULT)
.apply()
}
}
}
companion object { companion object {
private val simpleDateFormat by lazy { SimpleDateFormat("dd.MM.yyyy", Locale.US) } private val simpleDateFormat by lazy { SimpleDateFormat("dd.MM.yyyy", Locale.US) }
private const val DOMAIN_DEFAULT = "https://comxlife.com"
private const val DEFAULT_DOMAIN_PREF = "DEFAULT_DOMAIN_PREF"
private const val DOMAIN_PREF = "DOMAIN_PREF"
private const val FORCE_IMG_DOMAIN_PREF = "FORCE_IMG_DOMAIN_PREF"
private val IMG_DOMAIN_REGEX = "\"host\":\"(.+?)\"".toRegex()
} }
} }