kunfei 4 лет назад
Родитель
Сommit
c957bbdfbe

+ 2 - 2
app/src/main/java/io/legado/app/api/controller/BookController.kt

@@ -110,9 +110,9 @@ object BookController {
                     ?: return returnData.setErrorMsg("未找到对应书源,请换源")
                 val toc = runBlocking {
                     if (book.tocUrl.isBlank()) {
-                        WebBook.getBookInfoAwait(this, bookSource, book)
+                        WebBook.getBookInfoAwait(bookSource, book)
                     }
-                    WebBook.getChapterListAwait(this, bookSource, book).getOrThrow()
+                    WebBook.getChapterListAwait(bookSource, book).getOrThrow()
                 }
                 appDb.bookChapterDao.delByBook(book.bookUrl)
                 appDb.bookChapterDao.insert(*toc.toTypedArray())

+ 5 - 5
app/src/main/java/io/legado/app/help/BookHelp.kt

@@ -68,14 +68,13 @@ object BookHelp {
     }
 
     suspend fun saveContent(
-        scope: CoroutineScope,
         bookSource: BookSource,
         book: Book,
         bookChapter: BookChapter,
         content: String
     ) {
         saveText(book, bookChapter, content)
-        saveImages(scope, bookSource, book, bookChapter, content)
+        saveImages(bookSource, book, bookChapter, content)
         postEvent(EventBus.SAVE_CONTENT, bookChapter)
     }
 
@@ -95,7 +94,6 @@ object BookHelp {
     }
 
     private suspend fun saveImages(
-        scope: CoroutineScope,
         bookSource: BookSource,
         book: Book,
         bookChapter: BookChapter,
@@ -107,8 +105,10 @@ object BookHelp {
             if (matcher.find()) {
                 matcher.group(1)?.let { src ->
                     val mSrc = NetworkUtils.getAbsoluteURL(bookChapter.url, src)
-                    awaitList.add(scope.async {
-                        saveImage(bookSource, book, mSrc)
+                    awaitList.add(coroutineScope {
+                        async {
+                            saveImage(bookSource, book, mSrc)
+                        }
                     })
                 }
             }

+ 1 - 1
app/src/main/java/io/legado/app/model/CacheBook.kt

@@ -179,7 +179,7 @@ object CacheBook {
             val chapterCount = appDb.bookChapterDao.getChapterCount(book.bookUrl)
             if (chapterCount == 0) {
                 runBlocking {
-                    WebBook.getChapterListAwait(this, bookSource, book)
+                    WebBook.getChapterListAwait(bookSource, book)
                         .onFailure {
                             AppLog.put("缓存书籍没有目录且加载目录失败\n${it.localizedMessage}", it)
                             appCtx.toastOnUi("缓存书籍没有目录且加载目录失败\n${it.localizedMessage}")

+ 3 - 3
app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt

@@ -700,7 +700,7 @@ class AnalyzeRule(
                             book.putVariable(entry.key, entry.value)
                         }
                     }
-                WebBook.getBookInfoAwait(this, bookSource, book, false)
+                WebBook.getBookInfoAwait(bookSource, book, false)
             }
         }
     }
@@ -714,7 +714,7 @@ class AnalyzeRule(
         if (bookSource == null || book == null) return
         runBlocking {
             withTimeout(1800000) {
-                WebBook.getBookInfoAwait(this, bookSource, book)
+                WebBook.getBookInfoAwait(bookSource, book)
             }
         }
     }
@@ -728,7 +728,7 @@ class AnalyzeRule(
         if (bookSource == null || book == null) return
         runBlocking {
             withTimeout(1800000) {
-                WebBook.getBookInfoAwait(this, bookSource, book)
+                WebBook.getBookInfoAwait(bookSource, book)
             }
         }
     }

+ 10 - 12
app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt

@@ -13,12 +13,12 @@ import io.legado.app.model.Debug
 import io.legado.app.model.analyzeRule.AnalyzeRule
 import io.legado.app.model.analyzeRule.AnalyzeUrl
 import io.legado.app.utils.isTrue
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.async
 import kotlinx.coroutines.ensureActive
 import kotlinx.coroutines.withContext
 import splitties.init.appCtx
+import kotlin.coroutines.coroutineContext
 
 /**
  * 获取目录
@@ -26,7 +26,6 @@ import splitties.init.appCtx
 object BookChapterList {
 
     suspend fun analyzeChapterList(
-        scope: CoroutineScope,
         bookSource: BookSource,
         book: Book,
         baseUrl: String,
@@ -52,7 +51,7 @@ object BookChapterList {
         }
         var chapterData =
             analyzeChapterList(
-                scope, book, baseUrl, redirectUrl, body,
+                book, baseUrl, redirectUrl, body,
                 tocRule, listRule, bookSource, log = true
             )
         chapterList.addAll(chapterData.first)
@@ -69,7 +68,7 @@ object BookChapterList {
                         headerMapF = bookSource.getHeaderMap()
                     ).getStrResponseAwait().body?.let { nextBody ->
                         chapterData = analyzeChapterList(
-                            scope, book, nextUrl, nextUrl,
+                            book, nextUrl, nextUrl,
                             nextBody, tocRule, listRule, bookSource
                         )
                         nextUrl = chapterData.second.firstOrNull() ?: ""
@@ -92,7 +91,7 @@ object BookChapterList {
                             )
                             val res = analyzeUrl.getStrResponseAwait()
                             analyzeChapterList(
-                                this, book, urlStr, res.url,
+                                book, urlStr, res.url,
                                 res.body!!, tocRule, listRule, bookSource, false
                             ).first
                         }
@@ -110,14 +109,14 @@ object BookChapterList {
         if (!reverse) {
             chapterList.reverse()
         }
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         val lh = LinkedHashSet(chapterList)
         val list = ArrayList(lh)
         if (!book.getReverseToc()) {
             list.reverse()
         }
         Debug.log(book.origin, "◇目录总数:${list.size}")
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         list.forEachIndexed { index, bookChapter ->
             bookChapter.index = index
         }
@@ -131,12 +130,11 @@ object BookChapterList {
         }
         book.lastCheckTime = System.currentTimeMillis()
         book.totalChapterNum = list.size
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         return list
     }
 
-    private fun analyzeChapterList(
-        scope: CoroutineScope,
+    private suspend fun analyzeChapterList(
         book: Book,
         baseUrl: String,
         redirectUrl: String,
@@ -173,7 +171,7 @@ object BookChapterList {
                 log
             )
         }
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         if (elements.isNotEmpty()) {
             Debug.log(bookSource.bookSourceUrl, "┌解析目录列表", log)
             val nameRule = analyzeRule.splitSourceRule(tocRule.chapterName)
@@ -183,7 +181,7 @@ object BookChapterList {
             val upTimeRule = analyzeRule.splitSourceRule(tocRule.updateTime)
             val isVolumeRule = analyzeRule.splitSourceRule(tocRule.isVolume)
             elements.forEachIndexed { index, item ->
-                scope.ensureActive()
+                coroutineContext.ensureActive()
                 analyzeRule.setContent(item)
                 val bookChapter = BookChapter(bookUrl = book.bookUrl, baseUrl = redirectUrl)
                 analyzeRule.chapter = bookChapter

+ 5 - 6
app/src/main/java/io/legado/app/model/webBook/BookContent.kt

@@ -14,12 +14,12 @@ import io.legado.app.model.analyzeRule.AnalyzeRule
 import io.legado.app.model.analyzeRule.AnalyzeUrl
 import io.legado.app.utils.HtmlFormatter
 import io.legado.app.utils.NetworkUtils
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.async
 import kotlinx.coroutines.ensureActive
 import kotlinx.coroutines.withContext
 import splitties.init.appCtx
+import kotlin.coroutines.coroutineContext
 
 /**
  * 获取正文
@@ -28,7 +28,6 @@ object BookContent {
 
     @Throws(Exception::class)
     suspend fun analyzeContent(
-        scope: CoroutineScope,
         bookSource: BookSource,
         book: Book,
         bookChapter: BookChapter,
@@ -55,7 +54,7 @@ object BookContent {
         val analyzeRule = AnalyzeRule(book, bookSource).setContent(body, baseUrl)
         analyzeRule.setRedirectUrl(redirectUrl)
         analyzeRule.nextChapterUrl = mNextChapterUrl
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         var contentData = analyzeContent(
             book, baseUrl, redirectUrl, body, contentRule, bookChapter, bookSource, mNextChapterUrl
         )
@@ -68,7 +67,7 @@ object BookContent {
                     == NetworkUtils.getAbsoluteURL(redirectUrl, mNextChapterUrl)
                 ) break
                 nextUrlList.add(nextUrl)
-                scope.ensureActive()
+                coroutineContext.ensureActive()
                 val res = AnalyzeUrl(
                     mUrl = nextUrl,
                     source = bookSource,
@@ -106,7 +105,7 @@ object BookContent {
                     }
                 }
                 asyncArray.forEach { coroutine ->
-                    scope.ensureActive()
+                    coroutineContext.ensureActive()
                     content.append("\n").append(coroutine.await())
                 }
             }
@@ -124,7 +123,7 @@ object BookContent {
             throw ContentEmptyException("内容为空")
         }
         if (needSave) {
-            BookHelp.saveContent(scope, bookSource, book, bookChapter, contentStr)
+            BookHelp.saveContent(bookSource, book, bookChapter, contentStr)
         }
         return contentStr
     }

+ 14 - 16
app/src/main/java/io/legado/app/model/webBook/BookInfo.kt

@@ -13,9 +13,9 @@ import io.legado.app.utils.DebugLog
 import io.legado.app.utils.HtmlFormatter
 import io.legado.app.utils.NetworkUtils
 import io.legado.app.utils.StringUtils.wordCountFormat
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ensureActive
 import splitties.init.appCtx
+import kotlin.coroutines.coroutineContext
 
 
 /**
@@ -24,8 +24,7 @@ import splitties.init.appCtx
 object BookInfo {
 
     @Throws(Exception::class)
-    fun analyzeBookInfo(
-        scope: CoroutineScope,
+    suspend fun analyzeBookInfo(
         bookSource: BookSource,
         book: Book,
         baseUrl: String,
@@ -41,11 +40,10 @@ object BookInfo {
         val analyzeRule = AnalyzeRule(book, bookSource)
         analyzeRule.setContent(body).setBaseUrl(baseUrl)
         analyzeRule.setRedirectUrl(redirectUrl)
-        analyzeBookInfo(scope, book, body, analyzeRule, bookSource, baseUrl, redirectUrl, canReName)
+        analyzeBookInfo(book, body, analyzeRule, bookSource, baseUrl, redirectUrl, canReName)
     }
 
-    fun analyzeBookInfo(
-        scope: CoroutineScope,
+    suspend fun analyzeBookInfo(
         book: Book,
         body: String,
         analyzeRule: AnalyzeRule,
@@ -57,13 +55,13 @@ object BookInfo {
         val infoRule = bookSource.getBookInfoRule()
         infoRule.init?.let {
             if (it.isNotBlank()) {
-                scope.ensureActive()
+                coroutineContext.ensureActive()
                 Debug.log(bookSource.bookSourceUrl, "≡执行详情页初始化规则")
                 analyzeRule.setContent(analyzeRule.getElement(it))
             }
         }
         val mCanReName = canReName && !infoRule.canReName.isNullOrBlank()
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         Debug.log(bookSource.bookSourceUrl, "┌获取书名")
         BookHelp.formatBookName(analyzeRule.getString(infoRule.name)).let {
             if (it.isNotEmpty() && (mCanReName || book.name.isEmpty())) {
@@ -71,7 +69,7 @@ object BookInfo {
             }
             Debug.log(bookSource.bookSourceUrl, "└${it}")
         }
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         Debug.log(bookSource.bookSourceUrl, "┌获取作者")
         BookHelp.formatBookAuthor(analyzeRule.getString(infoRule.author)).let {
             if (it.isNotEmpty() && (mCanReName || book.author.isEmpty())) {
@@ -79,7 +77,7 @@ object BookInfo {
             }
             Debug.log(bookSource.bookSourceUrl, "└${it}")
         }
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         Debug.log(bookSource.bookSourceUrl, "┌获取分类")
         try {
             analyzeRule.getStringList(infoRule.kind)
@@ -92,7 +90,7 @@ object BookInfo {
             Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
             DebugLog.e("获取分类出错", e)
         }
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         Debug.log(bookSource.bookSourceUrl, "┌获取字数")
         try {
             wordCountFormat(analyzeRule.getString(infoRule.wordCount)).let {
@@ -103,7 +101,7 @@ object BookInfo {
             Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
             DebugLog.e("获取字数出错", e)
         }
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         Debug.log(bookSource.bookSourceUrl, "┌获取最新章节")
         try {
             analyzeRule.getString(infoRule.lastChapter).let {
@@ -114,7 +112,7 @@ object BookInfo {
             Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
             DebugLog.e("获取最新章节出错", e)
         }
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         Debug.log(bookSource.bookSourceUrl, "┌获取简介")
         try {
             HtmlFormatter.format(analyzeRule.getString(infoRule.intro)).let {
@@ -125,7 +123,7 @@ object BookInfo {
             Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
             DebugLog.e("获取简介出错", e)
         }
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         Debug.log(bookSource.bookSourceUrl, "┌获取封面链接")
         try {
             analyzeRule.getString(infoRule.coverUrl).let {
@@ -140,7 +138,7 @@ object BookInfo {
             DebugLog.e("获取封面出错", e)
         }
         if (book.type != BookType.file) {
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             Debug.log(bookSource.bookSourceUrl, "┌获取目录链接")
             book.tocUrl = analyzeRule.getString(infoRule.tocUrl, isUrl = true)
             if (book.tocUrl.isEmpty()) book.tocUrl = baseUrl
@@ -149,7 +147,7 @@ object BookInfo {
             }
             Debug.log(bookSource.bookSourceUrl, "└${book.tocUrl}")
         } else {
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             Debug.log(bookSource.bookSourceUrl, "┌获取文件下载链接")
             book.downloadUrls = analyzeRule.getStringList(infoRule.downloadUrls, isUrl = true)
             if (book.downloadUrls == null) {

+ 16 - 21
app/src/main/java/io/legado/app/model/webBook/BookList.kt

@@ -14,9 +14,9 @@ import io.legado.app.model.analyzeRule.RuleData
 import io.legado.app.utils.HtmlFormatter
 import io.legado.app.utils.NetworkUtils
 import io.legado.app.utils.StringUtils.wordCountFormat
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ensureActive
 import splitties.init.appCtx
+import kotlin.coroutines.coroutineContext
 
 /**
  * 获取书籍列表
@@ -24,8 +24,7 @@ import splitties.init.appCtx
 object BookList {
 
     @Throws(Exception::class)
-    fun analyzeBookList(
-        scope: CoroutineScope,
+    suspend fun analyzeBookList(
         bookSource: BookSource,
         ruleData: RuleData,
         analyzeUrl: AnalyzeUrl,
@@ -46,11 +45,10 @@ object BookList {
         analyzeRule.setContent(body).setBaseUrl(baseUrl)
         analyzeRule.setRedirectUrl(baseUrl)
         bookSource.bookUrlPattern?.let {
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             if (baseUrl.matches(it.toRegex())) {
                 Debug.log(bookSource.bookSourceUrl, "≡链接为详情页")
                 getInfoItem(
-                    scope,
                     bookSource,
                     analyzeRule,
                     analyzeUrl,
@@ -81,11 +79,11 @@ object BookList {
         }
         Debug.log(bookSource.bookSourceUrl, "┌获取书籍列表")
         collections = analyzeRule.getElements(ruleList)
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         if (collections.isEmpty() && bookSource.bookUrlPattern.isNullOrEmpty()) {
             Debug.log(bookSource.bookSourceUrl, "└列表为空,按详情页解析")
             getInfoItem(
-                scope, bookSource, analyzeRule, analyzeUrl, body, baseUrl, ruleData.getVariable()
+                bookSource, analyzeRule, analyzeUrl, body, baseUrl, ruleData.getVariable()
             )?.let { searchBook ->
                 searchBook.infoHtml = body
                 bookList.add(searchBook)
@@ -102,7 +100,7 @@ object BookList {
             Debug.log(bookSource.bookSourceUrl, "└列表大小:${collections.size}")
             for ((index, item) in collections.withIndex()) {
                 getSearchItem(
-                    scope, bookSource, analyzeRule, item, baseUrl, ruleData.getVariable(),
+                    bookSource, analyzeRule, item, baseUrl, ruleData.getVariable(),
                     index == 0,
                     ruleName = ruleName,
                     ruleBookUrl = ruleBookUrl,
@@ -127,8 +125,7 @@ object BookList {
     }
 
     @Throws(Exception::class)
-    private fun getInfoItem(
-        scope: CoroutineScope,
+    private suspend fun getInfoItem(
         bookSource: BookSource,
         analyzeRule: AnalyzeRule,
         analyzeUrl: AnalyzeUrl,
@@ -144,7 +141,6 @@ object BookList {
         book.type = bookSource.bookSourceType
         analyzeRule.ruleData = book
         BookInfo.analyzeBookInfo(
-            scope,
             book,
             body,
             analyzeRule,
@@ -160,8 +156,7 @@ object BookList {
     }
 
     @Throws(Exception::class)
-    private fun getSearchItem(
-        scope: CoroutineScope,
+    private suspend fun getSearchItem(
         bookSource: BookSource,
         analyzeRule: AnalyzeRule,
         item: Any,
@@ -184,16 +179,16 @@ object BookList {
         searchBook.originOrder = bookSource.customOrder
         analyzeRule.ruleData = searchBook
         analyzeRule.setContent(item)
-        scope.ensureActive()
+        coroutineContext.ensureActive()
         Debug.log(bookSource.bookSourceUrl, "┌获取书名", log)
         searchBook.name = BookHelp.formatBookName(analyzeRule.getString(ruleName))
         Debug.log(bookSource.bookSourceUrl, "└${searchBook.name}", log)
         if (searchBook.name.isNotEmpty()) {
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             Debug.log(bookSource.bookSourceUrl, "┌获取作者", log)
             searchBook.author = BookHelp.formatBookAuthor(analyzeRule.getString(ruleAuthor))
             Debug.log(bookSource.bookSourceUrl, "└${searchBook.author}", log)
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             Debug.log(bookSource.bookSourceUrl, "┌获取分类", log)
             try {
                 searchBook.kind = analyzeRule.getStringList(ruleKind)?.joinToString(",")
@@ -201,7 +196,7 @@ object BookList {
             } catch (e: Exception) {
                 Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
             }
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             Debug.log(bookSource.bookSourceUrl, "┌获取字数", log)
             try {
                 searchBook.wordCount = wordCountFormat(analyzeRule.getString(ruleWordCount))
@@ -209,7 +204,7 @@ object BookList {
             } catch (e: java.lang.Exception) {
                 Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
             }
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             Debug.log(bookSource.bookSourceUrl, "┌获取最新章节", log)
             try {
                 searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter)
@@ -217,7 +212,7 @@ object BookList {
             } catch (e: java.lang.Exception) {
                 Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
             }
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             Debug.log(bookSource.bookSourceUrl, "┌获取简介", log)
             try {
                 searchBook.intro = HtmlFormatter.format(analyzeRule.getString(ruleIntro))
@@ -225,7 +220,7 @@ object BookList {
             } catch (e: java.lang.Exception) {
                 Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
             }
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             Debug.log(bookSource.bookSourceUrl, "┌获取封面链接", log)
             try {
                 analyzeRule.getString(ruleCoverUrl).let {
@@ -237,7 +232,7 @@ object BookList {
             } catch (e: java.lang.Exception) {
                 Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}", log)
             }
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             Debug.log(bookSource.bookSourceUrl, "┌获取详情页链接", log)
             searchBook.bookUrl = analyzeRule.getString(ruleBookUrl, isUrl = true)
             if (searchBook.bookUrl.isEmpty()) {

+ 6 - 18
app/src/main/java/io/legado/app/model/webBook/WebBook.kt

@@ -29,12 +29,11 @@ object WebBook {
         context: CoroutineContext = Dispatchers.IO,
     ): Coroutine<ArrayList<SearchBook>> {
         return Coroutine.async(scope, context) {
-            searchBookAwait(scope, bookSource, key, page)
+            searchBookAwait(bookSource, key, page)
         }
     }
 
     suspend fun searchBookAwait(
-        scope: CoroutineScope,
         bookSource: BookSource,
         key: String,
         page: Int? = 1,
@@ -58,7 +57,6 @@ object WebBook {
                 }
             }
             return BookList.analyzeBookList(
-                scope = scope,
                 bookSource = bookSource,
                 ruleData = ruleData,
                 analyzeUrl = analyzeUrl,
@@ -81,12 +79,11 @@ object WebBook {
         context: CoroutineContext = Dispatchers.IO,
     ): Coroutine<List<SearchBook>> {
         return Coroutine.async(scope, context) {
-            exploreBookAwait(scope, bookSource, url, page)
+            exploreBookAwait(bookSource, url, page)
         }
     }
 
     suspend fun exploreBookAwait(
-        scope: CoroutineScope,
         bookSource: BookSource,
         url: String,
         page: Int? = 1,
@@ -108,7 +105,6 @@ object WebBook {
             }
         }
         return BookList.analyzeBookList(
-            scope = scope,
             bookSource = bookSource,
             ruleData = ruleData,
             analyzeUrl = analyzeUrl,
@@ -129,12 +125,11 @@ object WebBook {
         canReName: Boolean = true,
     ): Coroutine<Book> {
         return Coroutine.async(scope, context) {
-            getBookInfoAwait(scope, bookSource, book, canReName)
+            getBookInfoAwait(bookSource, book, canReName)
         }
     }
 
     suspend fun getBookInfoAwait(
-        scope: CoroutineScope,
         bookSource: BookSource,
         book: Book,
         canReName: Boolean = true,
@@ -142,7 +137,6 @@ object WebBook {
         book.type = bookSource.bookSourceType
         if (!book.infoHtml.isNullOrEmpty()) {
             BookInfo.analyzeBookInfo(
-                scope = scope,
                 bookSource = bookSource,
                 book = book,
                 baseUrl = book.bookUrl,
@@ -166,7 +160,6 @@ object WebBook {
                 }
             }
             BookInfo.analyzeBookInfo(
-                scope = scope,
                 bookSource = bookSource,
                 book = book,
                 baseUrl = book.bookUrl,
@@ -188,12 +181,11 @@ object WebBook {
         context: CoroutineContext = Dispatchers.IO
     ): Coroutine<List<BookChapter>> {
         return Coroutine.async(scope, context) {
-            getChapterListAwait(scope, bookSource, book).getOrThrow()
+            getChapterListAwait(bookSource, book).getOrThrow()
         }
     }
 
     suspend fun getChapterListAwait(
-        scope: CoroutineScope,
         bookSource: BookSource,
         book: Book,
     ): Result<List<BookChapter>> {
@@ -201,7 +193,6 @@ object WebBook {
         return kotlin.runCatching {
             if (book.bookUrl == book.tocUrl && !book.tocHtml.isNullOrEmpty()) {
                 BookChapterList.analyzeChapterList(
-                    scope = scope,
                     bookSource = bookSource,
                     book = book,
                     baseUrl = book.tocUrl,
@@ -224,7 +215,6 @@ object WebBook {
                     }
                 }
                 BookChapterList.analyzeChapterList(
-                    scope = scope,
                     bookSource = bookSource,
                     book = book,
                     baseUrl = book.tocUrl,
@@ -270,7 +260,6 @@ object WebBook {
         }
         return if (bookChapter.url == book.bookUrl && !book.tocHtml.isNullOrEmpty()) {
             BookContent.analyzeContent(
-                scope = scope,
                 bookSource = bookSource,
                 book = book,
                 bookChapter = bookChapter,
@@ -300,7 +289,6 @@ object WebBook {
                 }
             }
             BookContent.analyzeContent(
-                scope = scope,
                 bookSource = bookSource,
                 book = book,
                 bookChapter = bookChapter,
@@ -342,13 +330,13 @@ object WebBook {
     ): Result<Book> {
         return kotlin.runCatching {
             scope.isActive
-            searchBookAwait(scope, bookSource, name).firstOrNull {
+            searchBookAwait(bookSource, name).firstOrNull {
                 it.name == name && it.author == author
             }?.let { searchBook ->
                 scope.isActive
                 var book = searchBook.toBook()
                 if (book.tocUrl.isBlank()) {
-                    book = getBookInfoAwait(scope, bookSource, book)
+                    book = getBookInfoAwait(bookSource, book)
                 }
                 return@runCatching book
             }

+ 8 - 5
app/src/main/java/io/legado/app/service/CheckSourceService.kt

@@ -24,8 +24,11 @@ import io.legado.app.utils.activityPendingIntent
 import io.legado.app.utils.postEvent
 import io.legado.app.utils.servicePendingIntent
 import io.legado.app.utils.toastOnUi
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.Dispatchers.IO
+import kotlinx.coroutines.TimeoutCancellationException
+import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.launch
 import org.mozilla.javascript.WrappedException
 import java.util.concurrent.Executors
 import kotlin.math.min
@@ -139,7 +142,7 @@ class CheckSourceService : BaseService() {
             if (CheckSource.checkSearch) {
                 if (!source.searchUrl.isNullOrBlank()) {
                     source.removeGroup("搜索链接规则为空")
-                    val searchBooks = WebBook.searchBookAwait(this, source, searchWord)
+                    val searchBooks = WebBook.searchBookAwait(source, searchWord)
                     if (searchBooks.isEmpty()) {
                         source.addGroup("搜索失效")
                     } else {
@@ -164,7 +167,7 @@ class CheckSourceService : BaseService() {
                     source.addGroup("发现规则为空")
                 } else {
                     source.removeGroup("发现规则为空")
-                    val exploreBooks = WebBook.exploreBookAwait(this, source, url)
+                    val exploreBooks = WebBook.exploreBookAwait(source, url)
                     if (exploreBooks.isEmpty()) {
                         source.addGroup("发现失效")
                     } else {
@@ -205,13 +208,13 @@ class CheckSourceService : BaseService() {
             //校验详情
             if (CheckSource.checkInfo) {
                 if (mBook.tocUrl.isBlank()) {
-                    mBook = WebBook.getBookInfoAwait(this, source, mBook)
+                    mBook = WebBook.getBookInfoAwait(source, mBook)
                 }
                 //校验目录
                 if (CheckSource.checkCategory &&
                     source.bookSourceType != BookType.file
                 ) {
-                    val toc = WebBook.getChapterListAwait(this, source, mBook).getOrThrow()
+                    val toc = WebBook.getChapterListAwait(source, mBook).getOrThrow()
                     val nextChapterUrl = toc.getOrNull(1)?.url ?: toc.first().url
                     //校验正文
                     if (CheckSource.checkContent) {

+ 15 - 17
app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt

@@ -23,7 +23,6 @@ import io.legado.app.help.BookHelp
 import io.legado.app.help.ContentProcessor
 import io.legado.app.help.config.AppConfig
 import io.legado.app.utils.*
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.ensureActive
 import kotlinx.coroutines.sync.Mutex
@@ -37,6 +36,7 @@ import java.io.File
 import java.io.FileOutputStream
 import java.nio.charset.Charset
 import java.util.concurrent.ConcurrentHashMap
+import kotlin.coroutines.coroutineContext
 
 
 class CacheViewModel(application: Application) : BaseViewModel(application) {
@@ -79,9 +79,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
                 val uri = Uri.parse(path)
                 val doc = DocumentFile.fromTreeUri(context, uri)
                     ?: throw NoStackTraceException("获取导出文档失败")
-                export(this, doc, book)
+                export(doc, book)
             } else {
-                export(this, FileUtils.createFolderIfNotExist(path), book)
+                export(FileUtils.createFolderIfNotExist(path), book)
             }
         }.onError {
             exportProgress.remove(book.bookUrl)
@@ -98,14 +98,14 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
     }
 
     @Suppress("BlockingMethodInNonBlockingContext")
-    private suspend fun export(scope: CoroutineScope, doc: DocumentFile, book: Book) {
+    private suspend fun export(doc: DocumentFile, book: Book) {
         val filename = "${getExportFileName(book)}.txt"
         DocumentUtils.delete(doc, filename)
         val bookDoc = DocumentUtils.createFileIfNotExist(doc, filename)
             ?: throw NoStackTraceException("创建文档失败,请尝试重新设置导出文件夹")
         val stringBuilder = StringBuilder()
         context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
-            getAllContents(scope, book) { text, srcList ->
+            getAllContents(book) { text, srcList ->
                 bookOs.write(text.toByteArray(Charset.forName(AppConfig.exportCharset)))
                 stringBuilder.append(text)
                 srcList?.forEach {
@@ -128,12 +128,12 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
         }
     }
 
-    private suspend fun export(scope: CoroutineScope, file: File, book: Book) {
+    private suspend fun export(file: File, book: Book) {
         val filename = "${getExportFileName(book)}.txt"
         val bookPath = FileUtils.getPath(file, filename)
         val bookFile = FileUtils.createFileWithReplace(bookPath)
         val stringBuilder = StringBuilder()
-        getAllContents(scope, book) { text, srcList ->
+        getAllContents(book) { text, srcList ->
             bookFile.appendText(text, Charset.forName(AppConfig.exportCharset))
             stringBuilder.append(text)
             srcList?.forEach {
@@ -157,7 +157,6 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
     }
 
     private suspend fun getAllContents(
-        scope: CoroutineScope,
         book: Book,
         append: (text: String, srcList: ArrayList<Triple<String, Int, String>>?) -> Unit
     ) {
@@ -173,7 +172,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
         }"
         append(qy, null)
         appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             upAdapterLiveData.postValue(book.bookUrl)
             exportProgress[book.bookUrl] = index
             BookHelp.getContent(book, chapter).let { content ->
@@ -227,9 +226,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
                 val uri = Uri.parse(path)
                 val doc = DocumentFile.fromTreeUri(context, uri)
                     ?: throw NoStackTraceException("获取导出文档失败")
-                exportEpub(this, doc, book)
+                exportEpub(doc, book)
             } else {
-                exportEpub(this, FileUtils.createFolderIfNotExist(path), book)
+                exportEpub(FileUtils.createFolderIfNotExist(path), book)
             }
         }.onError {
             exportProgress.remove(book.bookUrl)
@@ -246,7 +245,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
     }
 
     @Suppress("BlockingMethodInNonBlockingContext")
-    private suspend fun exportEpub(scope: CoroutineScope, doc: DocumentFile, book: Book) {
+    private suspend fun exportEpub(doc: DocumentFile, book: Book) {
         val filename = "${getExportFileName(book)}.epub"
         DocumentUtils.delete(doc, filename)
         val epubBook = EpubBook()
@@ -259,7 +258,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
         val contentModel = setAssets(doc, book, epubBook)
 
         //设置正文
-        setEpubContent(scope, contentModel, book, epubBook)
+        setEpubContent(contentModel, book, epubBook)
         DocumentUtils.createFileIfNotExist(doc, filename)?.let { bookDoc ->
             context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
                 EpubWriter().write(epubBook, bookOs)
@@ -269,7 +268,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
     }
 
 
-    private suspend fun exportEpub(scope: CoroutineScope, file: File, book: Book) {
+    private suspend fun exportEpub(file: File, book: Book) {
         val filename = "${getExportFileName(book)}.epub"
         val epubBook = EpubBook()
         epubBook.version = "2.0"
@@ -283,7 +282,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
         val bookPath = FileUtils.getPath(file, filename)
         val bookFile = FileUtils.createFileWithReplace(bookPath)
         //设置正文
-        setEpubContent(scope, contentModel, book, epubBook)
+        setEpubContent(contentModel, book, epubBook)
         @Suppress("BlockingMethodInNonBlockingContext")
         EpubWriter().write(epubBook, FileOutputStream(bookFile))
     }
@@ -438,7 +437,6 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
     }
 
     private suspend fun setEpubContent(
-        scope: CoroutineScope,
         contentModel: String,
         book: Book,
         epubBook: EpubBook
@@ -447,7 +445,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
         val useReplace = AppConfig.exportUseReplace && book.getUseReplaceRule()
         val contentProcessor = ContentProcessor.get(book.name, book.origin)
         appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
-            scope.ensureActive()
+            coroutineContext.ensureActive()
             upAdapterLiveData.postValue(book.bookUrl)
             exportProgress[book.bookUrl] = index
             BookHelp.getContent(book, chapter).let { content ->

+ 9 - 10
app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceViewModel.kt

@@ -21,7 +21,6 @@ import io.legado.app.help.coroutine.Coroutine
 import io.legado.app.model.webBook.WebBook
 import io.legado.app.utils.getPrefBoolean
 import io.legado.app.utils.toastOnUi
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.ExecutorCoroutineDispatcher
 import kotlinx.coroutines.asCoroutineDispatcher
@@ -155,7 +154,7 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
         }
         val source = bookSourceList[searchIndex]
         val task = Coroutine.async(scope = viewModelScope, context = searchPool!!) {
-            val resultBooks = WebBook.searchBookAwait(this, source, name)
+            val resultBooks = WebBook.searchBookAwait(source, name)
             resultBooks.forEach { searchBook ->
                 if (searchBook.name == name) {
                     if ((AppConfig.changeSourceCheckAuthor && searchBook.author.contains(author))
@@ -163,7 +162,7 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
                     ) {
                         if (searchBook.latestChapterTitle.isNullOrEmpty()) {
                             if (AppConfig.changeSourceLoadInfo || AppConfig.changeSourceLoadToc) {
-                                loadBookInfo(this, source, searchBook.toBook())
+                                loadBookInfo(source, searchBook.toBook())
                             } else {
                                 searchCallback?.searchSuccess(searchBook)
                             }
@@ -183,10 +182,10 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
         tasks.add(task)
     }
 
-    private suspend fun loadBookInfo(scope: CoroutineScope, source: BookSource, book: Book) {
-        WebBook.getBookInfoAwait(scope, source, book)
+    private suspend fun loadBookInfo(source: BookSource, book: Book) {
+        WebBook.getBookInfoAwait(source, book)
         if (context.getPrefBoolean(PreferKey.changeSourceLoadToc)) {
-            loadBookToc(scope, source, book)
+            loadBookToc(source, book)
         } else {
             //从详情页里获取最新章节
             val searchBook = book.toSearchBook()
@@ -194,8 +193,8 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
         }
     }
 
-    private suspend fun loadBookToc(scope: CoroutineScope, source: BookSource, book: Book) {
-        val chapters = WebBook.getChapterListAwait(scope, source, book).getOrThrow()
+    private suspend fun loadBookToc(source: BookSource, book: Book) {
+        val chapters = WebBook.getChapterListAwait(source, book).getOrThrow()
         tocMap[book.bookUrl] = chapters
         book.latestChapterTitle = chapters.last().title
         val searchBook: SearchBook = book.toSearchBook()
@@ -298,9 +297,9 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
                 val source = appDb.bookSourceDao.getBookSource(book.origin)
                     ?: throw NoStackTraceException("书源不存在")
                 if (book.tocUrl.isEmpty()) {
-                    WebBook.getBookInfoAwait(this, source, book)
+                    WebBook.getBookInfoAwait(source, book)
                 }
-                val toc = WebBook.getChapterListAwait(this, source, book).getOrThrow()
+                val toc = WebBook.getChapterListAwait(source, book).getOrThrow()
                 Pair(toc, source)
             }
         }

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/manage/BookshelfManageViewModel.kt

@@ -51,7 +51,7 @@ class BookshelfManageViewModel(application: Application) : BaseViewModel(applica
                     .onFailure {
                         context.toastOnUi("获取书籍出错\n${it.localizedMessage}")
                     }.getOrNull()?.let { newBook ->
-                        WebBook.getChapterListAwait(this, source, newBook)
+                        WebBook.getChapterListAwait(source, newBook)
                             .onFailure {
                                 context.toastOnUi("获取目录出错\n${it.localizedMessage}")
                             }.getOrNull()?.let { toc ->

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

@@ -245,9 +245,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
             sources.forEach { source ->
                 WebBook.preciseSearchAwait(this, source, name, author).getOrNull()?.let { book ->
                     if (book.tocUrl.isEmpty()) {
-                        WebBook.getBookInfoAwait(this, source, book)
+                        WebBook.getBookInfoAwait(source, book)
                     }
-                    val toc = WebBook.getChapterListAwait(this, source, book).getOrThrow()
+                    val toc = WebBook.getChapterListAwait(source, book).getOrThrow()
                     changeTo(source, book, toc)
                     return@execute
                 }

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt

@@ -160,7 +160,7 @@ class SearchContentActivity :
                         binding.fbStop.visible()
                         val searchResults = withContext(IO) {
                             if (isLocalBook || viewModel.cacheChapterNames.contains(bookChapter.getFileName())) {
-                                viewModel.searchChapter(this, query, bookChapter)
+                                viewModel.searchChapter(query, bookChapter)
                             } else {
                                 null
                             }

+ 7 - 8
app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentViewModel.kt

@@ -10,10 +10,10 @@ import io.legado.app.data.entities.BookChapter
 import io.legado.app.help.BookHelp
 import io.legado.app.help.ContentProcessor
 import io.legado.app.help.config.AppConfig
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ensureActive
 import kotlinx.coroutines.withContext
+import kotlin.coroutines.coroutineContext
 
 class SearchContentViewModel(application: Application) : BaseViewModel(application) {
     var bookUrl: String = ""
@@ -38,7 +38,6 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
     }
 
     suspend fun searchChapter(
-        scope: CoroutineScope,
         query: String,
         chapter: BookChapter?
     ): List<SearchResult> {
@@ -46,7 +45,7 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
         if (chapter != null) {
             book?.let { book ->
                 val chapterContent = BookHelp.getContent(book, chapter)
-                scope.ensureActive()
+                coroutineContext.ensureActive()
                 if (chapterContent != null) {
                     //先搜索没有启用净化的正文
                     withContext(Dispatchers.IO) {
@@ -55,7 +54,7 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
                             2 -> ChineseUtils.s2t(chapter.title)
                             else -> chapter.title
                         }
-                        scope.ensureActive()
+                        kotlin.coroutines.coroutineContext.ensureActive()
                         mContent = contentProcessor!!.getContent(
                             book, chapter, chapterContent,
                             chineseConvert = true,
@@ -63,9 +62,9 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
                             useReplace = false
                         ).joinToString("")
                     }
-                    val positions = searchPosition(scope, query)
+                    val positions = searchPosition(query)
                     positions.forEachIndexed { index, position ->
-                        scope.ensureActive()
+                        coroutineContext.ensureActive()
                         val construct = getResultAndQueryIndex(mContent, position, query)
                         val result = SearchResult(
                             resultCountWithinChapter = index,
@@ -85,7 +84,7 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
         return searchResultsWithinChapter
     }
 
-    private suspend fun searchPosition(scope: CoroutineScope, pattern: String): List<Int> {
+    private suspend fun searchPosition(pattern: String): List<Int> {
         val position: MutableList<Int> = mutableListOf()
         var index = mContent.indexOf(pattern)
         if (index >= 0) {
@@ -95,7 +94,7 @@ class SearchContentViewModel(application: Application) : BaseViewModel(applicati
                 index = mContent.indexOf(pattern)
             }
             while (index >= 0) {
-                scope.ensureActive()
+                coroutineContext.ensureActive()
                 position.add(index)
                 index = mContent.indexOf(pattern, index + pattern.length)
             }

+ 2 - 2
app/src/main/java/io/legado/app/ui/main/MainViewModel.kt

@@ -123,9 +123,9 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
                 AnalyzeRule(book, source).evalJS(preUpdateJs)
             }
             if (book.tocUrl.isBlank()) {
-                WebBook.getBookInfoAwait(this, source, book)
+                WebBook.getBookInfoAwait(source, book)
             }
-            val toc = WebBook.getChapterListAwait(this, source, book).getOrThrow()
+            val toc = WebBook.getChapterListAwait(source, book).getOrThrow()
             if (book.bookUrl == bookUrl) {
                 appDb.bookDao.update(book)
             } else {