This commit is contained in:
Horis
2026-03-03 15:59:41 +08:00
parent 847d268db0
commit c8e7591f06
@@ -1,13 +1,16 @@
package io.legado.app.utils package io.legado.app.utils
import androidx.core.os.postDelayed
import com.script.ScriptBindings import com.script.ScriptBindings
import com.script.rhino.RhinoScriptEngine import com.script.rhino.RhinoScriptEngine
import io.legado.app.exception.RegexTimeoutException import io.legado.app.exception.RegexTimeoutException
import io.legado.app.help.CrashHandler import io.legado.app.help.CrashHandler
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.selects.onTimeout
import kotlinx.coroutines.selects.select
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import splitties.init.appCtx import splitties.init.appCtx
import java.util.regex.Matcher import java.util.regex.Matcher
@@ -19,47 +22,52 @@ private val handler by lazy { buildMainHandler() }
/** /**
* 带有超时检测的正则替换 * 带有超时检测的正则替换
*/ */
@OptIn(ExperimentalCoroutinesApi::class)
fun CharSequence.replace(regex: Regex, replacement: String, timeout: Long): String { fun CharSequence.replace(regex: Regex, replacement: String, timeout: Long): String {
val charSequence = this@replace val charSequence = this@replace
val isJs = replacement.startsWith("@js:") val isJs = replacement.startsWith("@js:")
val replacement1 = if (isJs) replacement.substring(4) else replacement val replacement1 = if (isJs) replacement.substring(4) else replacement
return runBlocking { return runBlocking {
suspendCancellableCoroutine { block -> suspendCancellableCoroutine { block ->
val coroutine = Coroutine.async(executeContext = IO) { Coroutine.async(executeContext = IO) {
try { val job = launch {
val pattern = regex.toPattern() try {
val matcher = pattern.matcher(charSequence) val pattern = regex.toPattern()
val stringBuffer = StringBuffer() val matcher = pattern.matcher(charSequence)
while (matcher.find()) { val stringBuffer = StringBuffer()
if (isJs) { while (matcher.find()) {
val jsResult = RhinoScriptEngine.run { if (isJs) {
val bindings = ScriptBindings() val jsResult = RhinoScriptEngine.run {
bindings["result"] = matcher.group() val bindings = ScriptBindings()
eval(replacement1, bindings) bindings["result"] = matcher.group()
}.toString() eval(replacement1, bindings)
val quotedResult = Matcher.quoteReplacement(jsResult) }.toString()
matcher.appendReplacement(stringBuffer, quotedResult) val quotedResult = Matcher.quoteReplacement(jsResult)
} else { matcher.appendReplacement(stringBuffer, quotedResult)
matcher.appendReplacement(stringBuffer, replacement1) } else {
matcher.appendReplacement(stringBuffer, replacement1)
}
} }
matcher.appendTail(stringBuffer)
block.resume(stringBuffer.toString())
} catch (e: Exception) {
block.resumeWithException(e)
} }
matcher.appendTail(stringBuffer)
block.resume(stringBuffer.toString())
} catch (e: Exception) {
block.resumeWithException(e)
} }
} select {
handler.postDelayed(timeout) { job.onJoin {}
if (coroutine.isActive) { onTimeout(timeout) {
val timeoutMsg = val timeoutMsg =
"替换超时,3秒后还未结束将重启应用\n替换规则$regex\n替换内容:$charSequence" "替换超时,3秒后还未结束将重启应用\n替换规则$regex\n替换内容:$charSequence"
val exception = RegexTimeoutException(timeoutMsg) val exception = RegexTimeoutException(timeoutMsg)
block.cancel(exception) block.cancel(exception)
appCtx.longToastOnUi(timeoutMsg) appCtx.longToastOnUi(timeoutMsg)
CrashHandler.saveCrashInfo2File(exception) CrashHandler.saveCrashInfo2File(exception)
handler.postDelayed(3000) { select {
if (coroutine.isActive) { job.onJoin {}
appCtx.restart() onTimeout(3000) {
appCtx.restart()
}
} }
} }
} }