优化
This commit is contained in:
@@ -3,15 +3,19 @@ package io.legado.app.data.entities
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
|
import com.google.gson.JsonDeserializationContext
|
||||||
|
import com.google.gson.JsonDeserializer
|
||||||
|
import com.google.gson.JsonElement
|
||||||
import io.legado.app.constant.AppPattern
|
import io.legado.app.constant.AppPattern
|
||||||
import io.legado.app.constant.BookSourceType
|
import io.legado.app.constant.BookSourceType
|
||||||
import io.legado.app.data.entities.rule.*
|
import io.legado.app.data.entities.rule.*
|
||||||
import io.legado.app.help.source.SourceAnalyzer
|
|
||||||
import io.legado.app.utils.GSON
|
import io.legado.app.utils.GSON
|
||||||
|
import io.legado.app.utils.fromJsonArray
|
||||||
import io.legado.app.utils.fromJsonObject
|
import io.legado.app.utils.fromJsonObject
|
||||||
import io.legado.app.utils.splitNotBlank
|
import io.legado.app.utils.splitNotBlank
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@@ -222,17 +226,46 @@ data class BookSource(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
private val gson by lazy {
|
||||||
|
GSON.newBuilder()
|
||||||
|
.registerTypeAdapter(String::class.java, StringJsonDeserializer())
|
||||||
|
.registerTypeAdapter(ExploreRule::class.java, ExploreRule.jsonDeserializer)
|
||||||
|
.registerTypeAdapter(SearchRule::class.java, SearchRule.jsonDeserializer)
|
||||||
|
.registerTypeAdapter(BookInfoRule::class.java, BookInfoRule.jsonDeserializer)
|
||||||
|
.registerTypeAdapter(TocRule::class.java, TocRule.jsonDeserializer)
|
||||||
|
.registerTypeAdapter(ContentRule::class.java, ContentRule.jsonDeserializer)
|
||||||
|
.registerTypeAdapter(ReviewRule::class.java, ReviewRule.jsonDeserializer)
|
||||||
|
.create()
|
||||||
|
}
|
||||||
|
|
||||||
fun fromJson(json: String): Result<BookSource> {
|
fun fromJson(json: String): Result<BookSource> {
|
||||||
return SourceAnalyzer.jsonToBookSource(json)
|
return gson.fromJsonObject(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fromJsonArray(json: String): Result<MutableList<BookSource>> {
|
fun fromJsonArray(json: String): Result<List<BookSource>> {
|
||||||
return SourceAnalyzer.jsonToBookSources(json)
|
return gson.fromJsonArray(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fromJsonArray(inputStream: InputStream): Result<MutableList<BookSource>> {
|
fun fromJsonArray(inputStream: InputStream): Result<List<BookSource>> {
|
||||||
return SourceAnalyzer.jsonToBookSources(inputStream)
|
return gson.fromJsonArray(inputStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StringJsonDeserializer : JsonDeserializer<String?> {
|
||||||
|
|
||||||
|
override fun deserialize(
|
||||||
|
json: JsonElement,
|
||||||
|
typeOfT: Type,
|
||||||
|
context: JsonDeserializationContext?
|
||||||
|
): String? {
|
||||||
|
return when {
|
||||||
|
json.isJsonPrimitive -> json.asString
|
||||||
|
json.isJsonNull -> null
|
||||||
|
else -> json.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Converters {
|
class Converters {
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ data class RssSource(
|
|||||||
companion object {
|
companion object {
|
||||||
private val gson by lazy {
|
private val gson by lazy {
|
||||||
GSON.newBuilder()
|
GSON.newBuilder()
|
||||||
.registerTypeAdapter(String::class.java, RssJsonDeserializer())
|
.registerTypeAdapter(String::class.java, StringJsonDeserializer())
|
||||||
.create()
|
.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,9 +187,8 @@ data class RssSource(
|
|||||||
fun fromJsonArray(jsonArray: String): Result<List<RssSource>> {
|
fun fromJsonArray(jsonArray: String): Result<List<RssSource>> {
|
||||||
return gson.fromJsonArray(jsonArray)
|
return gson.fromJsonArray(jsonArray)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class RssJsonDeserializer : JsonDeserializer<String?> {
|
class StringJsonDeserializer : JsonDeserializer<String?> {
|
||||||
|
|
||||||
override fun deserialize(
|
override fun deserialize(
|
||||||
json: JsonElement,
|
json: JsonElement,
|
||||||
@@ -206,3 +205,5 @@ data class RssSource(
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package io.legado.app.data.entities.rule
|
package io.legado.app.data.entities.rule
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.JsonDeserializer
|
||||||
|
import io.legado.app.utils.GSON
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,4 +22,18 @@ data class BookInfoRule(
|
|||||||
var wordCount: String? = null,
|
var wordCount: String? = null,
|
||||||
var canReName: String? = null,
|
var canReName: String? = null,
|
||||||
var downloadUrls: String? = null
|
var downloadUrls: String? = null
|
||||||
) : Parcelable
|
) : Parcelable {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val jsonDeserializer = JsonDeserializer<BookInfoRule?> { json, _, _ ->
|
||||||
|
when {
|
||||||
|
json.isJsonObject -> GSON.fromJson(json, BookInfoRule::class.java)
|
||||||
|
json.isJsonPrimitive -> GSON.fromJson(json.asString, BookInfoRule::class.java)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package io.legado.app.data.entities.rule
|
package io.legado.app.data.entities.rule
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.JsonDeserializer
|
||||||
|
import io.legado.app.utils.GSON
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,4 +18,20 @@ data class ContentRule(
|
|||||||
var imageStyle: String? = null, //默认大小居中,FULL最大宽度
|
var imageStyle: String? = null, //默认大小居中,FULL最大宽度
|
||||||
var imageDecode: String? = null, //图片bytes二次解密js, 返回解密后的bytes
|
var imageDecode: String? = null, //图片bytes二次解密js, 返回解密后的bytes
|
||||||
var payAction: String? = null, //购买操作,js或者包含{{js}}的url
|
var payAction: String? = null, //购买操作,js或者包含{{js}}的url
|
||||||
) : Parcelable
|
) : Parcelable {
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val jsonDeserializer = JsonDeserializer<ContentRule?> { json, _, _ ->
|
||||||
|
when {
|
||||||
|
json.isJsonObject -> GSON.fromJson(json, ContentRule::class.java)
|
||||||
|
json.isJsonPrimitive -> GSON.fromJson(json.asString, ContentRule::class.java)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package io.legado.app.data.entities.rule
|
package io.legado.app.data.entities.rule
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.JsonDeserializer
|
||||||
|
import io.legado.app.utils.GSON
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,4 +20,18 @@ data class ExploreRule(
|
|||||||
override var bookUrl: String? = null,
|
override var bookUrl: String? = null,
|
||||||
override var coverUrl: String? = null,
|
override var coverUrl: String? = null,
|
||||||
override var wordCount: String? = null
|
override var wordCount: String? = null
|
||||||
) : BookListRule, Parcelable
|
) : BookListRule, Parcelable {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val jsonDeserializer = JsonDeserializer<ExploreRule?> { json, _, _ ->
|
||||||
|
when {
|
||||||
|
json.isJsonObject -> GSON.fromJson(json, ExploreRule::class.java)
|
||||||
|
json.isJsonPrimitive -> GSON.fromJson(json.asString, ExploreRule::class.java)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package io.legado.app.data.entities.rule
|
package io.legado.app.data.entities.rule
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.JsonDeserializer
|
||||||
|
import io.legado.app.utils.GSON
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@@ -17,4 +19,18 @@ data class ReviewRule(
|
|||||||
var postReviewUrl: String? = null, // 发送回复URL
|
var postReviewUrl: String? = null, // 发送回复URL
|
||||||
var postQuoteUrl: String? = null, // 发送回复段评URL
|
var postQuoteUrl: String? = null, // 发送回复段评URL
|
||||||
var deleteUrl: String? = null, // 删除段评URL
|
var deleteUrl: String? = null, // 删除段评URL
|
||||||
): Parcelable
|
) : Parcelable {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val jsonDeserializer = JsonDeserializer<ReviewRule?> { json, _, _ ->
|
||||||
|
when {
|
||||||
|
json.isJsonObject -> GSON.fromJson(json, ReviewRule::class.java)
|
||||||
|
json.isJsonPrimitive -> GSON.fromJson(json.asString, ReviewRule::class.java)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package io.legado.app.data.entities.rule
|
package io.legado.app.data.entities.rule
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.JsonDeserializer
|
||||||
|
import io.legado.app.utils.GSON
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,4 +22,18 @@ data class SearchRule(
|
|||||||
override var bookUrl: String? = null,
|
override var bookUrl: String? = null,
|
||||||
override var coverUrl: String? = null,
|
override var coverUrl: String? = null,
|
||||||
override var wordCount: String? = null
|
override var wordCount: String? = null
|
||||||
) : BookListRule, Parcelable
|
) : BookListRule, Parcelable {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val jsonDeserializer = JsonDeserializer<SearchRule?> { json, _, _ ->
|
||||||
|
when {
|
||||||
|
json.isJsonObject -> GSON.fromJson(json, SearchRule::class.java)
|
||||||
|
json.isJsonPrimitive -> GSON.fromJson(json.asString, SearchRule::class.java)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package io.legado.app.data.entities.rule
|
package io.legado.app.data.entities.rule
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.JsonDeserializer
|
||||||
|
import io.legado.app.utils.GSON
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@@ -14,4 +16,18 @@ data class TocRule(
|
|||||||
var isPay: String? = null,
|
var isPay: String? = null,
|
||||||
var updateTime: String? = null,
|
var updateTime: String? = null,
|
||||||
var nextTocUrl: String? = null
|
var nextTocUrl: String? = null
|
||||||
) : Parcelable
|
) : Parcelable {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val jsonDeserializer = JsonDeserializer<TocRule?> { json, _, _ ->
|
||||||
|
when {
|
||||||
|
json.isJsonObject -> GSON.fromJson(json, TocRule::class.java)
|
||||||
|
json.isJsonPrimitive -> GSON.fromJson(json.asString, TocRule::class.java)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,389 +0,0 @@
|
|||||||
package io.legado.app.help.source
|
|
||||||
|
|
||||||
import androidx.annotation.Keep
|
|
||||||
import com.jayway.jsonpath.JsonPath
|
|
||||||
import io.legado.app.R
|
|
||||||
import io.legado.app.constant.AppConst
|
|
||||||
import io.legado.app.constant.AppLog
|
|
||||||
import io.legado.app.constant.BookSourceType
|
|
||||||
import io.legado.app.data.entities.BookSource
|
|
||||||
import io.legado.app.data.entities.rule.*
|
|
||||||
import io.legado.app.exception.NoStackTraceException
|
|
||||||
import io.legado.app.utils.*
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.util.regex.Pattern
|
|
||||||
import splitties.init.appCtx
|
|
||||||
|
|
||||||
|
|
||||||
@Suppress("RegExpRedundantEscape")
|
|
||||||
object SourceAnalyzer {
|
|
||||||
private val headerPattern = Pattern.compile("@Header:\\{.+?\\}", Pattern.CASE_INSENSITIVE)
|
|
||||||
private val jsPattern = Pattern.compile("\\{\\{.+?\\}\\}", Pattern.CASE_INSENSITIVE)
|
|
||||||
|
|
||||||
fun jsonToBookSources(json: String): Result<MutableList<BookSource>> {
|
|
||||||
return kotlin.runCatching {
|
|
||||||
val bookSources = mutableListOf<BookSource>()
|
|
||||||
when {
|
|
||||||
json.isJsonArray() -> {
|
|
||||||
val items: List<Map<String, Any>> = jsonPath.parse(json).read("$")
|
|
||||||
for (item in items) {
|
|
||||||
val jsonItem = jsonPath.parse(item)
|
|
||||||
jsonToBookSource(jsonItem.jsonString()).getOrThrow().let {
|
|
||||||
bookSources.add(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
json.isJsonObject() -> {
|
|
||||||
jsonToBookSource(json).getOrThrow().let {
|
|
||||||
bookSources.add(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
throw NoStackTraceException(appCtx.getString(R.string.wrong_format))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bookSources
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun jsonToBookSources(inputStream: InputStream): Result<MutableList<BookSource>> {
|
|
||||||
return kotlin.runCatching {
|
|
||||||
val bookSources = mutableListOf<BookSource>()
|
|
||||||
val documentContext = jsonPath.parse(inputStream)
|
|
||||||
try {
|
|
||||||
val items: List<Map<String, Any>> = documentContext.read("$")
|
|
||||||
items.forEach {
|
|
||||||
val jsonItem = jsonPath.parse(it)
|
|
||||||
jsonToBookSource(jsonItem.jsonString()).getOrThrow().let {
|
|
||||||
bookSources.add(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (_: Exception) {
|
|
||||||
val item: Map<String, Any> = documentContext.read("$")
|
|
||||||
val jsonItem = jsonPath.parse(item)
|
|
||||||
jsonToBookSource(jsonItem.jsonString()).getOrThrow().let {
|
|
||||||
bookSources.add(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bookSources
|
|
||||||
}.onFailure {
|
|
||||||
throw NoStackTraceException(appCtx.getString(R.string.wrong_format))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun jsonToBookSource(json: String): Result<BookSource> {
|
|
||||||
val source = BookSource()
|
|
||||||
val sourceAny = GSON.fromJsonObject<BookSourceAny>(json.trim())
|
|
||||||
.onFailure {
|
|
||||||
AppLog.put(appCtx.getString(R.string.wrong_format), it)
|
|
||||||
}.getOrNull()
|
|
||||||
return kotlin.runCatching {
|
|
||||||
if (sourceAny?.ruleToc == null) {
|
|
||||||
source.apply {
|
|
||||||
val jsonItem = jsonPath.parse(json.trim())
|
|
||||||
bookSourceUrl = jsonItem.readString("bookSourceUrl")
|
|
||||||
?: throw NoStackTraceException(appCtx.getString(R.string.wrong_format))
|
|
||||||
bookSourceName = jsonItem.readString("bookSourceName") ?: ""
|
|
||||||
bookSourceGroup = jsonItem.readString("bookSourceGroup")
|
|
||||||
loginUrl = jsonItem.readString("loginUrl")
|
|
||||||
loginUi = jsonItem.readString("loginUi")
|
|
||||||
loginCheckJs = jsonItem.readString("loginCheckJs")
|
|
||||||
coverDecodeJs = jsonItem.readString("coverDecodeJs")
|
|
||||||
bookSourceComment = jsonItem.readString("bookSourceComment") ?: ""
|
|
||||||
bookUrlPattern = jsonItem.readString("ruleBookUrlPattern")
|
|
||||||
customOrder = jsonItem.readInt("serialNumber") ?: 0
|
|
||||||
header = uaToHeader(jsonItem.readString("httpUserAgent"))
|
|
||||||
searchUrl = toNewUrl(jsonItem.readString("ruleSearchUrl"))
|
|
||||||
exploreUrl = toNewUrls(jsonItem.readString("ruleFindUrl"))
|
|
||||||
bookSourceType =
|
|
||||||
if (jsonItem.readString("bookSourceType") == "AUDIO") BookSourceType.audio else BookSourceType.default
|
|
||||||
enabled = jsonItem.readBool("enable") ?: true
|
|
||||||
if (exploreUrl.isNullOrBlank()) {
|
|
||||||
enabledExplore = false
|
|
||||||
}
|
|
||||||
ruleSearch = SearchRule(
|
|
||||||
bookList = toNewRule(jsonItem.readString("ruleSearchList")),
|
|
||||||
name = toNewRule(jsonItem.readString("ruleSearchName")),
|
|
||||||
author = toNewRule(jsonItem.readString("ruleSearchAuthor")),
|
|
||||||
intro = toNewRule(jsonItem.readString("ruleSearchIntroduce")),
|
|
||||||
kind = toNewRule(jsonItem.readString("ruleSearchKind")),
|
|
||||||
bookUrl = toNewRule(jsonItem.readString("ruleSearchNoteUrl")),
|
|
||||||
coverUrl = toNewRule(jsonItem.readString("ruleSearchCoverUrl")),
|
|
||||||
lastChapter = toNewRule(jsonItem.readString("ruleSearchLastChapter"))
|
|
||||||
)
|
|
||||||
ruleExplore = ExploreRule(
|
|
||||||
bookList = toNewRule(jsonItem.readString("ruleFindList")),
|
|
||||||
name = toNewRule(jsonItem.readString("ruleFindName")),
|
|
||||||
author = toNewRule(jsonItem.readString("ruleFindAuthor")),
|
|
||||||
intro = toNewRule(jsonItem.readString("ruleFindIntroduce")),
|
|
||||||
kind = toNewRule(jsonItem.readString("ruleFindKind")),
|
|
||||||
bookUrl = toNewRule(jsonItem.readString("ruleFindNoteUrl")),
|
|
||||||
coverUrl = toNewRule(jsonItem.readString("ruleFindCoverUrl")),
|
|
||||||
lastChapter = toNewRule(jsonItem.readString("ruleFindLastChapter"))
|
|
||||||
)
|
|
||||||
ruleBookInfo = BookInfoRule(
|
|
||||||
init = toNewRule(jsonItem.readString("ruleBookInfoInit")),
|
|
||||||
name = toNewRule(jsonItem.readString("ruleBookName")),
|
|
||||||
author = toNewRule(jsonItem.readString("ruleBookAuthor")),
|
|
||||||
intro = toNewRule(jsonItem.readString("ruleIntroduce")),
|
|
||||||
kind = toNewRule(jsonItem.readString("ruleBookKind")),
|
|
||||||
coverUrl = toNewRule(jsonItem.readString("ruleCoverUrl")),
|
|
||||||
lastChapter = toNewRule(jsonItem.readString("ruleBookLastChapter")),
|
|
||||||
tocUrl = toNewRule(jsonItem.readString("ruleChapterUrl"))
|
|
||||||
)
|
|
||||||
ruleToc = TocRule(
|
|
||||||
chapterList = toNewRule(jsonItem.readString("ruleChapterList")),
|
|
||||||
chapterName = toNewRule(jsonItem.readString("ruleChapterName")),
|
|
||||||
chapterUrl = toNewRule(jsonItem.readString("ruleContentUrl")),
|
|
||||||
nextTocUrl = toNewRule(jsonItem.readString("ruleChapterUrlNext"))
|
|
||||||
)
|
|
||||||
var content = toNewRule(jsonItem.readString("ruleBookContent")) ?: ""
|
|
||||||
if (content.startsWith("$") && !content.startsWith("$.")) {
|
|
||||||
content = content.substring(1)
|
|
||||||
}
|
|
||||||
ruleContent = ContentRule(
|
|
||||||
content = content,
|
|
||||||
replaceRegex = toNewRule(jsonItem.readString("ruleBookContentReplace")),
|
|
||||||
nextContentUrl = toNewRule(jsonItem.readString("ruleContentUrlNext"))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
source.bookSourceUrl = sourceAny.bookSourceUrl
|
|
||||||
source.bookSourceName = sourceAny.bookSourceName
|
|
||||||
source.bookSourceGroup = sourceAny.bookSourceGroup
|
|
||||||
source.bookSourceType = sourceAny.bookSourceType
|
|
||||||
source.bookUrlPattern = sourceAny.bookUrlPattern
|
|
||||||
source.customOrder = sourceAny.customOrder
|
|
||||||
source.enabled = sourceAny.enabled
|
|
||||||
source.enabledExplore = sourceAny.enabledExplore
|
|
||||||
source.enabledCookieJar = sourceAny.enabledCookieJar
|
|
||||||
source.enabledReview = sourceAny.enabledReview
|
|
||||||
source.concurrentRate = sourceAny.concurrentRate
|
|
||||||
source.header = sourceAny.header
|
|
||||||
source.loginUrl = when (sourceAny.loginUrl) {
|
|
||||||
null -> null
|
|
||||||
is String -> sourceAny.loginUrl.toString()
|
|
||||||
else -> JsonPath.parse(sourceAny.loginUrl).readString("url")
|
|
||||||
}
|
|
||||||
source.loginUi = if (sourceAny.loginUi is List<*>) {
|
|
||||||
GSON.toJson(sourceAny.loginUi)
|
|
||||||
} else {
|
|
||||||
sourceAny.loginUi?.toString()
|
|
||||||
}
|
|
||||||
source.loginCheckJs = sourceAny.loginCheckJs
|
|
||||||
source.coverDecodeJs = sourceAny.coverDecodeJs
|
|
||||||
source.bookSourceComment = sourceAny.bookSourceComment
|
|
||||||
source.variableComment = sourceAny.variableComment
|
|
||||||
source.lastUpdateTime = sourceAny.lastUpdateTime
|
|
||||||
source.respondTime = sourceAny.respondTime
|
|
||||||
source.weight = sourceAny.weight
|
|
||||||
source.exploreUrl = sourceAny.exploreUrl
|
|
||||||
source.ruleExplore = if (sourceAny.ruleExplore is String) {
|
|
||||||
GSON.fromJsonObject<ExploreRule>(sourceAny.ruleExplore.toString())
|
|
||||||
.getOrNull()
|
|
||||||
} else {
|
|
||||||
GSON.fromJsonObject<ExploreRule>(GSON.toJson(sourceAny.ruleExplore))
|
|
||||||
.getOrNull()
|
|
||||||
}
|
|
||||||
source.searchUrl = sourceAny.searchUrl
|
|
||||||
source.ruleSearch = if (sourceAny.ruleSearch is String) {
|
|
||||||
GSON.fromJsonObject<SearchRule>(sourceAny.ruleSearch.toString())
|
|
||||||
.getOrNull()
|
|
||||||
} else {
|
|
||||||
GSON.fromJsonObject<SearchRule>(GSON.toJson(sourceAny.ruleSearch))
|
|
||||||
.getOrNull()
|
|
||||||
}
|
|
||||||
source.ruleBookInfo = if (sourceAny.ruleBookInfo is String) {
|
|
||||||
GSON.fromJsonObject<BookInfoRule>(sourceAny.ruleBookInfo.toString())
|
|
||||||
.getOrNull()
|
|
||||||
} else {
|
|
||||||
GSON.fromJsonObject<BookInfoRule>(GSON.toJson(sourceAny.ruleBookInfo))
|
|
||||||
.getOrNull()
|
|
||||||
}
|
|
||||||
source.ruleToc = if (sourceAny.ruleToc is String) {
|
|
||||||
GSON.fromJsonObject<TocRule>(sourceAny.ruleToc.toString())
|
|
||||||
.getOrNull()
|
|
||||||
} else {
|
|
||||||
GSON.fromJsonObject<TocRule>(GSON.toJson(sourceAny.ruleToc))
|
|
||||||
.getOrNull()
|
|
||||||
}
|
|
||||||
source.ruleContent = if (sourceAny.ruleContent is String) {
|
|
||||||
GSON.fromJsonObject<ContentRule>(sourceAny.ruleContent.toString())
|
|
||||||
.getOrNull()
|
|
||||||
} else {
|
|
||||||
GSON.fromJsonObject<ContentRule>(GSON.toJson(sourceAny.ruleContent))
|
|
||||||
.getOrNull()
|
|
||||||
}
|
|
||||||
source.ruleReview = if (sourceAny.ruleReview is String) {
|
|
||||||
GSON.fromJsonObject<ReviewRule>(sourceAny.ruleReview.toString())
|
|
||||||
.getOrNull()
|
|
||||||
} else {
|
|
||||||
GSON.fromJsonObject<ReviewRule>(GSON.toJson(sourceAny.ruleReview))
|
|
||||||
.getOrNull()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
source
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Keep
|
|
||||||
data class BookSourceAny(
|
|
||||||
var bookSourceName: String = "", // 名称
|
|
||||||
var bookSourceGroup: String? = null, // 分组
|
|
||||||
var bookSourceUrl: String = "", // 地址,包括 http/https
|
|
||||||
var bookSourceType: Int = BookSourceType.default, // 类型,0 文本,1 音频
|
|
||||||
var bookUrlPattern: String? = null, // 详情页url正则
|
|
||||||
var customOrder: Int = 0, // 手动排序编号
|
|
||||||
var enabled: Boolean = true, // 是否启用
|
|
||||||
var enabledExplore: Boolean = true, // 启用发现
|
|
||||||
var enabledReview: Boolean = false, // 启用段评
|
|
||||||
var enabledCookieJar: Boolean = false, // 启用CookieJar
|
|
||||||
var concurrentRate: String? = null, // 并发率
|
|
||||||
var header: String? = null, // 请求头
|
|
||||||
var loginUrl: Any? = null, // 登录规则
|
|
||||||
var loginUi: Any? = null, // 登录UI
|
|
||||||
var loginCheckJs: String? = null, // 登录检测js
|
|
||||||
var coverDecodeJs: String? = null, // 封面解密js
|
|
||||||
var bookSourceComment: String? = "", // 书源注释
|
|
||||||
var variableComment: String? = null, // 变量说明
|
|
||||||
var lastUpdateTime: Long = 0, // 最后更新时间,用于排序
|
|
||||||
var respondTime: Long = 180000L, // 响应时间,用于排序
|
|
||||||
var weight: Int = 0, // 智能排序的权重
|
|
||||||
var exploreUrl: String? = null, // 发现url
|
|
||||||
var ruleExplore: Any? = null, // 发现规则
|
|
||||||
var searchUrl: String? = null, // 搜索url
|
|
||||||
var ruleSearch: Any? = null, // 搜索规则
|
|
||||||
var ruleBookInfo: Any? = null, // 书籍信息页规则
|
|
||||||
var ruleToc: Any? = null, // 目录页规则
|
|
||||||
var ruleContent: Any? = null, // 正文页规则
|
|
||||||
var ruleReview: Any? = null // 段评规则
|
|
||||||
)
|
|
||||||
|
|
||||||
// default规则适配
|
|
||||||
// #正则#替换内容 替换成 ##正则##替换内容
|
|
||||||
// | 替换成 ||
|
|
||||||
// & 替换成 &&
|
|
||||||
private fun toNewRule(oldRule: String?): String? {
|
|
||||||
if (oldRule.isNullOrBlank()) return null
|
|
||||||
var newRule = oldRule
|
|
||||||
var reverse = false
|
|
||||||
var allinone = false
|
|
||||||
if (oldRule.startsWith("-")) {
|
|
||||||
reverse = true
|
|
||||||
newRule = oldRule.substring(1)
|
|
||||||
}
|
|
||||||
if (newRule.startsWith("+")) {
|
|
||||||
allinone = true
|
|
||||||
newRule = newRule.substring(1)
|
|
||||||
}
|
|
||||||
if (!newRule.startsWith("@CSS:", true) &&
|
|
||||||
!newRule.startsWith("@XPath:", true) &&
|
|
||||||
!newRule.startsWith("//") &&
|
|
||||||
!newRule.startsWith("##") &&
|
|
||||||
!newRule.startsWith(":") &&
|
|
||||||
!newRule.contains("@js:", true) &&
|
|
||||||
!newRule.contains("<js>", true)
|
|
||||||
) {
|
|
||||||
if (newRule.contains("#") && !newRule.contains("##")) {
|
|
||||||
newRule = oldRule.replace("#", "##")
|
|
||||||
}
|
|
||||||
if (newRule.contains("|") && !newRule.contains("||")) {
|
|
||||||
if (newRule.contains("##")) {
|
|
||||||
val list = newRule.split("##")
|
|
||||||
if (list[0].contains("|")) {
|
|
||||||
newRule = list[0].replace("|", "||")
|
|
||||||
for (i in 1 until list.size) {
|
|
||||||
newRule += "##" + list[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newRule = newRule.replace("|", "||")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (newRule.contains("&")
|
|
||||||
&& !newRule.contains("&&")
|
|
||||||
&& !newRule.contains("http")
|
|
||||||
&& !newRule.startsWith("/")
|
|
||||||
) {
|
|
||||||
newRule = newRule.replace("&", "&&")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (allinone) {
|
|
||||||
newRule = "+$newRule"
|
|
||||||
}
|
|
||||||
if (reverse) {
|
|
||||||
newRule = "-$newRule"
|
|
||||||
}
|
|
||||||
return newRule
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toNewUrls(oldUrls: String?): String? {
|
|
||||||
if (oldUrls.isNullOrBlank()) return null
|
|
||||||
if (oldUrls.startsWith("@js:") || oldUrls.startsWith("<js>")) {
|
|
||||||
return oldUrls
|
|
||||||
}
|
|
||||||
if (!oldUrls.contains("\n") && !oldUrls.contains("&&")) {
|
|
||||||
return toNewUrl(oldUrls)
|
|
||||||
}
|
|
||||||
val urls = oldUrls.split("(&&|\r?\n)+".toRegex())
|
|
||||||
return urls.map {
|
|
||||||
toNewUrl(it)?.replace("\n\\s*".toRegex(), "")
|
|
||||||
}.joinToString("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toNewUrl(oldUrl: String?): String? {
|
|
||||||
if (oldUrl.isNullOrBlank()) return null
|
|
||||||
var url: String = oldUrl
|
|
||||||
if (oldUrl.startsWith("<js>", true)) {
|
|
||||||
url = url.replace("=searchKey", "={{key}}")
|
|
||||||
.replace("=searchPage", "={{page}}")
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
val map = HashMap<String, String>()
|
|
||||||
var mather = headerPattern.matcher(url)
|
|
||||||
if (mather.find()) {
|
|
||||||
val header = mather.group()
|
|
||||||
url = url.replace(header, "")
|
|
||||||
map["headers"] = header.substring(8)
|
|
||||||
}
|
|
||||||
var urlList = url.split("|")
|
|
||||||
url = urlList[0]
|
|
||||||
if (urlList.size > 1) {
|
|
||||||
map["charset"] = urlList[1].split("=")[1]
|
|
||||||
}
|
|
||||||
mather = jsPattern.matcher(url)
|
|
||||||
val jsList = arrayListOf<String>()
|
|
||||||
while (mather.find()) {
|
|
||||||
jsList.add(mather.group())
|
|
||||||
url = url.replace(jsList.last(), "$${jsList.size - 1}")
|
|
||||||
}
|
|
||||||
url = url.replace("{", "<").replace("}", ">")
|
|
||||||
url = url.replace("searchKey", "{{key}}")
|
|
||||||
url = url.replace("<searchPage([-+]1)>".toRegex(), "{{page$1}}")
|
|
||||||
.replace("searchPage([-+]1)".toRegex(), "{{page$1}}")
|
|
||||||
.replace("searchPage", "{{page}}")
|
|
||||||
for ((index, item) in jsList.withIndex()) {
|
|
||||||
url = url.replace(
|
|
||||||
"$$index",
|
|
||||||
item.replace("searchKey", "key").replace("searchPage", "page")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
urlList = url.split("@")
|
|
||||||
url = urlList[0]
|
|
||||||
if (urlList.size > 1) {
|
|
||||||
map["method"] = "POST"
|
|
||||||
map["body"] = urlList[1]
|
|
||||||
}
|
|
||||||
if (map.size > 0) {
|
|
||||||
url += "," + GSON.toJson(map)
|
|
||||||
}
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun uaToHeader(ua: String?): String? {
|
|
||||||
if (ua.isNullOrEmpty()) return null
|
|
||||||
val map = mapOf(Pair(AppConst.UA_NAME, ua))
|
|
||||||
return GSON.toJson(map)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -3,16 +3,26 @@ package io.legado.app.help.storage
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
|
import io.legado.app.R
|
||||||
|
import io.legado.app.constant.AppConst
|
||||||
|
import io.legado.app.constant.BookSourceType
|
||||||
import io.legado.app.constant.BookType
|
import io.legado.app.constant.BookType
|
||||||
import io.legado.app.data.appDb
|
import io.legado.app.data.appDb
|
||||||
import io.legado.app.data.entities.Book
|
import io.legado.app.data.entities.Book
|
||||||
import io.legado.app.data.entities.BookSource
|
import io.legado.app.data.entities.BookSource
|
||||||
|
import io.legado.app.data.entities.rule.*
|
||||||
|
import io.legado.app.exception.NoStackTraceException
|
||||||
import io.legado.app.help.ReplaceAnalyzer
|
import io.legado.app.help.ReplaceAnalyzer
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
|
import splitties.init.appCtx
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
object ImportOldData {
|
object ImportOldData {
|
||||||
|
|
||||||
|
private val headerPattern = Pattern.compile("@Header:\\{.+?\\}", Pattern.CASE_INSENSITIVE)
|
||||||
|
private val jsPattern = Pattern.compile("\\{\\{.+?\\}\\}", Pattern.CASE_INSENSITIVE)
|
||||||
|
|
||||||
fun importUri(context: Context, uri: Uri) {
|
fun importUri(context: Context, uri: Uri) {
|
||||||
if (uri.isContentScheme()) {
|
if (uri.isContentScheme()) {
|
||||||
DocumentFile.fromTreeUri(context, uri)?.listFiles()?.forEach { doc ->
|
DocumentFile.fromTreeUri(context, uri)?.listFiles()?.forEach { doc ->
|
||||||
@@ -92,10 +102,9 @@ object ImportOldData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun importOldSource(json: String): Int {
|
fun importOldSource(json: String): Int {
|
||||||
val count = BookSource.fromJsonArray(json).onSuccess {
|
val sources = fromOldBookSources(json)
|
||||||
appDb.bookSourceDao.insert(*it.toTypedArray())
|
appDb.bookSourceDao.insert(*sources.toTypedArray())
|
||||||
}.getOrNull()?.size
|
return sources.size
|
||||||
return count ?: 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun importOldReplaceRule(json: String): Int {
|
private fun importOldReplaceRule(json: String): Int {
|
||||||
@@ -147,4 +156,211 @@ object ImportOldData {
|
|||||||
}
|
}
|
||||||
return books
|
return books
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun fromOldBookSources(json: String): MutableList<BookSource> {
|
||||||
|
val sources = mutableListOf<BookSource>()
|
||||||
|
val items: List<Map<String, Any>> = jsonPath.parse(json).read("$")
|
||||||
|
for (item in items) {
|
||||||
|
val jsonItem = jsonPath.parse(item)
|
||||||
|
val source = BookSource()
|
||||||
|
source.apply {
|
||||||
|
bookSourceUrl = jsonItem.readString("bookSourceUrl")
|
||||||
|
?: throw NoStackTraceException(appCtx.getString(R.string.wrong_format))
|
||||||
|
bookSourceName = jsonItem.readString("bookSourceName") ?: ""
|
||||||
|
bookSourceGroup = jsonItem.readString("bookSourceGroup")
|
||||||
|
loginUrl = jsonItem.readString("loginUrl")
|
||||||
|
loginUi = jsonItem.readString("loginUi")
|
||||||
|
loginCheckJs = jsonItem.readString("loginCheckJs")
|
||||||
|
coverDecodeJs = jsonItem.readString("coverDecodeJs")
|
||||||
|
bookSourceComment = jsonItem.readString("bookSourceComment") ?: ""
|
||||||
|
bookUrlPattern = jsonItem.readString("ruleBookUrlPattern")
|
||||||
|
customOrder = jsonItem.readInt("serialNumber") ?: 0
|
||||||
|
header = uaToHeader(jsonItem.readString("httpUserAgent"))
|
||||||
|
searchUrl = toNewUrl(jsonItem.readString("ruleSearchUrl"))
|
||||||
|
exploreUrl = toNewUrls(jsonItem.readString("ruleFindUrl"))
|
||||||
|
bookSourceType =
|
||||||
|
if (jsonItem.readString("bookSourceType") == "AUDIO") BookSourceType.audio else BookSourceType.default
|
||||||
|
enabled = jsonItem.readBool("enable") ?: true
|
||||||
|
if (exploreUrl.isNullOrBlank()) {
|
||||||
|
enabledExplore = false
|
||||||
|
}
|
||||||
|
ruleSearch = SearchRule(
|
||||||
|
bookList = toNewRule(jsonItem.readString("ruleSearchList")),
|
||||||
|
name = toNewRule(jsonItem.readString("ruleSearchName")),
|
||||||
|
author = toNewRule(jsonItem.readString("ruleSearchAuthor")),
|
||||||
|
intro = toNewRule(jsonItem.readString("ruleSearchIntroduce")),
|
||||||
|
kind = toNewRule(jsonItem.readString("ruleSearchKind")),
|
||||||
|
bookUrl = toNewRule(jsonItem.readString("ruleSearchNoteUrl")),
|
||||||
|
coverUrl = toNewRule(jsonItem.readString("ruleSearchCoverUrl")),
|
||||||
|
lastChapter = toNewRule(jsonItem.readString("ruleSearchLastChapter"))
|
||||||
|
)
|
||||||
|
ruleExplore = ExploreRule(
|
||||||
|
bookList = toNewRule(jsonItem.readString("ruleFindList")),
|
||||||
|
name = toNewRule(jsonItem.readString("ruleFindName")),
|
||||||
|
author = toNewRule(jsonItem.readString("ruleFindAuthor")),
|
||||||
|
intro = toNewRule(jsonItem.readString("ruleFindIntroduce")),
|
||||||
|
kind = toNewRule(jsonItem.readString("ruleFindKind")),
|
||||||
|
bookUrl = toNewRule(jsonItem.readString("ruleFindNoteUrl")),
|
||||||
|
coverUrl = toNewRule(jsonItem.readString("ruleFindCoverUrl")),
|
||||||
|
lastChapter = toNewRule(jsonItem.readString("ruleFindLastChapter"))
|
||||||
|
)
|
||||||
|
ruleBookInfo = BookInfoRule(
|
||||||
|
init = toNewRule(jsonItem.readString("ruleBookInfoInit")),
|
||||||
|
name = toNewRule(jsonItem.readString("ruleBookName")),
|
||||||
|
author = toNewRule(jsonItem.readString("ruleBookAuthor")),
|
||||||
|
intro = toNewRule(jsonItem.readString("ruleIntroduce")),
|
||||||
|
kind = toNewRule(jsonItem.readString("ruleBookKind")),
|
||||||
|
coverUrl = toNewRule(jsonItem.readString("ruleCoverUrl")),
|
||||||
|
lastChapter = toNewRule(jsonItem.readString("ruleBookLastChapter")),
|
||||||
|
tocUrl = toNewRule(jsonItem.readString("ruleChapterUrl"))
|
||||||
|
)
|
||||||
|
ruleToc = TocRule(
|
||||||
|
chapterList = toNewRule(jsonItem.readString("ruleChapterList")),
|
||||||
|
chapterName = toNewRule(jsonItem.readString("ruleChapterName")),
|
||||||
|
chapterUrl = toNewRule(jsonItem.readString("ruleContentUrl")),
|
||||||
|
nextTocUrl = toNewRule(jsonItem.readString("ruleChapterUrlNext"))
|
||||||
|
)
|
||||||
|
var content = toNewRule(jsonItem.readString("ruleBookContent")) ?: ""
|
||||||
|
if (content.startsWith("$") && !content.startsWith("$.")) {
|
||||||
|
content = content.substring(1)
|
||||||
|
}
|
||||||
|
ruleContent = ContentRule(
|
||||||
|
content = content,
|
||||||
|
replaceRegex = toNewRule(jsonItem.readString("ruleBookContentReplace")),
|
||||||
|
nextContentUrl = toNewRule(jsonItem.readString("ruleContentUrlNext"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
sources.add(source)
|
||||||
|
}
|
||||||
|
return sources
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// default规则适配
|
||||||
|
// #正则#替换内容 替换成 ##正则##替换内容
|
||||||
|
// | 替换成 ||
|
||||||
|
// & 替换成 &&
|
||||||
|
private fun toNewRule(oldRule: String?): String? {
|
||||||
|
if (oldRule.isNullOrBlank()) return null
|
||||||
|
var newRule = oldRule
|
||||||
|
var reverse = false
|
||||||
|
var allinone = false
|
||||||
|
if (oldRule.startsWith("-")) {
|
||||||
|
reverse = true
|
||||||
|
newRule = oldRule.substring(1)
|
||||||
|
}
|
||||||
|
if (newRule.startsWith("+")) {
|
||||||
|
allinone = true
|
||||||
|
newRule = newRule.substring(1)
|
||||||
|
}
|
||||||
|
if (!newRule.startsWith("@CSS:", true) &&
|
||||||
|
!newRule.startsWith("@XPath:", true) &&
|
||||||
|
!newRule.startsWith("//") &&
|
||||||
|
!newRule.startsWith("##") &&
|
||||||
|
!newRule.startsWith(":") &&
|
||||||
|
!newRule.contains("@js:", true) &&
|
||||||
|
!newRule.contains("<js>", true)
|
||||||
|
) {
|
||||||
|
if (newRule.contains("#") && !newRule.contains("##")) {
|
||||||
|
newRule = oldRule.replace("#", "##")
|
||||||
|
}
|
||||||
|
if (newRule.contains("|") && !newRule.contains("||")) {
|
||||||
|
if (newRule.contains("##")) {
|
||||||
|
val list = newRule.split("##")
|
||||||
|
if (list[0].contains("|")) {
|
||||||
|
newRule = list[0].replace("|", "||")
|
||||||
|
for (i in 1 until list.size) {
|
||||||
|
newRule += "##" + list[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newRule = newRule.replace("|", "||")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newRule.contains("&")
|
||||||
|
&& !newRule.contains("&&")
|
||||||
|
&& !newRule.contains("http")
|
||||||
|
&& !newRule.startsWith("/")
|
||||||
|
) {
|
||||||
|
newRule = newRule.replace("&", "&&")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allinone) {
|
||||||
|
newRule = "+$newRule"
|
||||||
|
}
|
||||||
|
if (reverse) {
|
||||||
|
newRule = "-$newRule"
|
||||||
|
}
|
||||||
|
return newRule
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toNewUrls(oldUrls: String?): String? {
|
||||||
|
if (oldUrls.isNullOrBlank()) return null
|
||||||
|
if (oldUrls.startsWith("@js:") || oldUrls.startsWith("<js>")) {
|
||||||
|
return oldUrls
|
||||||
|
}
|
||||||
|
if (!oldUrls.contains("\n") && !oldUrls.contains("&&")) {
|
||||||
|
return toNewUrl(oldUrls)
|
||||||
|
}
|
||||||
|
val urls = oldUrls.split("(&&|\r?\n)+".toRegex())
|
||||||
|
return urls.map {
|
||||||
|
toNewUrl(it)?.replace("\n\\s*".toRegex(), "")
|
||||||
|
}.joinToString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toNewUrl(oldUrl: String?): String? {
|
||||||
|
if (oldUrl.isNullOrBlank()) return null
|
||||||
|
var url: String = oldUrl
|
||||||
|
if (oldUrl.startsWith("<js>", true)) {
|
||||||
|
url = url.replace("=searchKey", "={{key}}")
|
||||||
|
.replace("=searchPage", "={{page}}")
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
val map = HashMap<String, String>()
|
||||||
|
var mather = headerPattern.matcher(url)
|
||||||
|
if (mather.find()) {
|
||||||
|
val header = mather.group()
|
||||||
|
url = url.replace(header, "")
|
||||||
|
map["headers"] = header.substring(8)
|
||||||
|
}
|
||||||
|
var urlList = url.split("|")
|
||||||
|
url = urlList[0]
|
||||||
|
if (urlList.size > 1) {
|
||||||
|
map["charset"] = urlList[1].split("=")[1]
|
||||||
|
}
|
||||||
|
mather = jsPattern.matcher(url)
|
||||||
|
val jsList = arrayListOf<String>()
|
||||||
|
while (mather.find()) {
|
||||||
|
jsList.add(mather.group())
|
||||||
|
url = url.replace(jsList.last(), "$${jsList.size - 1}")
|
||||||
|
}
|
||||||
|
url = url.replace("{", "<").replace("}", ">")
|
||||||
|
url = url.replace("searchKey", "{{key}}")
|
||||||
|
url = url.replace("<searchPage([-+]1)>".toRegex(), "{{page$1}}")
|
||||||
|
.replace("searchPage([-+]1)".toRegex(), "{{page$1}}")
|
||||||
|
.replace("searchPage", "{{page}}")
|
||||||
|
for ((index, item) in jsList.withIndex()) {
|
||||||
|
url = url.replace(
|
||||||
|
"$$index",
|
||||||
|
item.replace("searchKey", "key").replace("searchPage", "page")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
urlList = url.split("@")
|
||||||
|
url = urlList[0]
|
||||||
|
if (urlList.size > 1) {
|
||||||
|
map["method"] = "POST"
|
||||||
|
map["body"] = urlList[1]
|
||||||
|
}
|
||||||
|
if (map.size > 0) {
|
||||||
|
url += "," + GSON.toJson(map)
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun uaToHeader(ua: String?): String? {
|
||||||
|
if (ua.isNullOrEmpty()) return null
|
||||||
|
val map = mapOf(Pair(AppConst.UA_NAME, ua))
|
||||||
|
return GSON.toJson(map)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user