优化
This commit is contained in:
@@ -93,7 +93,9 @@ object AppWebDav {
|
|||||||
val names = arrayListOf<String>()
|
val names = arrayListOf<String>()
|
||||||
authorization?.let {
|
authorization?.let {
|
||||||
var files = WebDav(rootWebDavUrl, it).listFiles()
|
var files = WebDav(rootWebDavUrl, it).listFiles()
|
||||||
files = files.reversed()
|
files = files.sortedWith { o1, o2 ->
|
||||||
|
AlphanumComparator.compare(o1.displayName, o2.displayName)
|
||||||
|
}.reversed()
|
||||||
files.forEach { webDav ->
|
files.forEach { webDav ->
|
||||||
val name = webDav.displayName
|
val name = webDav.displayName
|
||||||
if (name.startsWith("backup")) {
|
if (name.startsWith("backup")) {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class ContentProcessor private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun upRemoveSameTitle() {
|
private fun upRemoveSameTitle() {
|
||||||
val book = appDb.bookDao.getBookByOrigin(bookName, bookOrigin) ?: return
|
val book = appDb.bookDao.getBookByOrigin(bookName, bookOrigin) ?: return
|
||||||
removeSameTitleCache.clear()
|
removeSameTitleCache.clear()
|
||||||
val files = BookHelp.getChapterFiles(book).filter {
|
val files = BookHelp.getChapterFiles(book).filter {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import io.legado.app.model.webBook.WebBook
|
|||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeout
|
||||||
import org.jsoup.nodes.Entities
|
import org.apache.commons.text.StringEscapeUtils
|
||||||
import org.mozilla.javascript.NativeObject
|
import org.mozilla.javascript.NativeObject
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
@@ -49,6 +49,8 @@ class AnalyzeRule(
|
|||||||
private var objectChangedJS = false
|
private var objectChangedJS = false
|
||||||
private var objectChangedJP = false
|
private var objectChangedJP = false
|
||||||
|
|
||||||
|
private val stringRuleCache = hashMapOf<String, List<SourceRule>>()
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun setContent(content: Any?, baseUrl: String? = null): AnalyzeRule {
|
fun setContent(content: Any?, baseUrl: String? = null): AnalyzeRule {
|
||||||
if (content == null) throw AssertionError("内容不可空(Content cannot be null)")
|
if (content == null) throw AssertionError("内容不可空(Content cannot be null)")
|
||||||
@@ -128,7 +130,7 @@ class AnalyzeRule(
|
|||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun getStringList(rule: String?, mContent: Any? = null, isUrl: Boolean = false): List<String>? {
|
fun getStringList(rule: String?, mContent: Any? = null, isUrl: Boolean = false): List<String>? {
|
||||||
if (rule.isNullOrEmpty()) return null
|
if (rule.isNullOrEmpty()) return null
|
||||||
val ruleList = splitSourceRule(rule, false)
|
val ruleList = splitSourceRuleCacheString(rule)
|
||||||
return getStringList(ruleList, mContent, isUrl)
|
return getStringList(ruleList, mContent, isUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,13 +210,13 @@ class AnalyzeRule(
|
|||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun getString(ruleStr: String?, mContent: Any? = null, isUrl: Boolean = false): String {
|
fun getString(ruleStr: String?, mContent: Any? = null, isUrl: Boolean = false): String {
|
||||||
if (TextUtils.isEmpty(ruleStr)) return ""
|
if (TextUtils.isEmpty(ruleStr)) return ""
|
||||||
val ruleList = splitSourceRule(ruleStr)
|
val ruleList = splitSourceRuleCacheString(ruleStr)
|
||||||
return getString(ruleList, mContent, isUrl)
|
return getString(ruleList, mContent, isUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getString(ruleStr: String?, unescape: Boolean): String {
|
fun getString(ruleStr: String?, unescape: Boolean): String {
|
||||||
if (TextUtils.isEmpty(ruleStr)) return ""
|
if (TextUtils.isEmpty(ruleStr)) return ""
|
||||||
val ruleList = splitSourceRule(ruleStr)
|
val ruleList = splitSourceRuleCacheString(ruleStr)
|
||||||
return getString(ruleList, unescape = unescape)
|
return getString(ruleList, unescape = unescape)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,13 +272,7 @@ class AnalyzeRule(
|
|||||||
}
|
}
|
||||||
if (result == null) result = ""
|
if (result == null) result = ""
|
||||||
val str = if (unescape) {
|
val str = if (unescape) {
|
||||||
kotlin.runCatching {
|
StringEscapeUtils.unescapeHtml3(result.toString())
|
||||||
Entities.unescape(result.toString())
|
|
||||||
}.onFailure {
|
|
||||||
log("Entities.unescape() error\n${it.localizedMessage}")
|
|
||||||
}.getOrElse {
|
|
||||||
result.toString()
|
|
||||||
}
|
|
||||||
} else result.toString()
|
} else result.toString()
|
||||||
if (isUrl) {
|
if (isUrl) {
|
||||||
return if (str.isBlank()) {
|
return if (str.isBlank()) {
|
||||||
@@ -414,6 +410,21 @@ class AnalyzeRule(
|
|||||||
return vResult
|
return vResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getString 类规则缓存
|
||||||
|
*/
|
||||||
|
fun splitSourceRuleCacheString(ruleStr: String?) : List<SourceRule> {
|
||||||
|
if (ruleStr.isNullOrEmpty()) return emptyList()
|
||||||
|
val cacheRule = stringRuleCache[ruleStr]
|
||||||
|
return if (cacheRule != null) {
|
||||||
|
cacheRule
|
||||||
|
} else {
|
||||||
|
val rules = splitSourceRule(ruleStr)
|
||||||
|
stringRuleCache[ruleStr] = rules
|
||||||
|
rules
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分解规则生成规则列表
|
* 分解规则生成规则列表
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import io.legado.app.lib.webdav.WebDavException
|
|||||||
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.apache.commons.text.StringEscapeUtils
|
||||||
import org.jsoup.nodes.Entities
|
import org.jsoup.nodes.Entities
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import java.io.*
|
import java.io.*
|
||||||
@@ -133,11 +134,7 @@ object LocalBook {
|
|||||||
}
|
}
|
||||||
if (book.isEpub) {
|
if (book.isEpub) {
|
||||||
content = content?.replace("<img", "< img", true) ?: return null
|
content = content?.replace("<img", "< img", true) ?: return null
|
||||||
return kotlin.runCatching {
|
return StringEscapeUtils.unescapeHtml3(content)
|
||||||
Entities.unescape(content)
|
|
||||||
}.onFailure {
|
|
||||||
AppLog.put("HTML实体解码失败\n${it.localizedMessage}", it)
|
|
||||||
}.getOrDefault(content)
|
|
||||||
}
|
}
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package io.legado.app.utils
|
||||||
|
|
||||||
|
object AlphanumComparator : Comparator<String> {
|
||||||
|
|
||||||
|
override fun compare(s1: String, s2: String): Int {
|
||||||
|
var thisMarker = 0
|
||||||
|
var thatMarker = 0
|
||||||
|
val s1Length = s1.length
|
||||||
|
val s2Length = s2.length
|
||||||
|
|
||||||
|
while (thisMarker < s1Length && thatMarker < s2Length) {
|
||||||
|
val thisChunk = getChunk(s1, s1Length, thisMarker)
|
||||||
|
thisMarker += thisChunk.length
|
||||||
|
|
||||||
|
val thatChunk = getChunk(s2, s2Length, thatMarker)
|
||||||
|
thatMarker += thatChunk.length
|
||||||
|
|
||||||
|
// If both chunks contain numeric characters, sort them numerically.
|
||||||
|
var result: Int
|
||||||
|
if (isDigit(thisChunk[0]) && isDigit(thatChunk[0])) {
|
||||||
|
// Simple chunk comparison by length.
|
||||||
|
val thisChunkLength = thisChunk.length
|
||||||
|
result = thisChunkLength - thatChunk.length
|
||||||
|
// If equal, the first different number counts.
|
||||||
|
if (result == 0) {
|
||||||
|
for (i in 0 until thisChunkLength) {
|
||||||
|
result = thisChunk[i] - thatChunk[i]
|
||||||
|
if (result != 0) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = thisChunk.compareTo(thatChunk)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s1Length - s2Length
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getChunk(string: String, length: Int, marker: Int): String {
|
||||||
|
var current = marker
|
||||||
|
val chunk = StringBuilder()
|
||||||
|
var c = string[current]
|
||||||
|
chunk.append(c)
|
||||||
|
current++
|
||||||
|
if (isDigit(c)) {
|
||||||
|
while (current < length) {
|
||||||
|
c = string[current]
|
||||||
|
if (!isDigit(c)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
chunk.append(c)
|
||||||
|
current++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (current < length) {
|
||||||
|
c = string[current]
|
||||||
|
if (isDigit(c)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
chunk.append(c)
|
||||||
|
current++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chunk.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isDigit(ch: Char): Boolean {
|
||||||
|
return ch in '0'..'9'
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package io.legado.app.utils
|
|||||||
|
|
||||||
import io.legado.app.constant.AppLog
|
import io.legado.app.constant.AppLog
|
||||||
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
||||||
|
import org.apache.commons.text.StringEscapeUtils
|
||||||
import org.jsoup.nodes.Entities
|
import org.jsoup.nodes.Entities
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
@@ -31,12 +32,8 @@ object HtmlFormatter {
|
|||||||
.replace("\\s*\\n+\\s*".toRegex(), "\n ")
|
.replace("\\s*\\n+\\s*".toRegex(), "\n ")
|
||||||
.replace("^[\\n\\s]+".toRegex(), " ")
|
.replace("^[\\n\\s]+".toRegex(), " ")
|
||||||
.replace("[\\n\\s]+$".toRegex(), "")
|
.replace("[\\n\\s]+$".toRegex(), "")
|
||||||
.let { s ->
|
.let {
|
||||||
kotlin.runCatching {
|
StringEscapeUtils.unescapeHtml3(it)
|
||||||
Entities.unescape(s)
|
|
||||||
}.onFailure {
|
|
||||||
AppLog.put("Entities.unescape() error\n${it.localizedMessage}", it)
|
|
||||||
}.getOrDefault(s)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,16 @@ import java.io.InputStream
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object MD5Utils {
|
object MD5Utils {
|
||||||
|
|
||||||
|
private val MD5Digester by lazy {
|
||||||
|
DigestUtil.digester("MD5")
|
||||||
|
}
|
||||||
|
|
||||||
fun md5Encode(str: String?): String {
|
fun md5Encode(str: String?): String {
|
||||||
return DigestUtil.digester("MD5").digestHex(str)
|
return MD5Digester.digestHex(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun md5Encode(inputStream: InputStream): String {
|
fun md5Encode(inputStream: InputStream): String {
|
||||||
return DigestUtil.digester("MD5").digestHex(inputStream)
|
return MD5Digester.digestHex(inputStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun md5Encode16(str: String): String {
|
fun md5Encode16(str: String): String {
|
||||||
|
|||||||
@@ -32,9 +32,11 @@ abstract class AbstractScriptEngine(val bindings: Bindings? = null) : ScriptEngi
|
|||||||
200 -> {
|
200 -> {
|
||||||
context.setBindings(bindings, 200)
|
context.setBindings(bindings, 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
100 -> {
|
100 -> {
|
||||||
context.setBindings(bindings, 100)
|
context.setBindings(bindings, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
throw IllegalArgumentException("Invalid scope value.")
|
throw IllegalArgumentException("Invalid scope value.")
|
||||||
}
|
}
|
||||||
@@ -84,15 +86,11 @@ abstract class AbstractScriptEngine(val bindings: Bindings? = null) : ScriptEngi
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getScriptContext(bindings: Bindings): ScriptContext {
|
override fun getScriptContext(bindings: Bindings): ScriptContext {
|
||||||
val ctx = SimpleScriptContext()
|
val ctx = SimpleScriptContext(bindings, context.errorWriter, context.reader, context.writer)
|
||||||
val gs = getBindings(200)
|
val gs = getBindings(200)
|
||||||
if (gs != null) {
|
if (gs != null) {
|
||||||
ctx.setBindings(gs, 200)
|
ctx.setBindings(gs, 200)
|
||||||
}
|
}
|
||||||
ctx.setBindings(bindings, 100)
|
|
||||||
ctx.reader = context.reader
|
|
||||||
ctx.writer = context.writer
|
|
||||||
ctx.errorWriter = context.errorWriter
|
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,14 @@ import java.io.Reader
|
|||||||
import java.io.Writer
|
import java.io.Writer
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
open class SimpleScriptContext : ScriptContext {
|
open class SimpleScriptContext(
|
||||||
private var engineScope: Bindings = SimpleBindings()
|
private var engineScope: Bindings = SimpleBindings(),
|
||||||
override var errorWriter: Writer = PrintWriter(System.err, true)
|
override var errorWriter: Writer = PrintWriter(System.err, true),
|
||||||
private var globalScope: Bindings? = null
|
override var reader: Reader = InputStreamReader(System.`in`),
|
||||||
override var reader: Reader = InputStreamReader(System.`in`)
|
|
||||||
override var writer: Writer = PrintWriter(System.out, true)
|
override var writer: Writer = PrintWriter(System.out, true)
|
||||||
|
) : ScriptContext {
|
||||||
|
private var globalScope: Bindings? = null
|
||||||
|
|
||||||
override fun setBindings(bindings: Bindings?, scope: Int) {
|
override fun setBindings(bindings: Bindings?, scope: Int) {
|
||||||
when (scope) {
|
when (scope) {
|
||||||
100 -> {
|
100 -> {
|
||||||
@@ -24,6 +26,7 @@ open class SimpleScriptContext : ScriptContext {
|
|||||||
engineScope = bindings
|
engineScope = bindings
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
200 -> {
|
200 -> {
|
||||||
globalScope = bindings
|
globalScope = bindings
|
||||||
return
|
return
|
||||||
@@ -46,6 +49,7 @@ open class SimpleScriptContext : ScriptContext {
|
|||||||
100 -> {
|
100 -> {
|
||||||
return engineScope[name]
|
return engineScope[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
200 -> {
|
200 -> {
|
||||||
return globalScope?.get(name)
|
return globalScope?.get(name)
|
||||||
}
|
}
|
||||||
@@ -58,6 +62,7 @@ open class SimpleScriptContext : ScriptContext {
|
|||||||
100 -> {
|
100 -> {
|
||||||
return getBindings(100)?.remove(name)
|
return getBindings(100)?.remove(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
200 -> {
|
200 -> {
|
||||||
return getBindings(200)?.remove(name)
|
return getBindings(200)?.remove(name)
|
||||||
}
|
}
|
||||||
@@ -71,6 +76,7 @@ open class SimpleScriptContext : ScriptContext {
|
|||||||
engineScope[name] = value
|
engineScope[name] = value
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
200 -> {
|
200 -> {
|
||||||
globalScope?.put(name, value)
|
globalScope?.put(name, value)
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user