Jinman Tiantang: ID search & auto update domains (#16437)

* Jinman Tiantang: ID search & auto update domains

* Dedupe

* Non-null

* Reorder parameters
This commit is contained in:
stevenyomi 2023-05-19 18:15:45 +08:00 committed by GitHub
parent 3091cd6fdc
commit cd35641f37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 51 deletions

View File

@ -30,18 +30,6 @@
android:host="jmcomic1.me" android:host="jmcomic1.me"
android:pathPattern="/album/..*" android:pathPattern="/album/..*"
android:scheme="https" /> android:scheme="https" />
<data
android:host="jmcomic1.group"
android:pathPattern="/album/..*"
android:scheme="https" />
<data
android:host="jmcomic2.group"
android:pathPattern="/album/..*"
android:scheme="https" />
<data
android:host="jm-comic.cc"
android:pathPattern="/album/..*"
android:scheme="https" />
</intent-filter> </intent-filter>
</activity> </activity>
</application> </application>

View File

@ -5,7 +5,7 @@ ext {
extName = 'Jinman Tiantang' extName = 'Jinman Tiantang'
pkgNameSuffix = 'zh.jinmantiantang' pkgNameSuffix = 'zh.jinmantiantang'
extClass = '.Jinmantiantang' extClass = '.Jinmantiantang'
extVersionCode = 35 extVersionCode = 36
isNsfw = true isNsfw = true
} }

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.extension.zh.jinmantiantang package eu.kanade.tachiyomi.extension.zh.jinmantiantang
import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
@ -24,8 +23,6 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.select.Elements import org.jsoup.select.Elements
import rx.Observable import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
@ -36,10 +33,12 @@ class Jinmantiantang : ParsedHttpSource(), ConfigurableSource {
override val supportsLatest: Boolean = true override val supportsLatest: Boolean = true
private val preferences: SharedPreferences = private val preferences: SharedPreferences =
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) getSharedPreferences(id)
override val baseUrl: String = "https://" + preferences.baseUrl override val baseUrl: String = "https://" + preferences.baseUrl
private val updateUrlInterceptor = UpdateUrlInterceptor(preferences)
// 处理URL请求 // 处理URL请求
override val client: OkHttpClient = network.cloudflareClient override val client: OkHttpClient = network.cloudflareClient
.newBuilder() .newBuilder()
@ -49,6 +48,7 @@ class Jinmantiantang : ParsedHttpSource(), ConfigurableSource {
preferences.getString(MAINSITE_RATELIMIT_PREF, MAINSITE_RATELIMIT_PREF_DEFAULT)!!.toInt(), preferences.getString(MAINSITE_RATELIMIT_PREF, MAINSITE_RATELIMIT_PREF_DEFAULT)!!.toInt(),
preferences.getString(MAINSITE_RATELIMIT_PERIOD, MAINSITE_RATELIMIT_PERIOD_DEFAULT)!!.toLong(), preferences.getString(MAINSITE_RATELIMIT_PERIOD, MAINSITE_RATELIMIT_PERIOD_DEFAULT)!!.toLong(),
) )
.addInterceptor(updateUrlInterceptor)
.addInterceptor(ScrambledImageInterceptor).build() .addInterceptor(ScrambledImageInterceptor).build()
// 点击量排序(人气) // 点击量排序(人气)
@ -110,8 +110,8 @@ class Jinmantiantang : ParsedHttpSource(), ConfigurableSource {
} }
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
return if (query.startsWith(PREFIX_ID_SEARCH)) { return if (query.startsWith(PREFIX_ID_SEARCH_NO_COLON, true) || query.toIntOrNull() != null) {
val id = query.removePrefix(PREFIX_ID_SEARCH) val id = query.removePrefix(PREFIX_ID_SEARCH_NO_COLON).removePrefix(":")
client.newCall(searchMangaByIdRequest(id)) client.newCall(searchMangaByIdRequest(id))
.asObservableSuccess() .asObservableSuccess()
.map { response -> searchMangaByIdParse(response, id) } .map { response -> searchMangaByIdParse(response, id) }
@ -383,9 +383,10 @@ class Jinmantiantang : ParsedHttpSource(), ConfigurableSource {
} }
override fun setupPreferenceScreen(screen: PreferenceScreen) { override fun setupPreferenceScreen(screen: PreferenceScreen) {
getPreferenceList(screen.context).forEach { screen.addPreference(it) } getPreferenceList(screen.context, preferences, updateUrlInterceptor.isUpdated).forEach(screen::addPreference)
} }
companion object { companion object {
const val PREFIX_ID_SEARCH = "JM:" private const val PREFIX_ID_SEARCH_NO_COLON = "JM"
const val PREFIX_ID_SEARCH = "$PREFIX_ID_SEARCH_NO_COLON:"
} }
} }

View File

@ -1,11 +1,18 @@
package eu.kanade.tachiyomi.extension.zh.jinmantiantang package eu.kanade.tachiyomi.extension.zh.jinmantiantang
import android.app.Application
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import androidx.preference.ListPreference import androidx.preference.ListPreference
import eu.kanade.tachiyomi.network.GET
import okhttp3.Interceptor
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.IOException
internal fun getPreferenceList(context: Context) = arrayOf( internal fun getPreferenceList(context: Context, preferences: SharedPreferences, isUrlUpdated: Boolean) = arrayOf(
ListPreference(context).apply { ListPreference(context).apply {
key = MAINSITE_RATELIMIT_PREF key = MAINSITE_RATELIMIT_PREF
title = "在限制时间内(下个设置项)允许的请求数量。" title = "在限制时间内(下个设置项)允许的请求数量。"
@ -27,23 +34,20 @@ internal fun getPreferenceList(context: Context) = arrayOf(
}, },
ListPreference(context).apply { ListPreference(context).apply {
val count = SITE_ENTRIES_ARRAY.size val urlList = preferences.urlList
val fullList = SITE_ENTRIES_ARRAY + urlList
val fullDesc = SITE_ENTRIES_ARRAY_DESCRIPTION + Array(urlList.size) { "中国大陆线路${it + 1}" }
val count = fullList.size
key = USE_MIRROR_URL_PREF key = USE_MIRROR_URL_PREF
title = "使用镜像网址" title = "使用镜像网址"
entries = Array(count) { "${SITE_ENTRIES_ARRAY_DESCRIPTION[it]} (${SITE_ENTRIES_ARRAY[it]})" } entries = Array(count) { "${fullDesc[it]} (${fullList[it]})" }
entryValues = Array(count) { "$it" }.apply { this[count - 1] = "-1" } entryValues = Array(count) { "$it" }
summary = "%s\n重启后生效。" summary = if (isUrlUpdated) "%s\n镜像列表已自动更新,请选择合适的镜像并重启应用。" else "%s\n镜像列表会自动更新。重启后生效。"
setDefaultValue("0") setDefaultValue("0")
}, },
EditTextPreference(context).apply {
key = OVERRIDE_BASE_URL_PREF
title = "自定义网址"
summary = "需要在上一个设置选择“自定义”,重启后生效。" +
"不需要输入 https:// 前缀。最新网址可在 jmcomic1.bet 找到。"
},
EditTextPreference(context).apply { EditTextPreference(context).apply {
key = BLOCK_PREF key = BLOCK_PREF
title = "屏蔽词列表" title = "屏蔽词列表"
@ -58,13 +62,9 @@ internal fun getPreferenceList(context: Context) = arrayOf(
val SharedPreferences.baseUrl: String val SharedPreferences.baseUrl: String
get() { get() {
val list = SITE_ENTRIES_ARRAY val list = SITE_ENTRIES_ARRAY
val index = getString(USE_MIRROR_URL_PREF, "0")!!.toInt() val index = mirrorIndex
.coerceAtMost(list.size - 1) if (index in list.indices) return list[index]
return if (index == -1) { return urlList.getOrNull(index - list.size) ?: list[0]
getString(OVERRIDE_BASE_URL_PREF, list[0])!!
} else {
list[index]
}
} }
internal const val BLOCK_PREF = "BLOCK_GENRES_LIST" internal const val BLOCK_PREF = "BLOCK_GENRES_LIST"
@ -76,28 +76,91 @@ internal const val MAINSITE_RATELIMIT_PERIOD = "mainSiteRateLimitPeriodPreferenc
internal const val MAINSITE_RATELIMIT_PERIOD_DEFAULT = 3.toString() internal const val MAINSITE_RATELIMIT_PERIOD_DEFAULT = 3.toString()
private const val USE_MIRROR_URL_PREF = "useMirrorWebsitePreference" private const val USE_MIRROR_URL_PREF = "useMirrorWebsitePreference"
private const val OVERRIDE_BASE_URL_PREF = "overrideBaseUrl"
private val SITE_ENTRIES_ARRAY_DESCRIPTION = arrayOf( private val SITE_ENTRIES_ARRAY_DESCRIPTION get() = arrayOf(
"主站", "主站",
"海外分流", "海外分流",
"东南亚线路1", "东南亚线路1",
"东南亚线路2", "东南亚线路2",
"中国大陆线路1",
"中国大陆线路2",
"中国大陆线路3",
"自定义", // -1
) )
// List is based on https://jmcomic1.bet/ // List is based on https://jmcomic1.bet/
// Please also update AndroidManifest // Please also update AndroidManifest
private val SITE_ENTRIES_ARRAY = arrayOf( private val SITE_ENTRIES_ARRAY get() = arrayOf(
"18comic.vip", "18comic.vip",
"18comic.org", "18comic.org",
"jmcomic.me", "jmcomic.me",
"jmcomic1.me", "jmcomic1.me",
"jmcomic1.group",
"jmcomic2.group",
"jm-comic.cc",
"自定义", // -1
) )
private const val DEFAULT_LIST = "jm-comic2.cc,jm-comic.org,jmcomic2.group"
private const val DEFAULT_LIST_PREF = "defaultBaseUrlList"
private const val URL_LIST_PREF = "baseUrlList"
private val SharedPreferences.mirrorIndex get() = getString(USE_MIRROR_URL_PREF, "0")!!.toInt()
private val SharedPreferences.urlList get() = getString(URL_LIST_PREF, DEFAULT_LIST)!!.split(",")
fun getSharedPreferences(id: Long): SharedPreferences {
val preferences: SharedPreferences = Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
if (preferences.getString(DEFAULT_LIST_PREF, "")!! == DEFAULT_LIST) return preferences
preferences.edit()
.remove("overrideBaseUrl")
.putString(DEFAULT_LIST_PREF, DEFAULT_LIST)
.setUrlList(DEFAULT_LIST, preferences.mirrorIndex)
.apply()
return preferences
}
fun SharedPreferences.Editor.setUrlList(urlList: String, oldIndex: Int): SharedPreferences.Editor {
putString(URL_LIST_PREF, urlList)
val maxIndex = SITE_ENTRIES_ARRAY.size + urlList.count { it == ',' }
if (oldIndex in 0..maxIndex) return this
return putString(USE_MIRROR_URL_PREF, maxIndex.toString())
}
class UpdateUrlInterceptor(private val preferences: SharedPreferences) : Interceptor {
private val baseUrl = "https://" + preferences.baseUrl
var isUpdated = false
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
if (!request.url.toString().startsWith(baseUrl)) return chain.proceed(request)
val failedResponse = try {
val response = chain.proceed(request)
if (response.isSuccessful) return response
Result.success(response)
} catch (e: Throwable) {
if (chain.call().isCanceled()) throw e
Result.failure(e)
}
if (isUpdated || updateUrl(chain)) {
failedResponse.onSuccess(Response::close)
throw IOException("镜像网址已自动更新,请在插件设置中选择合适的镜像网址并重启应用")
}
return failedResponse.getOrThrow()
}
@Synchronized
private fun updateUrl(chain: Interceptor.Chain): Boolean {
if (isUpdated) return true
val response = try {
chain.proceed(GET("https://stevenyomi.github.io/source-domains/jmcomic.txt"))
} catch (_: Throwable) {
return false
}
if (!response.isSuccessful) {
response.close()
return false
}
val newList = response.body.string()
if (newList != preferences.getString(URL_LIST_PREF, "")!!) {
preferences.edit()
.setUrlList(newList, preferences.mirrorIndex)
.apply()
}
isUpdated = true
return true
}
}