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:
parent
3091cd6fdc
commit
cd35641f37
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue