This commit is contained in:
Horis 2023-06-10 15:23:25 +08:00
parent 45c88716f3
commit d6ff9d06ad
9 changed files with 128 additions and 37 deletions

View File

@ -93,7 +93,9 @@ object AppWebDav {
val names = arrayListOf<String>()
authorization?.let {
var files = WebDav(rootWebDavUrl, it).listFiles()
files = files.reversed()
files = files.sortedWith { o1, o2 ->
AlphanumComparator.compare(o1.displayName, o2.displayName)
}.reversed()
files.forEach { webDav ->
val name = webDav.displayName
if (name.startsWith("backup")) {

View File

@ -68,7 +68,7 @@ class ContentProcessor private constructor(
}
}
fun upRemoveSameTitle() {
private fun upRemoveSameTitle() {
val book = appDb.bookDao.getBookByOrigin(bookName, bookOrigin) ?: return
removeSameTitleCache.clear()
val files = BookHelp.getChapterFiles(book).filter {

View File

@ -13,7 +13,7 @@ import io.legado.app.model.webBook.WebBook
import io.legado.app.utils.*
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
import org.jsoup.nodes.Entities
import org.apache.commons.text.StringEscapeUtils
import org.mozilla.javascript.NativeObject
import java.net.URL
import java.util.regex.Pattern
@ -49,6 +49,8 @@ class AnalyzeRule(
private var objectChangedJS = false
private var objectChangedJP = false
private val stringRuleCache = hashMapOf<String, List<SourceRule>>()
@JvmOverloads
fun setContent(content: Any?, baseUrl: String? = null): AnalyzeRule {
if (content == null) throw AssertionError("内容不可空Content cannot be null")
@ -128,7 +130,7 @@ class AnalyzeRule(
@JvmOverloads
fun getStringList(rule: String?, mContent: Any? = null, isUrl: Boolean = false): List<String>? {
if (rule.isNullOrEmpty()) return null
val ruleList = splitSourceRule(rule, false)
val ruleList = splitSourceRuleCacheString(rule)
return getStringList(ruleList, mContent, isUrl)
}
@ -208,13 +210,13 @@ class AnalyzeRule(
@JvmOverloads
fun getString(ruleStr: String?, mContent: Any? = null, isUrl: Boolean = false): String {
if (TextUtils.isEmpty(ruleStr)) return ""
val ruleList = splitSourceRule(ruleStr)
val ruleList = splitSourceRuleCacheString(ruleStr)
return getString(ruleList, mContent, isUrl)
}
fun getString(ruleStr: String?, unescape: Boolean): String {
if (TextUtils.isEmpty(ruleStr)) return ""
val ruleList = splitSourceRule(ruleStr)
val ruleList = splitSourceRuleCacheString(ruleStr)
return getString(ruleList, unescape = unescape)
}
@ -270,13 +272,7 @@ class AnalyzeRule(
}
if (result == null) result = ""
val str = if (unescape) {
kotlin.runCatching {
Entities.unescape(result.toString())
}.onFailure {
log("Entities.unescape() error\n${it.localizedMessage}")
}.getOrElse {
result.toString()
}
StringEscapeUtils.unescapeHtml3(result.toString())
} else result.toString()
if (isUrl) {
return if (str.isBlank()) {
@ -414,6 +410,21 @@ class AnalyzeRule(
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
}
}
/**
* 分解规则生成规则列表
*/

View File

@ -23,6 +23,7 @@ import io.legado.app.lib.webdav.WebDavException
import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.utils.*
import kotlinx.coroutines.runBlocking
import org.apache.commons.text.StringEscapeUtils
import org.jsoup.nodes.Entities
import splitties.init.appCtx
import java.io.*
@ -133,11 +134,7 @@ object LocalBook {
}
if (book.isEpub) {
content = content?.replace("&lt;img", "&lt; img", true) ?: return null
return kotlin.runCatching {
Entities.unescape(content)
}.onFailure {
AppLog.put("HTML实体解码失败\n${it.localizedMessage}", it)
}.getOrDefault(content)
return StringEscapeUtils.unescapeHtml3(content)
}
return content
}

View File

@ -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'
}
}

View File

@ -2,6 +2,7 @@ package io.legado.app.utils
import io.legado.app.constant.AppLog
import io.legado.app.model.analyzeRule.AnalyzeUrl
import org.apache.commons.text.StringEscapeUtils
import org.jsoup.nodes.Entities
import java.net.URL
import java.util.regex.Pattern
@ -31,12 +32,8 @@ object HtmlFormatter {
.replace("\\s*\\n+\\s*".toRegex(), "\n  ")
.replace("^[\\n\\s]+".toRegex(), "  ")
.replace("[\\n\\s]+$".toRegex(), "")
.let { s ->
kotlin.runCatching {
Entities.unescape(s)
}.onFailure {
AppLog.put("Entities.unescape() error\n${it.localizedMessage}", it)
}.getOrDefault(s)
.let {
StringEscapeUtils.unescapeHtml3(it)
}
}

View File

@ -9,12 +9,16 @@ import java.io.InputStream
@Suppress("unused")
object MD5Utils {
private val MD5Digester by lazy {
DigestUtil.digester("MD5")
}
fun md5Encode(str: String?): String {
return DigestUtil.digester("MD5").digestHex(str)
return MD5Digester.digestHex(str)
}
fun md5Encode(inputStream: InputStream): String {
return DigestUtil.digester("MD5").digestHex(inputStream)
return MD5Digester.digestHex(inputStream)
}
fun md5Encode16(str: String): String {

View File

@ -32,9 +32,11 @@ abstract class AbstractScriptEngine(val bindings: Bindings? = null) : ScriptEngi
200 -> {
context.setBindings(bindings, 200)
}
100 -> {
context.setBindings(bindings, 100)
}
else -> {
throw IllegalArgumentException("Invalid scope value.")
}
@ -84,15 +86,11 @@ abstract class AbstractScriptEngine(val bindings: Bindings? = null) : ScriptEngi
}
override fun getScriptContext(bindings: Bindings): ScriptContext {
val ctx = SimpleScriptContext()
val ctx = SimpleScriptContext(bindings, context.errorWriter, context.reader, context.writer)
val gs = getBindings(200)
if (gs != null) {
ctx.setBindings(gs, 200)
}
ctx.setBindings(bindings, 100)
ctx.reader = context.reader
ctx.writer = context.writer
ctx.errorWriter = context.errorWriter
return ctx
}
}
}

View File

@ -9,12 +9,14 @@ import java.io.Reader
import java.io.Writer
import java.util.*
open class SimpleScriptContext : ScriptContext {
private var engineScope: Bindings = SimpleBindings()
override var errorWriter: Writer = PrintWriter(System.err, true)
private var globalScope: Bindings? = null
override var reader: Reader = InputStreamReader(System.`in`)
open class SimpleScriptContext(
private var engineScope: Bindings = SimpleBindings(),
override var errorWriter: Writer = PrintWriter(System.err, true),
override var reader: Reader = InputStreamReader(System.`in`),
override var writer: Writer = PrintWriter(System.out, true)
) : ScriptContext {
private var globalScope: Bindings? = null
override fun setBindings(bindings: Bindings?, scope: Int) {
when (scope) {
100 -> {
@ -24,6 +26,7 @@ open class SimpleScriptContext : ScriptContext {
engineScope = bindings
return
}
200 -> {
globalScope = bindings
return
@ -46,6 +49,7 @@ open class SimpleScriptContext : ScriptContext {
100 -> {
return engineScope[name]
}
200 -> {
return globalScope?.get(name)
}
@ -58,6 +62,7 @@ open class SimpleScriptContext : ScriptContext {
100 -> {
return getBindings(100)?.remove(name)
}
200 -> {
return getBindings(200)?.remove(name)
}
@ -71,6 +76,7 @@ open class SimpleScriptContext : ScriptContext {
engineScope[name] = value
return
}
200 -> {
globalScope?.put(name, value)
return