Horis 1 год назад
Родитель
Сommit
b07b9dcf77
31 измененных файлов с 178 добавлено и 78 удалено
  1. 2 0
      app/src/main/java/io/legado/app/App.kt
  2. 3 2
      app/src/main/java/io/legado/app/data/entities/DictRule.kt
  3. 2 0
      app/src/main/java/io/legado/app/help/DirectLinkUpload.kt
  4. 15 6
      app/src/main/java/io/legado/app/help/book/BookHelp.kt
  5. 15 5
      app/src/main/java/io/legado/app/help/glide/LegadoDataUrlLoader.kt
  6. 19 13
      app/src/main/java/io/legado/app/help/glide/OkHttpStreamFetcher.kt
  7. 4 1
      app/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt
  8. 4 1
      app/src/main/java/io/legado/app/help/source/RssSourceExtensions.kt
  9. 0 1
      app/src/main/java/io/legado/app/help/source/SourceVerificationHelp.kt
  10. 4 1
      app/src/main/java/io/legado/app/model/BookCover.kt
  11. 5 1
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt
  12. 6 2
      app/src/main/java/io/legado/app/model/rss/Rss.kt
  13. 3 1
      app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt
  14. 0 2
      app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt
  15. 0 2
      app/src/main/java/io/legado/app/model/webBook/BookContent.kt
  16. 0 5
      app/src/main/java/io/legado/app/model/webBook/WebBook.kt
  17. 1 0
      app/src/main/java/io/legado/app/service/AudioPlayService.kt
  18. 0 1
      app/src/main/java/io/legado/app/service/HttpReadAloudService.kt
  19. 4 1
      app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt
  20. 4 2
      app/src/main/java/io/legado/app/ui/book/read/MangaMenu.kt
  21. 3 2
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  22. 3 2
      app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt
  23. 4 4
      app/src/main/java/io/legado/app/ui/browser/WebViewModel.kt
  24. 10 6
      app/src/main/java/io/legado/app/ui/login/SourceLoginDialog.kt
  25. 5 0
      app/src/main/java/io/legado/app/ui/login/SourceLoginViewModel.kt
  26. 13 9
      app/src/main/java/io/legado/app/ui/login/WebViewLoginFragment.kt
  27. 4 1
      app/src/main/java/io/legado/app/ui/main/rss/RssViewModel.kt
  28. 2 4
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
  29. 10 2
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt
  30. 30 0
      modules/rhino/src/main/java/com/script/rhino/RhinoExtensions.kt
  31. 3 1
      modules/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt

+ 2 - 0
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.github.liuyueyi.quick.transfer.constants.TransType
 import com.jeremyliao.liveeventbus.LiveEventBus
 import com.jeremyliao.liveeventbus.LiveEventBus
 import com.jeremyliao.liveeventbus.logger.DefaultLogger
 import com.jeremyliao.liveeventbus.logger.DefaultLogger
+import com.script.rhino.RhinoScriptEngine
 import io.legado.app.base.AppContextWrapper
 import io.legado.app.base.AppContextWrapper
 import io.legado.app.constant.AppConst.channelIdDownload
 import io.legado.app.constant.AppConst.channelIdDownload
 import io.legado.app.constant.AppConst.channelIdReadAloud
 import io.legado.app.constant.AppConst.channelIdReadAloud
@@ -77,6 +78,7 @@ class App : Application() {
         Coroutine.async {
         Coroutine.async {
             URL.setURLStreamHandlerFactory(ObsoleteUrlFactory(okHttpClient))
             URL.setURLStreamHandlerFactory(ObsoleteUrlFactory(okHttpClient))
             launch { installGmsTlsProvider(appCtx) }
             launch { installGmsTlsProvider(appCtx) }
+            RhinoScriptEngine
             //初始化封面
             //初始化封面
             BookCover.toString()
             BookCover.toString()
             //清除过期数据
             //清除过期数据

+ 3 - 2
app/src/main/java/io/legado/app/data/entities/DictRule.kt

@@ -5,6 +5,7 @@ import androidx.room.Entity
 import androidx.room.PrimaryKey
 import androidx.room.PrimaryKey
 import io.legado.app.model.analyzeRule.AnalyzeRule
 import io.legado.app.model.analyzeRule.AnalyzeRule
 import io.legado.app.model.analyzeRule.AnalyzeUrl
 import io.legado.app.model.analyzeRule.AnalyzeUrl
+import kotlin.coroutines.coroutineContext
 
 
 /**
 /**
  * 字典规则
  * 字典规则
@@ -36,12 +37,12 @@ data class DictRule(
      * 搜索字典
      * 搜索字典
      */
      */
     suspend fun search(word: String): String {
     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
         val body = analyzeUrl.getStrResponseAwait().body
         if (showRule.isBlank()) {
         if (showRule.isBlank()) {
             return body!!
             return body!!
         }
         }
-        val analyzeRule = AnalyzeRule()
+        val analyzeRule = AnalyzeRule().setCoroutineContext(coroutineContext)
         return analyzeRule.getString(showRule, mContent = body)
         return analyzeRule.getString(showRule, mContent = body)
     }
     }
 
 

+ 2 - 0
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 io.legado.app.utils.fromJsonObject
 import splitties.init.appCtx
 import splitties.init.appCtx
 import java.io.File
 import java.io.File
+import kotlin.coroutines.coroutineContext
 
 
 @Suppress("MemberVisibilityCanBePrivate")
 @Suppress("MemberVisibilityCanBePrivate")
 object DirectLinkUpload {
 object DirectLinkUpload {
@@ -60,6 +61,7 @@ object DirectLinkUpload {
             mFile.delete()
             mFile.delete()
         }
         }
         val analyzeRule = AnalyzeRule().setContent(res.body, res.url)
         val analyzeRule = AnalyzeRule().setContent(res.body, res.url)
+            .setCoroutineContext(coroutineContext)
         val downloadUrl = analyzeRule.getString(downloadUrlRule)
         val downloadUrl = analyzeRule.getString(downloadUrlRule)
         if (downloadUrl.isBlank()) {
         if (downloadUrl.isBlank()) {
             throw NoStackTraceException("上传失败,${res.body}")
             throw NoStackTraceException("上传失败,${res.body}")

+ 15 - 6
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.isContentScheme
 import io.legado.app.utils.onEachParallel
 import io.legado.app.utils.onEachParallel
 import io.legado.app.utils.postEvent
 import io.legado.app.utils.postEvent
+import io.legado.app.utils.runScriptWithContext
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.ensureActive
 import kotlinx.coroutines.ensureActive
@@ -232,12 +233,16 @@ object BookHelp {
             if (isImageExist(book, src)) {
             if (isImageExist(book, src)) {
                 return
                 return
             }
             }
-            val analyzeUrl = AnalyzeUrl(src, source = bookSource)
+            val analyzeUrl = AnalyzeUrl(
+                src, source = bookSource, coroutineContext = coroutineContext
+            )
             val bytes = analyzeUrl.getByteArrayAwait()
             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)) {
                 if (!checkImage(it)) {
                     // 如果部分图片失效,每次进入正文都会花很长时间再次获取图片数据
                     // 如果部分图片失效,每次进入正文都会花很长时间再次获取图片数据
                     // 所以无论如何都要将数据写入到文件里
                     // 所以无论如何都要将数据写入到文件里
@@ -546,12 +551,16 @@ object BookHelp {
     }
     }
 
 
     private val chapterNamePattern1 by lazy {
     private val chapterNamePattern1 by lazy {
-        Pattern.compile(".*?第([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+)[章节篇回集话]")
+        Pattern.compile(
+            ".*?第([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+)[章节篇回集话]"
+        )
     }
     }
 
 
     @Suppress("RegExpSimplifiable")
     @Suppress("RegExpSimplifiable")
     private val chapterNamePattern2 by lazy {
     private val chapterNamePattern2 by lazy {
-        Pattern.compile("^(?:[\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+[,:、])*([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+)(?:[,:、]|\\.[^\\d])")
+        Pattern.compile(
+            "^(?:[\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+[,:、])*([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+)(?:[,:、]|\\.[^\\d])"
+        )
     }
     }
 
 
     private val regexA by lazy {
     private val regexA by lazy {

+ 15 - 5
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.ReadManga
 import io.legado.app.model.analyzeRule.AnalyzeUrl
 import io.legado.app.model.analyzeRule.AnalyzeUrl
 import io.legado.app.utils.ImageUtils
 import io.legado.app.utils.ImageUtils
+import io.legado.app.utils.runScriptWithContext
+import kotlinx.coroutines.Job
 import java.io.InputStream
 import java.io.InputStream
 
 
 class LegadoDataUrlLoader : ModelLoader<String, InputStream> {
 class LegadoDataUrlLoader : ModelLoader<String, InputStream> {
@@ -33,15 +35,23 @@ class LegadoDataUrlLoader : ModelLoader<String, InputStream> {
     }
     }
 
 
     class LegadoDataUrlFetcher(private val model: String) : DataFetcher<InputStream> {
     class LegadoDataUrlFetcher(private val model: String) : DataFetcher<InputStream> {
+
+        private val coroutineContext = Job()
+
         override fun loadData(
         override fun loadData(
             priority: Priority,
             priority: Priority,
             callback: DataFetcher.DataCallback<in InputStream>
             callback: DataFetcher.DataCallback<in InputStream>
         ) {
         ) {
             try {
             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) {
                 if (decoded == null) {
                     throw NoStackTraceException("漫画图片解密失败")
                     throw NoStackTraceException("漫画图片解密失败")
                 }
                 }
@@ -56,7 +66,7 @@ class LegadoDataUrlLoader : ModelLoader<String, InputStream> {
         }
         }
 
 
         override fun cancel() {
         override fun cancel() {
-            // do nothing
+            coroutineContext.cancel()
         }
         }
 
 
         override fun getDataClass(): Class<InputStream> {
         override fun getDataClass(): Class<InputStream> {

+ 19 - 13
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.model.ReadManga
 import io.legado.app.utils.ImageUtils
 import io.legado.app.utils.ImageUtils
 import io.legado.app.utils.isWifiConnect
 import io.legado.app.utils.isWifiConnect
+import io.legado.app.utils.runScriptWithContext
+import kotlinx.coroutines.Job
 import okhttp3.Call
 import okhttp3.Call
 import okhttp3.Request
 import okhttp3.Request
 import okhttp3.Response
 import okhttp3.Response
@@ -38,6 +40,7 @@ class OkHttpStreamFetcher(
     private var callback: DataFetcher.DataCallback<in InputStream>? = null
     private var callback: DataFetcher.DataCallback<in InputStream>? = null
     private var source: BaseSource? = null
     private var source: BaseSource? = null
     private val manga = options.get(OkHttpModelLoader.mangaOption) == true
     private val manga = options.get(OkHttpModelLoader.mangaOption) == true
+    private val coroutineContext = Job()
 
 
     @Volatile
     @Volatile
     private var call: Call? = null
     private var call: Call? = null
@@ -89,6 +92,7 @@ class OkHttpStreamFetcher(
 
 
     override fun cancel() {
     override fun cancel() {
         call?.cancel()
         call?.cancel()
+        coroutineContext.cancel()
     }
     }
 
 
     override fun getDataClass(): Class<InputStream> {
     override fun getDataClass(): Class<InputStream> {
@@ -106,19 +110,21 @@ class OkHttpStreamFetcher(
     override fun onResponse(call: Call, response: Response) {
     override fun onResponse(call: Call, response: Response) {
         responseBody = response.body
         responseBody = response.body
         if (response.isSuccessful) {
         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) {
             if (decodeResult == null) {
                 callback?.onLoadFailed(NoStackTraceException("封面二次解密失败"))
                 callback?.onLoadFailed(NoStackTraceException("封面二次解密失败"))

+ 4 - 1
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.fromJsonArray
 import io.legado.app.utils.isJsonArray
 import io.legado.app.utils.isJsonArray
 import io.legado.app.utils.printOnDebug
 import io.legado.app.utils.printOnDebug
+import io.legado.app.utils.runScriptWithContext
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
 import kotlinx.coroutines.sync.withLock
@@ -61,7 +62,9 @@ suspend fun BookSource.exploreKinds(): List<ExploreKind> {
                         } else {
                         } else {
                             exploreUrl.substring(4, exploreUrl.lastIndexOf("<"))
                             exploreUrl.substring(4, exploreUrl.lastIndexOf("<"))
                         }
                         }
-                        ruleStr = evalJS(jsStr).toString().trim()
+                        ruleStr = runScriptWithContext {
+                            evalJS(jsStr).toString().trim()
+                        }
                         aCache.put(exploreKindsKey, ruleStr)
                         aCache.put(exploreKindsKey, ruleStr)
                     }
                     }
                 }
                 }

+ 4 - 1
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.ACache
 import io.legado.app.utils.MD5Utils
 import io.legado.app.utils.MD5Utils
 import io.legado.app.utils.NetworkUtils
 import io.legado.app.utils.NetworkUtils
+import io.legado.app.utils.runScriptWithContext
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.withContext
 import kotlinx.coroutines.withContext
 
 
@@ -29,7 +30,9 @@ suspend fun RssSource.sortUrls(): List<Pair<String, String>> {
                         } else {
                         } else {
                             sortUrl!!.substring(4, sortUrl!!.lastIndexOf("<"))
                             sortUrl!!.substring(4, sortUrl!!.lastIndexOf("<"))
                         }
                         }
-                        str = evalJS(jsStr).toString()
+                        str = runScriptWithContext {
+                            evalJS(jsStr).toString()
+                        }
                         aCache.put(sortUrlsKey, str)
                         aCache.put(sortUrlsKey, str)
                     }
                     }
                 }
                 }

+ 0 - 1
app/src/main/java/io/legado/app/help/source/SourceVerificationHelp.kt

@@ -84,7 +84,6 @@ object SourceVerificationHelp {
             putExtra("sourceName", source.getTag())
             putExtra("sourceName", source.getTag())
             putExtra("sourceVerificationEnable", saveResult)
             putExtra("sourceVerificationEnable", saveResult)
             putExtra("refetchAfterSuccess", refetchAfterSuccess)
             putExtra("refetchAfterSuccess", refetchAfterSuccess)
-            IntentData.put(url, source.getHeaderMap(true))
             IntentData.put(getVerificationResultKey(source), Thread.currentThread())
             IntentData.put(getVerificationResultKey(source), Thread.currentThread())
         }
         }
     }
     }

+ 4 - 1
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 io.legado.app.utils.getPrefString
 import splitties.init.appCtx
 import splitties.init.appCtx
 import java.io.File
 import java.io.File
+import kotlin.coroutines.coroutineContext
 
 
 @Keep
 @Keep
 object BookCover {
 object BookCover {
@@ -174,10 +175,12 @@ object BookCover {
             config.searchUrl,
             config.searchUrl,
             book.name,
             book.name,
             source = config,
             source = config,
-            headerMapF = config.getHeaderMap()
+            coroutineContext = coroutineContext,
+            hasLoginHeader = false
         )
         )
         val res = analyzeUrl.getStrResponseAwait()
         val res = analyzeUrl.getStrResponseAwait()
         val analyzeRule = AnalyzeRule(book)
         val analyzeRule = AnalyzeRule(book)
+        analyzeRule.setCoroutineContext(coroutineContext)
         analyzeRule.setContent(res.body)
         analyzeRule.setContent(res.body)
         analyzeRule.setRedirectUrl(res.url)
         analyzeRule.setRedirectUrl(res.url)
         return analyzeRule.getString(config.coverRule, isUrl = true)
         return analyzeRule.getString(config.coverRule, isUrl = true)

+ 5 - 1
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.isJsonArray
 import io.legado.app.utils.isJsonObject
 import io.legado.app.utils.isJsonObject
 import io.legado.app.utils.isXml
 import io.legado.app.utils.isXml
+import io.legado.app.utils.runScriptWithContext
 import io.legado.app.utils.splitNotBlank
 import io.legado.app.utils.splitNotBlank
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.runBlocking
 import okhttp3.MediaType.Companion.toMediaType
 import okhttp3.MediaType.Companion.toMediaType
@@ -81,6 +82,7 @@ class AnalyzeUrl(
     private val readTimeout: Long? = null,
     private val readTimeout: Long? = null,
     private var coroutineContext: CoroutineContext = EmptyCoroutineContext,
     private var coroutineContext: CoroutineContext = EmptyCoroutineContext,
     headerMapF: Map<String, String>? = null,
     headerMapF: Map<String, String>? = null,
+    hasLoginHeader: Boolean = true
 ) : JsExtensions {
 ) : JsExtensions {
     companion object {
     companion object {
         val paramPattern: Pattern = Pattern.compile("\\s*,\\s*(?=\\{)")
         val paramPattern: Pattern = Pattern.compile("\\s*,\\s*(?=\\{)")
@@ -118,7 +120,9 @@ class AnalyzeUrl(
         coroutineContext = coroutineContext.minusKey(ContinuationInterceptor)
         coroutineContext = coroutineContext.minusKey(ContinuationInterceptor)
         val urlMatcher = paramPattern.matcher(baseUrl)
         val urlMatcher = paramPattern.matcher(baseUrl)
         if (urlMatcher.find()) baseUrl = baseUrl.substring(0, urlMatcher.start())
         if (urlMatcher.find()) baseUrl = baseUrl.substring(0, urlMatcher.start())
-        (headerMapF ?: source?.getHeaderMap(true))?.let {
+        (headerMapF ?: runScriptWithContext(coroutineContext) {
+            source?.getHeaderMap(hasLoginHeader)
+        })?.let {
             headerMap.putAll(it)
             headerMap.putAll(it)
             if (it.containsKey("proxy")) {
             if (it.containsKey("proxy")) {
                 proxy = it["proxy"]
                 proxy = it["proxy"]

+ 6 - 2
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.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.Dispatchers
 import kotlin.coroutines.CoroutineContext
 import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.coroutineContext
 
 
 @Suppress("MemberVisibilityCanBePrivate")
 @Suppress("MemberVisibilityCanBePrivate")
 object Rss {
 object Rss {
@@ -41,7 +42,8 @@ object Rss {
             page = page,
             page = page,
             source = rssSource,
             source = rssSource,
             ruleData = ruleData,
             ruleData = ruleData,
-            headerMapF = rssSource.getHeaderMap()
+            coroutineContext = coroutineContext,
+            hasLoginHeader = false
         )
         )
         val res = analyzeUrl.getStrResponseAwait()
         val res = analyzeUrl.getStrResponseAwait()
         checkRedirect(rssSource, res)
         checkRedirect(rssSource, res)
@@ -70,7 +72,8 @@ object Rss {
             baseUrl = rssArticle.origin,
             baseUrl = rssArticle.origin,
             source = rssSource,
             source = rssSource,
             ruleData = rssArticle,
             ruleData = rssArticle,
-            headerMapF = rssSource.getHeaderMap()
+            coroutineContext = coroutineContext,
+            hasLoginHeader = false
         )
         )
         val res = analyzeUrl.getStrResponseAwait()
         val res = analyzeUrl.getStrResponseAwait()
         checkRedirect(rssSource, res)
         checkRedirect(rssSource, res)
@@ -79,6 +82,7 @@ object Rss {
         val analyzeRule = AnalyzeRule(rssArticle, rssSource)
         val analyzeRule = AnalyzeRule(rssArticle, rssSource)
         analyzeRule.setContent(res.body)
         analyzeRule.setContent(res.body)
             .setBaseUrl(NetworkUtils.getAbsoluteURL(rssArticle.origin, rssArticle.link))
             .setBaseUrl(NetworkUtils.getAbsoluteURL(rssArticle.origin, rssArticle.link))
+            .setCoroutineContext(coroutineContext)
             .setRedirectUrl(res.url)
             .setRedirectUrl(res.url)
         return analyzeRule.getString(ruleContent)
         return analyzeRule.getString(ruleContent)
     }
     }

+ 3 - 1
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 io.legado.app.utils.NetworkUtils
 import splitties.init.appCtx
 import splitties.init.appCtx
 import java.util.Locale
 import java.util.Locale
+import kotlin.coroutines.coroutineContext
 
 
 @Keep
 @Keep
 object RssParserByRule {
 object RssParserByRule {
 
 
     @Throws(Exception::class)
     @Throws(Exception::class)
-    fun parseXML(
+    suspend fun parseXML(
         sortName: String,
         sortName: String,
         sortUrl: String,
         sortUrl: String,
         redirectUrl: String,
         redirectUrl: String,
@@ -40,6 +41,7 @@ object RssParserByRule {
         } else {
         } else {
             val articleList = mutableListOf<RssArticle>()
             val articleList = mutableListOf<RssArticle>()
             val analyzeRule = AnalyzeRule(ruleData, rssSource)
             val analyzeRule = AnalyzeRule(ruleData, rssSource)
+            analyzeRule.setCoroutineContext(coroutineContext)
             analyzeRule.setContent(body).setBaseUrl(sortUrl)
             analyzeRule.setContent(body).setBaseUrl(sortUrl)
             analyzeRule.setRedirectUrl(redirectUrl)
             analyzeRule.setRedirectUrl(redirectUrl)
             var reverse = false
             var reverse = false

+ 0 - 2
app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt

@@ -70,7 +70,6 @@ object BookChapterList {
                         mUrl = nextUrl,
                         mUrl = nextUrl,
                         source = bookSource,
                         source = bookSource,
                         ruleData = book,
                         ruleData = book,
-                        headerMapF = bookSource.getHeaderMap(),
                         coroutineContext = coroutineContext
                         coroutineContext = coroutineContext
                     )
                     )
                     val res = analyzeUrl.getStrResponseAwait() //控制并发访问
                     val res = analyzeUrl.getStrResponseAwait() //控制并发访问
@@ -100,7 +99,6 @@ object BookChapterList {
                         mUrl = urlStr,
                         mUrl = urlStr,
                         source = bookSource,
                         source = bookSource,
                         ruleData = book,
                         ruleData = book,
-                        headerMapF = bookSource.getHeaderMap(),
                         coroutineContext = coroutineContext
                         coroutineContext = coroutineContext
                     )
                     )
                     val res = analyzeUrl.getStrResponseAwait() //控制并发访问
                     val res = analyzeUrl.getStrResponseAwait() //控制并发访问

+ 0 - 2
app/src/main/java/io/legado/app/model/webBook/BookContent.kt

@@ -90,7 +90,6 @@ object BookContent {
                     mUrl = nextUrl,
                     mUrl = nextUrl,
                     source = bookSource,
                     source = bookSource,
                     ruleData = book,
                     ruleData = book,
-                    headerMapF = bookSource.getHeaderMap(),
                     coroutineContext = coroutineContext
                     coroutineContext = coroutineContext
                 )
                 )
                 val res = analyzeUrl.getStrResponseAwait() //控制并发访问
                 val res = analyzeUrl.getStrResponseAwait() //控制并发访问
@@ -118,7 +117,6 @@ object BookContent {
                     mUrl = urlStr,
                     mUrl = urlStr,
                     source = bookSource,
                     source = bookSource,
                     ruleData = book,
                     ruleData = book,
-                    headerMapF = bookSource.getHeaderMap(),
                     coroutineContext = coroutineContext
                     coroutineContext = coroutineContext
                 )
                 )
                 val res = analyzeUrl.getStrResponseAwait() //控制并发访问
                 val res = analyzeUrl.getStrResponseAwait() //控制并发访问

+ 0 - 5
app/src/main/java/io/legado/app/model/webBook/WebBook.kt

@@ -62,7 +62,6 @@ object WebBook {
             key = key,
             key = key,
             page = page,
             page = page,
             baseUrl = bookSource.bookSourceUrl,
             baseUrl = bookSource.bookSourceUrl,
-            headerMapF = bookSource.getHeaderMap(true),
             source = bookSource,
             source = bookSource,
             ruleData = ruleData,
             ruleData = ruleData,
             coroutineContext = coroutineContext
             coroutineContext = coroutineContext
@@ -115,7 +114,6 @@ object WebBook {
             baseUrl = bookSource.bookSourceUrl,
             baseUrl = bookSource.bookSourceUrl,
             source = bookSource,
             source = bookSource,
             ruleData = ruleData,
             ruleData = ruleData,
-            headerMapF = bookSource.getHeaderMap(true),
             coroutineContext = coroutineContext
             coroutineContext = coroutineContext
         )
         )
         var res = analyzeUrl.getStrResponseAwait()
         var res = analyzeUrl.getStrResponseAwait()
@@ -173,7 +171,6 @@ object WebBook {
                 baseUrl = bookSource.bookSourceUrl,
                 baseUrl = bookSource.bookSourceUrl,
                 source = bookSource,
                 source = bookSource,
                 ruleData = book,
                 ruleData = book,
-                headerMapF = bookSource.getHeaderMap(true),
                 coroutineContext = coroutineContext
                 coroutineContext = coroutineContext
             )
             )
             var res = analyzeUrl.getStrResponseAwait()
             var res = analyzeUrl.getStrResponseAwait()
@@ -249,7 +246,6 @@ object WebBook {
                     baseUrl = book.bookUrl,
                     baseUrl = book.bookUrl,
                     source = bookSource,
                     source = bookSource,
                     ruleData = book,
                     ruleData = book,
-                    headerMapF = bookSource.getHeaderMap(true),
                     coroutineContext = coroutineContext
                     coroutineContext = coroutineContext
                 )
                 )
                 var res = analyzeUrl.getStrResponseAwait()
                 var res = analyzeUrl.getStrResponseAwait()
@@ -328,7 +324,6 @@ object WebBook {
                 source = bookSource,
                 source = bookSource,
                 ruleData = book,
                 ruleData = book,
                 chapter = bookChapter,
                 chapter = bookChapter,
-                headerMapF = bookSource.getHeaderMap(true),
                 coroutineContext = coroutineContext
                 coroutineContext = coroutineContext
             )
             )
             var res = analyzeUrl.getStrResponseAwait(
             var res = analyzeUrl.getStrResponseAwait(

+ 1 - 0
app/src/main/java/io/legado/app/service/AudioPlayService.kt

@@ -225,6 +225,7 @@ class AudioPlayService : BaseService(),
                 source = AudioPlay.bookSource,
                 source = AudioPlay.bookSource,
                 ruleData = AudioPlay.book,
                 ruleData = AudioPlay.book,
                 chapter = AudioPlay.durChapter,
                 chapter = AudioPlay.durChapter,
+                coroutineContext = coroutineContext
             )
             )
             exoPlayer.setMediaItem(analyzeUrl.getMediaItem())
             exoPlayer.setMediaItem(analyzeUrl.getMediaItem())
             exoPlayer.playWhenReady = true
             exoPlayer.playWhenReady = true

+ 0 - 1
app/src/main/java/io/legado/app/service/HttpReadAloudService.kt

@@ -328,7 +328,6 @@ class HttpReadAloudService : BaseReadAloudService(),
                     speakText = speakText,
                     speakText = speakText,
                     speakSpeed = speechRate,
                     speakSpeed = speechRate,
                     source = httpTts,
                     source = httpTts,
-                    headerMapF = httpTts.getHeaderMap(true),
                     readTimeout = 300 * 1000L,
                     readTimeout = 300 * 1000L,
                     coroutineContext = coroutineContext
                     coroutineContext = coroutineContext
                 )
                 )

+ 4 - 1
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
             val fileNameNoExtension = if (book.author.isBlank()) book.name
             else "${book.name} 作者:${book.author}"
             else "${book.name} 作者:${book.author}"
             book.downloadUrls!!.map {
             book.downloadUrls!!.map {
-                val analyzeUrl = AnalyzeUrl(it, source = bookSource)
+                val analyzeUrl = AnalyzeUrl(
+                    it, source = bookSource,
+                    coroutineContext = coroutineContext
+                )
                 val mFileName = UrlUtil.getFileName(analyzeUrl)
                 val mFileName = UrlUtil.getFileName(analyzeUrl)
                     ?: "${fileNameNoExtension}.${analyzeUrl.type}"
                     ?: "${fileNameNoExtension}.${analyzeUrl.type}"
                 WebFile(it, mFileName)
                 WebFile(it, mFileName)

+ 4 - 2
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 androidx.core.view.isVisible
 import io.legado.app.R
 import io.legado.app.R
 import io.legado.app.databinding.ViewMangaMenuBinding
 import io.legado.app.databinding.ViewMangaMenuBinding
-import io.legado.app.help.IntentData
 import io.legado.app.help.config.AppConfig
 import io.legado.app.help.config.AppConfig
 import io.legado.app.lib.dialogs.alert
 import io.legado.app.lib.dialogs.alert
 import io.legado.app.lib.theme.bottomBackground
 import io.legado.app.lib.theme.bottomBackground
+import io.legado.app.model.ReadBook
 import io.legado.app.model.ReadManga
 import io.legado.app.model.ReadManga
 import io.legado.app.ui.browser.WebViewActivity
 import io.legado.app.ui.browser.WebViewActivity
 import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
 import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
@@ -176,9 +176,11 @@ class MangaMenu @JvmOverloads constructor(
             } else {
             } else {
                 context.startActivity<WebViewActivity> {
                 context.startActivity<WebViewActivity> {
                     val url = tvChapterUrl.text.toString()
                     val url = tvChapterUrl.text.toString()
+                    val bookSource = ReadBook.bookSource
                     putExtra("title", tvChapterName.text)
                     putExtra("title", tvChapterName.text)
                     putExtra("url", url)
                     putExtra("url", url)
-                    IntentData.put(url, ReadManga.bookSource?.getHeaderMap(true))
+                    putExtra("sourceOrigin", bookSource?.bookSourceUrl)
+                    putExtra("sourceName", bookSource?.bookSourceName)
                 }
                 }
             }
             }
         }
         }

+ 3 - 2
app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt

@@ -1281,7 +1281,7 @@ class ReadBookActivity : BaseReadBookActivity(),
         alert(R.string.chapter_pay) {
         alert(R.string.chapter_pay) {
             setMessage(chapter.title)
             setMessage(chapter.title)
             yesButton {
             yesButton {
-                Coroutine.async {
+                Coroutine.async(lifecycleScope) {
                     val source =
                     val source =
                         ReadBook.bookSource ?: throw NoStackTraceException("no book source")
                         ReadBook.bookSource ?: throw NoStackTraceException("no book source")
                     val payAction = source.getContentRule().payAction
                     val payAction = source.getContentRule().payAction
@@ -1289,6 +1289,7 @@ class ReadBookActivity : BaseReadBookActivity(),
                         throw NoStackTraceException("no pay action")
                         throw NoStackTraceException("no pay action")
                     }
                     }
                     val analyzeRule = AnalyzeRule(book, source)
                     val analyzeRule = AnalyzeRule(book, source)
+                    analyzeRule.setCoroutineContext(coroutineContext)
                     analyzeRule.setBaseUrl(chapter.url)
                     analyzeRule.setBaseUrl(chapter.url)
                     analyzeRule.chapter = chapter
                     analyzeRule.chapter = chapter
                     analyzeRule.evalJS(payAction).toString()
                     analyzeRule.evalJS(payAction).toString()
@@ -1297,7 +1298,7 @@ class ReadBookActivity : BaseReadBookActivity(),
                         startActivity<WebViewActivity> {
                         startActivity<WebViewActivity> {
                             putExtra("title", getString(R.string.chapter_pay))
                             putExtra("title", getString(R.string.chapter_pay))
                             putExtra("url", it)
                             putExtra("url", it)
-                            IntentData.put(it, ReadBook.bookSource?.getHeaderMap(true))
+                            putExtra("sourceOrigin", ReadBook.bookSource?.bookSourceUrl)
                         }
                         }
                     } else if (it.isTrue()) {
                     } else if (it.isTrue()) {
                         //购买成功后刷新目录
                         //购买成功后刷新目录

+ 3 - 2
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.R
 import io.legado.app.constant.PreferKey
 import io.legado.app.constant.PreferKey
 import io.legado.app.databinding.ViewReadMenuBinding
 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.AppConfig
 import io.legado.app.help.config.LocalConfig
 import io.legado.app.help.config.LocalConfig
 import io.legado.app.help.config.ReadBookConfig
 import io.legado.app.help.config.ReadBookConfig
@@ -350,9 +349,11 @@ class ReadMenu @JvmOverloads constructor(
                 Coroutine.async {
                 Coroutine.async {
                     context.startActivity<WebViewActivity> {
                     context.startActivity<WebViewActivity> {
                         val url = tvChapterUrl.text.toString()
                         val url = tvChapterUrl.text.toString()
+                        val bookSource = ReadBook.bookSource
                         putExtra("title", tvChapterName.text)
                         putExtra("title", tvChapterName.text)
                         putExtra("url", url)
                         putExtra("url", url)
-                        IntentData.put(url, ReadBook.bookSource?.getHeaderMap(true))
+                        putExtra("sourceOrigin", bookSource?.bookSourceUrl)
+                        putExtra("sourceName", bookSource?.bookSourceName)
                     }
                     }
                 }
                 }
             }
             }

+ 4 - 4
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.constant.AppConst
 import io.legado.app.data.appDb
 import io.legado.app.data.appDb
 import io.legado.app.exception.NoStackTraceException
 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.newCallResponseBody
 import io.legado.app.help.http.okHttpClient
 import io.legado.app.help.http.okHttpClient
 import io.legado.app.help.source.SourceVerificationHelp
 import io.legado.app.help.source.SourceVerificationHelp
@@ -48,8 +47,8 @@ class WebViewModel(application: Application) : BaseViewModel(application) {
             sourceOrigin = intent.getStringExtra("sourceOrigin") ?: ""
             sourceOrigin = intent.getStringExtra("sourceOrigin") ?: ""
             sourceVerificationEnable = intent.getBooleanExtra("sourceVerificationEnable", false)
             sourceVerificationEnable = intent.getBooleanExtra("sourceVerificationEnable", false)
             refetchAfterSuccess = intent.getBooleanExtra("refetchAfterSuccess", true)
             refetchAfterSuccess = intent.getBooleanExtra("refetchAfterSuccess", true)
-            val headerMapF = IntentData.get<Map<String, String>>(url)
-            val analyzeUrl = AnalyzeUrl(url, headerMapF = headerMapF)
+            val source = appDb.bookSourceDao.getBookSource(sourceOrigin)
+            val analyzeUrl = AnalyzeUrl(url, source = source, coroutineContext = coroutineContext)
             baseUrl = analyzeUrl.url
             baseUrl = analyzeUrl.url
             headerMap.putAll(analyzeUrl.headerMap)
             headerMap.putAll(analyzeUrl.headerMap)
             if (analyzeUrl.isPost()) {
             if (analyzeUrl.isPost()) {
@@ -107,7 +106,8 @@ class WebViewModel(application: Application) : BaseViewModel(application) {
                 html = AnalyzeUrl(
                 html = AnalyzeUrl(
                     url,
                     url,
                     headerMapF = headerMap,
                     headerMapF = headerMap,
-                    source = source
+                    source = source,
+                    coroutineContext = coroutineContext
                 ).getStrResponseAwait(useWebView = false).body
                 ).getStrResponseAwait(useWebView = false).body
                 SourceVerificationHelp.setResult(sourceOrigin, html ?: "")
                 SourceVerificationHelp.setResult(sourceOrigin, html ?: "")
             }.onSuccess {
             }.onSuccess {

+ 10 - 6
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.DialogLoginBinding
 import io.legado.app.databinding.ItemFilletTextBinding
 import io.legado.app.databinding.ItemFilletTextBinding
 import io.legado.app.databinding.ItemSourceEditBinding
 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.dialogs.alert
 import io.legado.app.lib.theme.primaryColor
 import io.legado.app.lib.theme.primaryColor
 import io.legado.app.ui.about.AppLogDialog
 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.isAbsUrl
 import io.legado.app.utils.openUrl
 import io.legado.app.utils.openUrl
 import io.legado.app.utils.printOnDebug
 import io.legado.app.utils.printOnDebug
+import io.legado.app.utils.runScriptWithContext
 import io.legado.app.utils.setLayout
 import io.legado.app.utils.setLayout
 import io.legado.app.utils.showDialogFragment
 import io.legado.app.utils.showDialogFragment
 import io.legado.app.utils.toastOnUi
 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<RowUi>) {
     private fun handleButtonClick(source: BaseSource, rowUi: RowUi, loginUi: List<RowUi>) {
-        Coroutine.async {
+        lifecycleScope.launch(IO) {
             if (rowUi.action.isAbsUrl()) {
             if (rowUi.action.isAbsUrl()) {
                 context?.openUrl(rowUi.action!!)
                 context?.openUrl(rowUi.action!!)
             } else if (rowUi.action != null) {
             } else if (rowUi.action != null) {
                 // JavaScript
                 // JavaScript
                 val buttonFunctionJS = rowUi.action!!
                 val buttonFunctionJS = rowUi.action!!
-                val loginJS = source.getLoginJs() ?: return@async
+                val loginJS = source.getLoginJs() ?: return@launch
                 kotlin.runCatching {
                 kotlin.runCatching {
-                    source.evalJS("$loginJS\n$buttonFunctionJS") {
-                        put("result", getLoginData(loginUi))
+                    runScriptWithContext {
+                        source.evalJS("$loginJS\n$buttonFunctionJS") {
+                            put("result", getLoginData(loginUi))
+                        }
                     }
                     }
                 }.onFailure { e ->
                 }.onFailure { e ->
                     AppLog.put("LoginUI Button ${rowUi.name} JavaScript error", 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))) {
             } else if (source.putLoginInfo(GSON.toJson(loginData))) {
                 try {
                 try {
-                    source.login()
+                    runScriptWithContext {
+                        source.login()
+                    }
                     context?.toastOnUi(R.string.success)
                     context?.toastOnUi(R.string.success)
                     withContext(Main) {
                     withContext(Main) {
                         dismiss()
                         dismiss()

+ 5 - 0
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.appDb
 import io.legado.app.data.entities.BaseSource
 import io.legado.app.data.entities.BaseSource
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.exception.NoStackTraceException
+import io.legado.app.utils.runScriptWithContext
 import io.legado.app.utils.toastOnUi
 import io.legado.app.utils.toastOnUi
 
 
 class SourceLoginViewModel(application: Application) : BaseViewModel(application) {
 class SourceLoginViewModel(application: Application) : BaseViewModel(application) {
 
 
     var source: BaseSource? = null
     var source: BaseSource? = null
+    var headerMap: Map<String, String> = emptyMap()
 
 
     fun initData(intent: Intent, success: (bookSource: BaseSource) -> Unit) {
     fun initData(intent: Intent, success: (bookSource: BaseSource) -> Unit) {
         execute {
         execute {
@@ -21,6 +23,9 @@ class SourceLoginViewModel(application: Application) : BaseViewModel(application
                 "rssSource" -> source = appDb.rssSourceDao.getByKey(sourceKey)
                 "rssSource" -> source = appDb.rssSourceDao.getByKey(sourceKey)
                 "httpTts" -> source = appDb.httpTTSDao.get(sourceKey.toLong())
                 "httpTts" -> source = appDb.httpTTSDao.get(sourceKey.toLong())
             }
             }
+            headerMap = runScriptWithContext {
+                source?.getHeaderMap(true) ?: emptyMap()
+            }
             source
             source
         }.onSuccess {
         }.onSuccess {
             if (it != null) {
             if (it != null) {

+ 13 - 9
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.WebView
 import android.webkit.WebViewClient
 import android.webkit.WebViewClient
 import androidx.fragment.app.activityViewModels
 import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
 import io.legado.app.R
 import io.legado.app.base.BaseFragment
 import io.legado.app.base.BaseFragment
 import io.legado.app.constant.AppConst
 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.openUrl
 import io.legado.app.utils.snackbar
 import io.legado.app.utils.snackbar
 import io.legado.app.utils.viewbindingdelegate.viewBinding
 import io.legado.app.utils.viewbindingdelegate.viewBinding
+import kotlinx.coroutines.launch
 
 
 class WebViewLoginFragment : BaseFragment(R.layout.fragment_web_view_login) {
 class WebViewLoginFragment : BaseFragment(R.layout.fragment_web_view_login) {
 
 
@@ -55,11 +57,8 @@ class WebViewLoginFragment : BaseFragment(R.layout.fragment_web_view_login) {
                 if (!checking) {
                 if (!checking) {
                     checking = true
                     checking = true
                     binding.titleBar.snackbar(R.string.check_host_cookie)
                     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
             builtInZoomControls = true
             javaScriptEnabled = true
             javaScriptEnabled = true
             displayZoomControls = false
             displayZoomControls = false
-            source.getHeaderMap()[AppConst.UA_NAME]?.let {
+            viewModel.headerMap[AppConst.UA_NAME]?.let {
                 userAgentString = it
                 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)
         }
         }
     }
     }
 
 

+ 4 - 1
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.base.BaseViewModel
 import io.legado.app.data.appDb
 import io.legado.app.data.appDb
 import io.legado.app.data.entities.RssSource
 import io.legado.app.data.entities.RssSource
+import io.legado.app.utils.runScriptWithContext
 import io.legado.app.utils.toastOnUi
 import io.legado.app.utils.toastOnUi
 
 
 class RssViewModel(application: Application) : BaseViewModel(application) {
 class RssViewModel(application: Application) : BaseViewModel(application) {
@@ -58,7 +59,9 @@ class RssViewModel(application: Application) : BaseViewModel(application) {
                     } else {
                     } else {
                         sortUrl.substring(4, sortUrl.lastIndexOf("<"))
                         sortUrl.substring(4, sortUrl.lastIndexOf("<"))
                     }
                     }
-                    val result = rssSource.evalJS(jsStr)?.toString()
+                    val result = runScriptWithContext {
+                        rssSource.evalJS(jsStr)?.toString()
+                    }
                     if (!result.isNullOrBlank()) {
                     if (!result.isNullOrBlank()) {
                         sortUrl = result
                         sortUrl = result
                     }
                     }

+ 2 - 4
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.ui.rss.favorites.RssFavoritesDialog
 import io.legado.app.utils.ACache
 import io.legado.app.utils.ACache
 import io.legado.app.utils.NetworkUtils
 import io.legado.app.utils.NetworkUtils
-import io.legado.app.utils.get
 import io.legado.app.utils.gone
 import io.legado.app.utils.gone
 import io.legado.app.utils.invisible
 import io.legado.app.utils.invisible
 import io.legado.app.utils.isTrue
 import io.legado.app.utils.isTrue
@@ -187,7 +186,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
     }
     }
 
 
     override fun updateFavorite(title: String?, group: String?) {
     override fun updateFavorite(title: String?, group: String?) {
-        viewModel.rssArticle?.let{
+        viewModel.rssArticle?.let {
             if (title != null) {
             if (title != null) {
                 it.title = title
                 it.title = title
             }
             }
@@ -294,8 +293,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
                 val url = NetworkUtils.getAbsoluteURL(it.origin, it.link)
                 val url = NetworkUtils.getAbsoluteURL(it.origin, it.link)
                 val html = viewModel.clHtml(content)
                 val html = viewModel.clHtml(content)
                 binding.webView.settings.userAgentString =
                 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) {
                 if (viewModel.rssSource?.loadWithBaseUrl == true) {
                     binding.webView
                     binding.webView
                         .loadDataWithBaseURL(url, html, "text/html", "utf-8", url)//不想用baseUrl进else
                         .loadDataWithBaseURL(url, html, "text/html", "utf-8", url)//不想用baseUrl进else

+ 10 - 2
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.help.http.okHttpClient
 import io.legado.app.model.analyzeRule.AnalyzeUrl
 import io.legado.app.model.analyzeRule.AnalyzeUrl
 import io.legado.app.model.rss.Rss
 import io.legado.app.model.rss.Rss
+import io.legado.app.utils.runScriptWithContext
 import io.legado.app.utils.toastOnUi
 import io.legado.app.utils.toastOnUi
 import io.legado.app.utils.writeBytes
 import io.legado.app.utils.writeBytes
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.Dispatchers.IO
 import splitties.init.appCtx
 import splitties.init.appCtx
 import java.util.Date
 import java.util.Date
+import kotlin.coroutines.coroutineContext
 
 
 
 
 class ReadRssViewModel(application: Application) : BaseViewModel(application), JsExtensions {
 class ReadRssViewModel(application: Application) : BaseViewModel(application), JsExtensions {
@@ -37,6 +39,7 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application), J
     var rssStar: RssStar? = null
     var rssStar: RssStar? = null
     val upTtsMenuData = MutableLiveData<Boolean>()
     val upTtsMenuData = MutableLiveData<Boolean>()
     val upStarMenuData = MutableLiveData<Boolean>()
     val upStarMenuData = MutableLiveData<Boolean>()
+    var headerMap: Map<String, String> = emptyMap()
 
 
     override fun getSource(): BaseSource? {
     override fun getSource(): BaseSource? {
         return rssSource
         return rssSource
@@ -47,6 +50,9 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application), J
             val origin = intent.getStringExtra("origin") ?: return@execute
             val origin = intent.getStringExtra("origin") ?: return@execute
             val link = intent.getStringExtra("link")
             val link = intent.getStringExtra("link")
             rssSource = appDb.rssSourceDao.getByKey(origin)
             rssSource = appDb.rssSourceDao.getByKey(origin)
+            headerMap = runScriptWithContext {
+                rssSource?.getHeaderMap() ?: emptyMap()
+            }
             if (link != null) {
             if (link != null) {
                 rssStar = appDb.rssStarDao.get(origin, link)
                 rssStar = appDb.rssStarDao.get(origin, link)
                 rssArticle = rssStar?.toRssArticle() ?: appDb.rssArticleDao.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(
         val analyzeUrl = AnalyzeUrl(
             mUrl = url,
             mUrl = url,
             baseUrl = baseUrl,
             baseUrl = baseUrl,
-            headerMapF = rssSource?.getHeaderMap()
+            source = rssSource,
+            coroutineContext = coroutineContext,
+            hasLoginHeader = false
         )
         )
         urlLiveData.postValue(analyzeUrl)
         urlLiveData.postValue(analyzeUrl)
     }
     }

+ 30 - 0
modules/rhino/src/main/java/com/script/rhino/RhinoExtensions.kt

@@ -1,5 +1,7 @@
 package io.legado.app.utils
 package io.legado.app.utils
 
 
+import com.script.rhino.RhinoContext
+import com.script.rhino.RhinoScriptEngine
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.supervisorScope
 import kotlinx.coroutines.supervisorScope
@@ -7,6 +9,9 @@ import org.mozilla.javascript.Context
 import kotlin.contracts.ExperimentalContracts
 import kotlin.contracts.ExperimentalContracts
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
 import kotlin.contracts.contract
+import kotlin.coroutines.ContinuationInterceptor
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.coroutineContext
 
 
 @Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND")
 @Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND")
 @OptIn(ExperimentalContracts::class)
 @OptIn(ExperimentalContracts::class)
@@ -29,3 +34,28 @@ inline fun <T> suspendContinuation(crossinline block: suspend CoroutineScope.()
         Context.exit()
         Context.exit()
     }
     }
 }
 }
+
+inline fun <T> 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 <T> 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()
+    }
+}

+ 3 - 1
modules/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt

@@ -93,7 +93,9 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
     ): Any? {
     ): Any? {
         val cx = Context.enter() as RhinoContext
         val cx = Context.enter() as RhinoContext
         val previousCoroutineContext = cx.coroutineContext
         val previousCoroutineContext = cx.coroutineContext
-        cx.coroutineContext = coroutineContext
+        if (coroutineContext != null) {
+            cx.coroutineContext = coroutineContext
+        }
         cx.allowScriptRun = true
         cx.allowScriptRun = true
         val ret: Any?
         val ret: Any?
         try {
         try {