diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index 51f8714ea..03e52e43c 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -12,6 +12,7 @@ import android.os.Build import com.github.liuyueyi.quick.transfer.constants.TransType import com.jeremyliao.liveeventbus.LiveEventBus import com.jeremyliao.liveeventbus.logger.DefaultLogger +import com.script.rhino.RhinoScriptEngine import io.legado.app.base.AppContextWrapper import io.legado.app.constant.AppConst.channelIdDownload import io.legado.app.constant.AppConst.channelIdReadAloud @@ -77,6 +78,7 @@ class App : Application() { Coroutine.async { URL.setURLStreamHandlerFactory(ObsoleteUrlFactory(okHttpClient)) launch { installGmsTlsProvider(appCtx) } + RhinoScriptEngine //初始化封面 BookCover.toString() //清除过期数据 diff --git a/app/src/main/java/io/legado/app/data/entities/DictRule.kt b/app/src/main/java/io/legado/app/data/entities/DictRule.kt index 32df2a200..899309b4c 100644 --- a/app/src/main/java/io/legado/app/data/entities/DictRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/DictRule.kt @@ -5,6 +5,7 @@ import androidx.room.Entity import androidx.room.PrimaryKey import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeUrl +import kotlin.coroutines.coroutineContext /** * 字典规则 @@ -36,12 +37,12 @@ data class DictRule( * 搜索字典 */ suspend fun search(word: String): String { - val analyzeUrl = AnalyzeUrl(urlRule, key = word) + val analyzeUrl = AnalyzeUrl(urlRule, key = word, coroutineContext = coroutineContext) val body = analyzeUrl.getStrResponseAwait().body if (showRule.isBlank()) { return body!! } - val analyzeRule = AnalyzeRule() + val analyzeRule = AnalyzeRule().setCoroutineContext(coroutineContext) return analyzeRule.getString(showRule, mContent = body) } diff --git a/app/src/main/java/io/legado/app/help/DirectLinkUpload.kt b/app/src/main/java/io/legado/app/help/DirectLinkUpload.kt index 45b662e58..3cb01e978 100644 --- a/app/src/main/java/io/legado/app/help/DirectLinkUpload.kt +++ b/app/src/main/java/io/legado/app/help/DirectLinkUpload.kt @@ -14,6 +14,7 @@ import io.legado.app.utils.fromJsonArray import io.legado.app.utils.fromJsonObject import splitties.init.appCtx import java.io.File +import kotlin.coroutines.coroutineContext @Suppress("MemberVisibilityCanBePrivate") object DirectLinkUpload { @@ -60,6 +61,7 @@ object DirectLinkUpload { mFile.delete() } val analyzeRule = AnalyzeRule().setContent(res.body, res.url) + .setCoroutineContext(coroutineContext) val downloadUrl = analyzeRule.getString(downloadUrlRule) if (downloadUrl.isBlank()) { throw NoStackTraceException("上传失败,${res.body}") diff --git a/app/src/main/java/io/legado/app/help/book/BookHelp.kt b/app/src/main/java/io/legado/app/help/book/BookHelp.kt index 7554d54c6..f2587aec9 100644 --- a/app/src/main/java/io/legado/app/help/book/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/book/BookHelp.kt @@ -28,6 +28,7 @@ import io.legado.app.utils.getFile import io.legado.app.utils.isContentScheme import io.legado.app.utils.onEachParallel import io.legado.app.utils.postEvent +import io.legado.app.utils.runScriptWithContext import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.ensureActive @@ -232,12 +233,16 @@ object BookHelp { if (isImageExist(book, src)) { return } - val analyzeUrl = AnalyzeUrl(src, source = bookSource) + val analyzeUrl = AnalyzeUrl( + src, source = bookSource, coroutineContext = coroutineContext + ) val bytes = analyzeUrl.getByteArrayAwait() //某些图片被加密,需要进一步解密 - ImageUtils.decode( - src, bytes, isCover = false, bookSource, book - )?.let { + runScriptWithContext { + ImageUtils.decode( + src, bytes, isCover = false, bookSource, book + ) + }?.let { if (!checkImage(it)) { // 如果部分图片失效,每次进入正文都会花很长时间再次获取图片数据 // 所以无论如何都要将数据写入到文件里 @@ -546,12 +551,16 @@ object BookHelp { } private val chapterNamePattern1 by lazy { - Pattern.compile(".*?第([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+)[章节篇回集话]") + Pattern.compile( + ".*?第([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+)[章节篇回集话]" + ) } @Suppress("RegExpSimplifiable") private val chapterNamePattern2 by lazy { - Pattern.compile("^(?:[\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+[,:、])*([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+)(?:[,:、]|\\.[^\\d])") + Pattern.compile( + "^(?:[\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+[,:、])*([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+)(?:[,:、]|\\.[^\\d])" + ) } private val regexA by lazy { diff --git a/app/src/main/java/io/legado/app/help/glide/LegadoDataUrlLoader.kt b/app/src/main/java/io/legado/app/help/glide/LegadoDataUrlLoader.kt index 2601c0d3a..d089704be 100644 --- a/app/src/main/java/io/legado/app/help/glide/LegadoDataUrlLoader.kt +++ b/app/src/main/java/io/legado/app/help/glide/LegadoDataUrlLoader.kt @@ -12,6 +12,8 @@ import io.legado.app.exception.NoStackTraceException import io.legado.app.model.ReadManga import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.ImageUtils +import io.legado.app.utils.runScriptWithContext +import kotlinx.coroutines.Job import java.io.InputStream class LegadoDataUrlLoader : ModelLoader { @@ -33,15 +35,23 @@ class LegadoDataUrlLoader : ModelLoader { } class LegadoDataUrlFetcher(private val model: String) : DataFetcher { + + private val coroutineContext = Job() + override fun loadData( priority: Priority, callback: DataFetcher.DataCallback ) { try { - val bytes = AnalyzeUrl(model, source = ReadManga.bookSource).getByteArray() - val decoded = ImageUtils.decode( - model, bytes, isCover = false, ReadManga.bookSource, ReadManga.book - )?.inputStream() + val bytes = AnalyzeUrl( + model, source = ReadManga.bookSource, + coroutineContext = coroutineContext + ).getByteArray() + val decoded = runScriptWithContext(coroutineContext) { + ImageUtils.decode( + model, bytes, isCover = false, ReadManga.bookSource, ReadManga.book + )?.inputStream() + } if (decoded == null) { throw NoStackTraceException("漫画图片解密失败") } @@ -56,7 +66,7 @@ class LegadoDataUrlLoader : ModelLoader { } override fun cancel() { - // do nothing + coroutineContext.cancel() } override fun getDataClass(): Class { diff --git a/app/src/main/java/io/legado/app/help/glide/OkHttpStreamFetcher.kt b/app/src/main/java/io/legado/app/help/glide/OkHttpStreamFetcher.kt index 7e635521d..d602807a2 100644 --- a/app/src/main/java/io/legado/app/help/glide/OkHttpStreamFetcher.kt +++ b/app/src/main/java/io/legado/app/help/glide/OkHttpStreamFetcher.kt @@ -17,6 +17,8 @@ import io.legado.app.help.source.SourceHelp import io.legado.app.model.ReadManga import io.legado.app.utils.ImageUtils import io.legado.app.utils.isWifiConnect +import io.legado.app.utils.runScriptWithContext +import kotlinx.coroutines.Job import okhttp3.Call import okhttp3.Request import okhttp3.Response @@ -38,6 +40,7 @@ class OkHttpStreamFetcher( private var callback: DataFetcher.DataCallback? = null private var source: BaseSource? = null private val manga = options.get(OkHttpModelLoader.mangaOption) == true + private val coroutineContext = Job() @Volatile private var call: Call? = null @@ -89,6 +92,7 @@ class OkHttpStreamFetcher( override fun cancel() { call?.cancel() + coroutineContext.cancel() } override fun getDataClass(): Class { @@ -106,19 +110,21 @@ class OkHttpStreamFetcher( override fun onResponse(call: Call, response: Response) { responseBody = response.body if (response.isSuccessful) { - val decodeResult = if (manga) { - ImageUtils.decode( - oldUrl.toString(), - responseBody!!.bytes(), - isCover = false, - source, - ReadManga.book - )?.inputStream() - } else { - ImageUtils.decode( - url.toStringUrl(), responseBody!!.byteStream(), - isCover = true, source - ) + val decodeResult = runScriptWithContext(coroutineContext) { + if (manga) { + ImageUtils.decode( + oldUrl.toString(), + responseBody!!.bytes(), + isCover = false, + source, + ReadManga.book + )?.inputStream() + } else { + ImageUtils.decode( + url.toStringUrl(), responseBody!!.byteStream(), + isCover = true, source + ) + } } if (decodeResult == null) { callback?.onLoadFailed(NoStackTraceException("封面二次解密失败")) diff --git a/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt b/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt index 2208218e5..8ead82d4e 100644 --- a/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt +++ b/app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt @@ -11,6 +11,7 @@ import io.legado.app.utils.MD5Utils import io.legado.app.utils.fromJsonArray import io.legado.app.utils.isJsonArray import io.legado.app.utils.printOnDebug +import io.legado.app.utils.runScriptWithContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -61,7 +62,9 @@ suspend fun BookSource.exploreKinds(): List { } else { exploreUrl.substring(4, exploreUrl.lastIndexOf("<")) } - ruleStr = evalJS(jsStr).toString().trim() + ruleStr = runScriptWithContext { + evalJS(jsStr).toString().trim() + } aCache.put(exploreKindsKey, ruleStr) } } diff --git a/app/src/main/java/io/legado/app/help/source/RssSourceExtensions.kt b/app/src/main/java/io/legado/app/help/source/RssSourceExtensions.kt index 5f5b62687..beecad74a 100644 --- a/app/src/main/java/io/legado/app/help/source/RssSourceExtensions.kt +++ b/app/src/main/java/io/legado/app/help/source/RssSourceExtensions.kt @@ -4,6 +4,7 @@ import io.legado.app.data.entities.RssSource import io.legado.app.utils.ACache import io.legado.app.utils.MD5Utils import io.legado.app.utils.NetworkUtils +import io.legado.app.utils.runScriptWithContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -29,7 +30,9 @@ suspend fun RssSource.sortUrls(): List> { } else { sortUrl!!.substring(4, sortUrl!!.lastIndexOf("<")) } - str = evalJS(jsStr).toString() + str = runScriptWithContext { + evalJS(jsStr).toString() + } aCache.put(sortUrlsKey, str) } } diff --git a/app/src/main/java/io/legado/app/help/source/SourceVerificationHelp.kt b/app/src/main/java/io/legado/app/help/source/SourceVerificationHelp.kt index 5f28d6a9b..4b9497750 100644 --- a/app/src/main/java/io/legado/app/help/source/SourceVerificationHelp.kt +++ b/app/src/main/java/io/legado/app/help/source/SourceVerificationHelp.kt @@ -84,7 +84,6 @@ object SourceVerificationHelp { putExtra("sourceName", source.getTag()) putExtra("sourceVerificationEnable", saveResult) putExtra("refetchAfterSuccess", refetchAfterSuccess) - IntentData.put(url, source.getHeaderMap(true)) IntentData.put(getVerificationResultKey(source), Thread.currentThread()) } } diff --git a/app/src/main/java/io/legado/app/model/BookCover.kt b/app/src/main/java/io/legado/app/model/BookCover.kt index c415d6a46..f987a2e8c 100644 --- a/app/src/main/java/io/legado/app/model/BookCover.kt +++ b/app/src/main/java/io/legado/app/model/BookCover.kt @@ -31,6 +31,7 @@ import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefString import splitties.init.appCtx import java.io.File +import kotlin.coroutines.coroutineContext @Keep object BookCover { @@ -174,10 +175,12 @@ object BookCover { config.searchUrl, book.name, source = config, - headerMapF = config.getHeaderMap() + coroutineContext = coroutineContext, + hasLoginHeader = false ) val res = analyzeUrl.getStrResponseAwait() val analyzeRule = AnalyzeRule(book) + analyzeRule.setCoroutineContext(coroutineContext) analyzeRule.setContent(res.body) analyzeRule.setRedirectUrl(res.url) return analyzeRule.getString(config.coverRule, isUrl = true) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 9a2ac4ab9..336558be7 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -45,6 +45,7 @@ import io.legado.app.utils.isJson import io.legado.app.utils.isJsonArray import io.legado.app.utils.isJsonObject import io.legado.app.utils.isXml +import io.legado.app.utils.runScriptWithContext import io.legado.app.utils.splitNotBlank import kotlinx.coroutines.runBlocking import okhttp3.MediaType.Companion.toMediaType @@ -81,6 +82,7 @@ class AnalyzeUrl( private val readTimeout: Long? = null, private var coroutineContext: CoroutineContext = EmptyCoroutineContext, headerMapF: Map? = null, + hasLoginHeader: Boolean = true ) : JsExtensions { companion object { val paramPattern: Pattern = Pattern.compile("\\s*,\\s*(?=\\{)") @@ -118,7 +120,9 @@ class AnalyzeUrl( coroutineContext = coroutineContext.minusKey(ContinuationInterceptor) val urlMatcher = paramPattern.matcher(baseUrl) if (urlMatcher.find()) baseUrl = baseUrl.substring(0, urlMatcher.start()) - (headerMapF ?: source?.getHeaderMap(true))?.let { + (headerMapF ?: runScriptWithContext(coroutineContext) { + source?.getHeaderMap(hasLoginHeader) + })?.let { headerMap.putAll(it) if (it.containsKey("proxy")) { proxy = it["proxy"] diff --git a/app/src/main/java/io/legado/app/model/rss/Rss.kt b/app/src/main/java/io/legado/app/model/rss/Rss.kt index 444cb2cd7..977c63dd5 100644 --- a/app/src/main/java/io/legado/app/model/rss/Rss.kt +++ b/app/src/main/java/io/legado/app/model/rss/Rss.kt @@ -12,6 +12,7 @@ import io.legado.app.utils.NetworkUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.coroutineContext @Suppress("MemberVisibilityCanBePrivate") object Rss { @@ -41,7 +42,8 @@ object Rss { page = page, source = rssSource, ruleData = ruleData, - headerMapF = rssSource.getHeaderMap() + coroutineContext = coroutineContext, + hasLoginHeader = false ) val res = analyzeUrl.getStrResponseAwait() checkRedirect(rssSource, res) @@ -70,7 +72,8 @@ object Rss { baseUrl = rssArticle.origin, source = rssSource, ruleData = rssArticle, - headerMapF = rssSource.getHeaderMap() + coroutineContext = coroutineContext, + hasLoginHeader = false ) val res = analyzeUrl.getStrResponseAwait() checkRedirect(rssSource, res) @@ -79,6 +82,7 @@ object Rss { val analyzeRule = AnalyzeRule(rssArticle, rssSource) analyzeRule.setContent(res.body) .setBaseUrl(NetworkUtils.getAbsoluteURL(rssArticle.origin, rssArticle.link)) + .setCoroutineContext(coroutineContext) .setRedirectUrl(res.url) return analyzeRule.getString(ruleContent) } diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index 0f4c41b20..7b573e460 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -11,12 +11,13 @@ import io.legado.app.model.analyzeRule.RuleData import io.legado.app.utils.NetworkUtils import splitties.init.appCtx import java.util.Locale +import kotlin.coroutines.coroutineContext @Keep object RssParserByRule { @Throws(Exception::class) - fun parseXML( + suspend fun parseXML( sortName: String, sortUrl: String, redirectUrl: String, @@ -40,6 +41,7 @@ object RssParserByRule { } else { val articleList = mutableListOf() val analyzeRule = AnalyzeRule(ruleData, rssSource) + analyzeRule.setCoroutineContext(coroutineContext) analyzeRule.setContent(body).setBaseUrl(sortUrl) analyzeRule.setRedirectUrl(redirectUrl) var reverse = false diff --git a/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt index 2714cfafd..d34f53c54 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt @@ -70,7 +70,6 @@ object BookChapterList { mUrl = nextUrl, source = bookSource, ruleData = book, - headerMapF = bookSource.getHeaderMap(), coroutineContext = coroutineContext ) val res = analyzeUrl.getStrResponseAwait() //控制并发访问 @@ -100,7 +99,6 @@ object BookChapterList { mUrl = urlStr, source = bookSource, ruleData = book, - headerMapF = bookSource.getHeaderMap(), coroutineContext = coroutineContext ) val res = analyzeUrl.getStrResponseAwait() //控制并发访问 diff --git a/app/src/main/java/io/legado/app/model/webBook/BookContent.kt b/app/src/main/java/io/legado/app/model/webBook/BookContent.kt index 6f4d348f2..35dfa8cdd 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webBook/BookContent.kt @@ -90,7 +90,6 @@ object BookContent { mUrl = nextUrl, source = bookSource, ruleData = book, - headerMapF = bookSource.getHeaderMap(), coroutineContext = coroutineContext ) val res = analyzeUrl.getStrResponseAwait() //控制并发访问 @@ -118,7 +117,6 @@ object BookContent { mUrl = urlStr, source = bookSource, ruleData = book, - headerMapF = bookSource.getHeaderMap(), coroutineContext = coroutineContext ) val res = analyzeUrl.getStrResponseAwait() //控制并发访问 diff --git a/app/src/main/java/io/legado/app/model/webBook/WebBook.kt b/app/src/main/java/io/legado/app/model/webBook/WebBook.kt index fbd1518b0..2698e6440 100644 --- a/app/src/main/java/io/legado/app/model/webBook/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/webBook/WebBook.kt @@ -62,7 +62,6 @@ object WebBook { key = key, page = page, baseUrl = bookSource.bookSourceUrl, - headerMapF = bookSource.getHeaderMap(true), source = bookSource, ruleData = ruleData, coroutineContext = coroutineContext @@ -115,7 +114,6 @@ object WebBook { baseUrl = bookSource.bookSourceUrl, source = bookSource, ruleData = ruleData, - headerMapF = bookSource.getHeaderMap(true), coroutineContext = coroutineContext ) var res = analyzeUrl.getStrResponseAwait() @@ -173,7 +171,6 @@ object WebBook { baseUrl = bookSource.bookSourceUrl, source = bookSource, ruleData = book, - headerMapF = bookSource.getHeaderMap(true), coroutineContext = coroutineContext ) var res = analyzeUrl.getStrResponseAwait() @@ -249,7 +246,6 @@ object WebBook { baseUrl = book.bookUrl, source = bookSource, ruleData = book, - headerMapF = bookSource.getHeaderMap(true), coroutineContext = coroutineContext ) var res = analyzeUrl.getStrResponseAwait() @@ -328,7 +324,6 @@ object WebBook { source = bookSource, ruleData = book, chapter = bookChapter, - headerMapF = bookSource.getHeaderMap(true), coroutineContext = coroutineContext ) var res = analyzeUrl.getStrResponseAwait( diff --git a/app/src/main/java/io/legado/app/service/AudioPlayService.kt b/app/src/main/java/io/legado/app/service/AudioPlayService.kt index 086fd3c14..713e7cfbc 100644 --- a/app/src/main/java/io/legado/app/service/AudioPlayService.kt +++ b/app/src/main/java/io/legado/app/service/AudioPlayService.kt @@ -225,6 +225,7 @@ class AudioPlayService : BaseService(), source = AudioPlay.bookSource, ruleData = AudioPlay.book, chapter = AudioPlay.durChapter, + coroutineContext = coroutineContext ) exoPlayer.setMediaItem(analyzeUrl.getMediaItem()) exoPlayer.playWhenReady = true diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index cbc4fd18e..fe0800cbd 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -328,7 +328,6 @@ class HttpReadAloudService : BaseReadAloudService(), speakText = speakText, speakSpeed = speechRate, source = httpTts, - headerMapF = httpTts.getHeaderMap(true), readTimeout = 300 * 1000L, coroutineContext = coroutineContext ) diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt index 73cf7d5f3..074f038c1 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt @@ -274,7 +274,10 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { val fileNameNoExtension = if (book.author.isBlank()) book.name else "${book.name} 作者:${book.author}" book.downloadUrls!!.map { - val analyzeUrl = AnalyzeUrl(it, source = bookSource) + val analyzeUrl = AnalyzeUrl( + it, source = bookSource, + coroutineContext = coroutineContext + ) val mFileName = UrlUtil.getFileName(analyzeUrl) ?: "${fileNameNoExtension}.${analyzeUrl.type}" WebFile(it, mFileName) diff --git a/app/src/main/java/io/legado/app/ui/book/read/MangaMenu.kt b/app/src/main/java/io/legado/app/ui/book/read/MangaMenu.kt index 27e599a7f..73724e6cd 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/MangaMenu.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/MangaMenu.kt @@ -12,10 +12,10 @@ import androidx.core.view.isGone import androidx.core.view.isVisible import io.legado.app.R import io.legado.app.databinding.ViewMangaMenuBinding -import io.legado.app.help.IntentData import io.legado.app.help.config.AppConfig import io.legado.app.lib.dialogs.alert import io.legado.app.lib.theme.bottomBackground +import io.legado.app.model.ReadBook import io.legado.app.model.ReadManga import io.legado.app.ui.browser.WebViewActivity import io.legado.app.ui.widget.seekbar.SeekBarChangeListener @@ -176,9 +176,11 @@ class MangaMenu @JvmOverloads constructor( } else { context.startActivity { val url = tvChapterUrl.text.toString() + val bookSource = ReadBook.bookSource putExtra("title", tvChapterName.text) putExtra("url", url) - IntentData.put(url, ReadManga.bookSource?.getHeaderMap(true)) + putExtra("sourceOrigin", bookSource?.bookSourceUrl) + putExtra("sourceName", bookSource?.bookSourceName) } } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 734c10226..a51a25856 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -1281,7 +1281,7 @@ class ReadBookActivity : BaseReadBookActivity(), alert(R.string.chapter_pay) { setMessage(chapter.title) yesButton { - Coroutine.async { + Coroutine.async(lifecycleScope) { val source = ReadBook.bookSource ?: throw NoStackTraceException("no book source") val payAction = source.getContentRule().payAction @@ -1289,6 +1289,7 @@ class ReadBookActivity : BaseReadBookActivity(), throw NoStackTraceException("no pay action") } val analyzeRule = AnalyzeRule(book, source) + analyzeRule.setCoroutineContext(coroutineContext) analyzeRule.setBaseUrl(chapter.url) analyzeRule.chapter = chapter analyzeRule.evalJS(payAction).toString() @@ -1297,7 +1298,7 @@ class ReadBookActivity : BaseReadBookActivity(), startActivity { putExtra("title", getString(R.string.chapter_pay)) putExtra("url", it) - IntentData.put(it, ReadBook.bookSource?.getHeaderMap(true)) + putExtra("sourceOrigin", ReadBook.bookSource?.bookSourceUrl) } } else if (it.isTrue()) { //购买成功后刷新目录 diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt index b16ec6f06..ba69b4e56 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt @@ -18,7 +18,6 @@ import androidx.core.view.isVisible import io.legado.app.R import io.legado.app.constant.PreferKey import io.legado.app.databinding.ViewReadMenuBinding -import io.legado.app.help.IntentData import io.legado.app.help.config.AppConfig import io.legado.app.help.config.LocalConfig import io.legado.app.help.config.ReadBookConfig @@ -350,9 +349,11 @@ class ReadMenu @JvmOverloads constructor( Coroutine.async { context.startActivity { val url = tvChapterUrl.text.toString() + val bookSource = ReadBook.bookSource putExtra("title", tvChapterName.text) putExtra("url", url) - IntentData.put(url, ReadBook.bookSource?.getHeaderMap(true)) + putExtra("sourceOrigin", bookSource?.bookSourceUrl) + putExtra("sourceName", bookSource?.bookSourceName) } } } diff --git a/app/src/main/java/io/legado/app/ui/browser/WebViewModel.kt b/app/src/main/java/io/legado/app/ui/browser/WebViewModel.kt index e0e7caca8..75d9fdd1c 100644 --- a/app/src/main/java/io/legado/app/ui/browser/WebViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/browser/WebViewModel.kt @@ -11,7 +11,6 @@ import io.legado.app.base.BaseViewModel import io.legado.app.constant.AppConst import io.legado.app.data.appDb import io.legado.app.exception.NoStackTraceException -import io.legado.app.help.IntentData import io.legado.app.help.http.newCallResponseBody import io.legado.app.help.http.okHttpClient import io.legado.app.help.source.SourceVerificationHelp @@ -48,8 +47,8 @@ class WebViewModel(application: Application) : BaseViewModel(application) { sourceOrigin = intent.getStringExtra("sourceOrigin") ?: "" sourceVerificationEnable = intent.getBooleanExtra("sourceVerificationEnable", false) refetchAfterSuccess = intent.getBooleanExtra("refetchAfterSuccess", true) - val headerMapF = IntentData.get>(url) - val analyzeUrl = AnalyzeUrl(url, headerMapF = headerMapF) + val source = appDb.bookSourceDao.getBookSource(sourceOrigin) + val analyzeUrl = AnalyzeUrl(url, source = source, coroutineContext = coroutineContext) baseUrl = analyzeUrl.url headerMap.putAll(analyzeUrl.headerMap) if (analyzeUrl.isPost()) { @@ -107,7 +106,8 @@ class WebViewModel(application: Application) : BaseViewModel(application) { html = AnalyzeUrl( url, headerMapF = headerMap, - source = source + source = source, + coroutineContext = coroutineContext ).getStrResponseAwait(useWebView = false).body SourceVerificationHelp.setResult(sourceOrigin, html ?: "") }.onSuccess { diff --git a/app/src/main/java/io/legado/app/ui/login/SourceLoginDialog.kt b/app/src/main/java/io/legado/app/ui/login/SourceLoginDialog.kt index a8ab81018..dc7326651 100644 --- a/app/src/main/java/io/legado/app/ui/login/SourceLoginDialog.kt +++ b/app/src/main/java/io/legado/app/ui/login/SourceLoginDialog.kt @@ -16,7 +16,6 @@ import io.legado.app.data.entities.rule.RowUi import io.legado.app.databinding.DialogLoginBinding import io.legado.app.databinding.ItemFilletTextBinding import io.legado.app.databinding.ItemSourceEditBinding -import io.legado.app.help.coroutine.Coroutine import io.legado.app.lib.dialogs.alert import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.about.AppLogDialog @@ -26,6 +25,7 @@ import io.legado.app.utils.dpToPx import io.legado.app.utils.isAbsUrl import io.legado.app.utils.openUrl import io.legado.app.utils.printOnDebug +import io.legado.app.utils.runScriptWithContext import io.legado.app.utils.setLayout import io.legado.app.utils.showDialogFragment import io.legado.app.utils.toastOnUi @@ -119,16 +119,18 @@ class SourceLoginDialog : BaseDialogFragment(R.layout.dialog_login, true) { } private fun handleButtonClick(source: BaseSource, rowUi: RowUi, loginUi: List) { - Coroutine.async { + lifecycleScope.launch(IO) { if (rowUi.action.isAbsUrl()) { context?.openUrl(rowUi.action!!) } else if (rowUi.action != null) { // JavaScript val buttonFunctionJS = rowUi.action!! - val loginJS = source.getLoginJs() ?: return@async + val loginJS = source.getLoginJs() ?: return@launch kotlin.runCatching { - source.evalJS("$loginJS\n$buttonFunctionJS") { - put("result", getLoginData(loginUi)) + runScriptWithContext { + source.evalJS("$loginJS\n$buttonFunctionJS") { + put("result", getLoginData(loginUi)) + } } }.onFailure { e -> AppLog.put("LoginUI Button ${rowUi.name} JavaScript error", e) @@ -161,7 +163,9 @@ class SourceLoginDialog : BaseDialogFragment(R.layout.dialog_login, true) { } } else if (source.putLoginInfo(GSON.toJson(loginData))) { try { - source.login() + runScriptWithContext { + source.login() + } context?.toastOnUi(R.string.success) withContext(Main) { dismiss() diff --git a/app/src/main/java/io/legado/app/ui/login/SourceLoginViewModel.kt b/app/src/main/java/io/legado/app/ui/login/SourceLoginViewModel.kt index 056b47612..0774407b4 100644 --- a/app/src/main/java/io/legado/app/ui/login/SourceLoginViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/login/SourceLoginViewModel.kt @@ -6,11 +6,13 @@ import io.legado.app.base.BaseViewModel import io.legado.app.data.appDb import io.legado.app.data.entities.BaseSource import io.legado.app.exception.NoStackTraceException +import io.legado.app.utils.runScriptWithContext import io.legado.app.utils.toastOnUi class SourceLoginViewModel(application: Application) : BaseViewModel(application) { var source: BaseSource? = null + var headerMap: Map = emptyMap() fun initData(intent: Intent, success: (bookSource: BaseSource) -> Unit) { execute { @@ -21,6 +23,9 @@ class SourceLoginViewModel(application: Application) : BaseViewModel(application "rssSource" -> source = appDb.rssSourceDao.getByKey(sourceKey) "httpTts" -> source = appDb.httpTTSDao.get(sourceKey.toLong()) } + headerMap = runScriptWithContext { + source?.getHeaderMap(true) ?: emptyMap() + } source }.onSuccess { if (it != null) { diff --git a/app/src/main/java/io/legado/app/ui/login/WebViewLoginFragment.kt b/app/src/main/java/io/legado/app/ui/login/WebViewLoginFragment.kt index da6b763fb..ece7a5bcb 100644 --- a/app/src/main/java/io/legado/app/ui/login/WebViewLoginFragment.kt +++ b/app/src/main/java/io/legado/app/ui/login/WebViewLoginFragment.kt @@ -16,6 +16,7 @@ import android.webkit.WebSettings import android.webkit.WebView import android.webkit.WebViewClient import androidx.fragment.app.activityViewModels +import androidx.lifecycle.lifecycleScope import io.legado.app.R import io.legado.app.base.BaseFragment import io.legado.app.constant.AppConst @@ -29,6 +30,7 @@ import io.legado.app.utils.longSnackbar import io.legado.app.utils.openUrl import io.legado.app.utils.snackbar import io.legado.app.utils.viewbindingdelegate.viewBinding +import kotlinx.coroutines.launch class WebViewLoginFragment : BaseFragment(R.layout.fragment_web_view_login) { @@ -55,11 +57,8 @@ class WebViewLoginFragment : BaseFragment(R.layout.fragment_web_view_login) { if (!checking) { checking = true binding.titleBar.snackbar(R.string.check_host_cookie) - viewModel.source?.let { source -> - source.loginUrl?.let { - val absoluteUrl = NetworkUtils.getAbsoluteURL(source.getKey(), it) - binding.webView.loadUrl(absoluteUrl, source.getHeaderMap(true)) - } + viewModel.source?.let { + loadUrl(it) } } } @@ -77,7 +76,7 @@ class WebViewLoginFragment : BaseFragment(R.layout.fragment_web_view_login) { builtInZoomControls = true javaScriptEnabled = true displayZoomControls = false - source.getHeaderMap()[AppConst.UA_NAME]?.let { + viewModel.headerMap[AppConst.UA_NAME]?.let { userAgentString = it } } @@ -143,9 +142,14 @@ class WebViewLoginFragment : BaseFragment(R.layout.fragment_web_view_login) { } } - source.loginUrl?.let { - val absoluteUrl = NetworkUtils.getAbsoluteURL(source.getKey(), it) - binding.webView.loadUrl(absoluteUrl, source.getHeaderMap(true)) + loadUrl(source) + } + + private fun loadUrl(source: BaseSource) { + lifecycleScope.launch { + val loginUrl = source.loginUrl ?: return@launch + val absoluteUrl = NetworkUtils.getAbsoluteURL(source.getKey(), loginUrl) + binding.webView.loadUrl(absoluteUrl, viewModel.headerMap) } } diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssViewModel.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssViewModel.kt index 486ee99bc..c033459ed 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssViewModel.kt @@ -4,6 +4,7 @@ import android.app.Application import io.legado.app.base.BaseViewModel import io.legado.app.data.appDb import io.legado.app.data.entities.RssSource +import io.legado.app.utils.runScriptWithContext import io.legado.app.utils.toastOnUi class RssViewModel(application: Application) : BaseViewModel(application) { @@ -58,7 +59,9 @@ class RssViewModel(application: Application) : BaseViewModel(application) { } else { sortUrl.substring(4, sortUrl.lastIndexOf("<")) } - val result = rssSource.evalJS(jsStr)?.toString() + val result = runScriptWithContext { + rssSource.evalJS(jsStr)?.toString() + } if (!result.isNullOrBlank()) { sortUrl = result } diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index f470a438d..b64d87c9e 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -46,7 +46,6 @@ import io.legado.app.ui.login.SourceLoginActivity import io.legado.app.ui.rss.favorites.RssFavoritesDialog import io.legado.app.utils.ACache import io.legado.app.utils.NetworkUtils -import io.legado.app.utils.get import io.legado.app.utils.gone import io.legado.app.utils.invisible import io.legado.app.utils.isTrue @@ -187,7 +186,7 @@ class ReadRssActivity : VMBaseActivity } override fun updateFavorite(title: String?, group: String?) { - viewModel.rssArticle?.let{ + viewModel.rssArticle?.let { if (title != null) { it.title = title } @@ -294,8 +293,7 @@ class ReadRssActivity : VMBaseActivity val url = NetworkUtils.getAbsoluteURL(it.origin, it.link) val html = viewModel.clHtml(content) binding.webView.settings.userAgentString = - viewModel.rssSource?.getHeaderMap()?.get(AppConst.UA_NAME, true) - ?: AppConfig.userAgent + viewModel.headerMap[AppConst.UA_NAME] ?: AppConfig.userAgent if (viewModel.rssSource?.loadWithBaseUrl == true) { binding.webView .loadDataWithBaseURL(url, html, "text/html", "utf-8", url)//不想用baseUrl进else diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index c59e5f4ff..bb5395722 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -21,11 +21,13 @@ import io.legado.app.help.http.newCallResponseBody import io.legado.app.help.http.okHttpClient import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.model.rss.Rss +import io.legado.app.utils.runScriptWithContext import io.legado.app.utils.toastOnUi import io.legado.app.utils.writeBytes import kotlinx.coroutines.Dispatchers.IO import splitties.init.appCtx import java.util.Date +import kotlin.coroutines.coroutineContext class ReadRssViewModel(application: Application) : BaseViewModel(application), JsExtensions { @@ -37,6 +39,7 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application), J var rssStar: RssStar? = null val upTtsMenuData = MutableLiveData() val upStarMenuData = MutableLiveData() + var headerMap: Map = emptyMap() override fun getSource(): BaseSource? { return rssSource @@ -47,6 +50,9 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application), J val origin = intent.getStringExtra("origin") ?: return@execute val link = intent.getStringExtra("link") rssSource = appDb.rssSourceDao.getByKey(origin) + headerMap = runScriptWithContext { + rssSource?.getHeaderMap() ?: emptyMap() + } if (link != null) { rssStar = appDb.rssStarDao.get(origin, link) rssArticle = rssStar?.toRssArticle() ?: appDb.rssArticleDao.get(origin, link) @@ -80,11 +86,13 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application), J } } - private fun loadUrl(url: String, baseUrl: String) { + private suspend fun loadUrl(url: String, baseUrl: String) { val analyzeUrl = AnalyzeUrl( mUrl = url, baseUrl = baseUrl, - headerMapF = rssSource?.getHeaderMap() + source = rssSource, + coroutineContext = coroutineContext, + hasLoginHeader = false ) urlLiveData.postValue(analyzeUrl) } diff --git a/modules/rhino/src/main/java/com/script/rhino/RhinoExtensions.kt b/modules/rhino/src/main/java/com/script/rhino/RhinoExtensions.kt index d5e0c82da..4097956a1 100644 --- a/modules/rhino/src/main/java/com/script/rhino/RhinoExtensions.kt +++ b/modules/rhino/src/main/java/com/script/rhino/RhinoExtensions.kt @@ -1,5 +1,7 @@ package io.legado.app.utils +import com.script.rhino.RhinoContext +import com.script.rhino.RhinoScriptEngine import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.runBlocking import kotlinx.coroutines.supervisorScope @@ -7,6 +9,9 @@ import org.mozilla.javascript.Context import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract +import kotlin.coroutines.ContinuationInterceptor +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.coroutineContext @Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND") @OptIn(ExperimentalContracts::class) @@ -29,3 +34,28 @@ inline fun suspendContinuation(crossinline block: suspend CoroutineScope.() Context.exit() } } + +inline fun runScriptWithContext(context: CoroutineContext, block: () -> T): T { + RhinoScriptEngine + val rhinoContext = Context.enter() as RhinoContext + val previousCoroutineContext = rhinoContext.coroutineContext + rhinoContext.coroutineContext = context.minusKey(ContinuationInterceptor) + try { + return block() + } finally { + rhinoContext.coroutineContext = previousCoroutineContext + Context.exit() + } +} + +suspend inline fun runScriptWithContext(block: () -> T): T { + val rhinoContext = Context.enter() as RhinoContext + val previousCoroutineContext = rhinoContext.coroutineContext + rhinoContext.coroutineContext = coroutineContext.minusKey(ContinuationInterceptor) + try { + return block() + } finally { + rhinoContext.coroutineContext = previousCoroutineContext + Context.exit() + } +} diff --git a/modules/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt b/modules/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt index 271a3a131..5ec250dec 100644 --- a/modules/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt +++ b/modules/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt @@ -93,7 +93,9 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable { ): Any? { val cx = Context.enter() as RhinoContext val previousCoroutineContext = cx.coroutineContext - cx.coroutineContext = coroutineContext + if (coroutineContext != null) { + cx.coroutineContext = coroutineContext + } cx.allowScriptRun = true val ret: Any? try {