Horis 1 год назад
Родитель
Сommit
f0f7aebe53

+ 3 - 2
app/src/main/java/io/legado/app/model/ReadBook.kt

@@ -628,6 +628,7 @@ object ReadBook : CoroutineScope by MainScope() {
                 } ?: removeLoading(index)
             } catch (_: Exception) {
                 removeLoading(index)
+                coroutineContext.ensureActive()
             }
         }
     }
@@ -900,7 +901,7 @@ object ReadBook : CoroutineScope by MainScope() {
                 launch {
                     val maxChapterIndex =
                         min(durChapterIndex + AppConfig.preDownloadNum, chapterSize)
-                    for (i in durChapterIndex.plus(2)..maxChapterIndex) {
+                    for (i in durChapterIndex.plus(1)..maxChapterIndex) {
                         if (downloadedChapters.contains(i)) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         downloadIndex(i)
@@ -908,7 +909,7 @@ object ReadBook : CoroutineScope by MainScope() {
                 }
                 launch {
                     val minChapterIndex = durChapterIndex - min(5, AppConfig.preDownloadNum)
-                    for (i in durChapterIndex.minus(2) downTo minChapterIndex) {
+                    for (i in durChapterIndex.minus(1) downTo minChapterIndex) {
                         if (downloadedChapters.contains(i)) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         downloadIndex(i)

+ 30 - 13
app/src/main/java/io/legado/app/model/ReadManga.kt

@@ -39,6 +39,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.toList
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Semaphore
 import kotlin.math.min
 
 @Suppress("MemberVisibilityCanBePrivate")
@@ -64,6 +65,7 @@ object ReadManga : CoroutineScope by MainScope() {
     val downloadedChapters = hashSetOf<Int>()
     val downloadFailChapters = hashMapOf<Int, Int>()
     val downloadScope = CoroutineScope(SupervisorJob() + IO)
+    val preDownloadSemaphore = Semaphore(2)
     var rateLimiter = ConcurrentRateLimiter(null)
     val mangaContents get() = buildContentList()
     val hasNextChapter get() = durChapterIndex < simulatedChapterSize - 1
@@ -73,10 +75,10 @@ object ReadManga : CoroutineScope by MainScope() {
             val book = book ?: return@execute
             book.lastCheckCount = 0
             book.durChapterTime = System.currentTimeMillis()
-            val changed = book.durChapterIndex != durChapterIndex
+            val chapterChanged = book.durChapterIndex != durChapterIndex
             book.durChapterIndex = durChapterIndex
             book.durChapterPos = durChapterPos
-            if (!pageChanged || changed) {
+            if (!pageChanged || chapterChanged) {
                 appDb.bookChapterDao.getChapter(book.bookUrl, durChapterIndex)?.let {
                     book.durChapterTitle = it.getDisplayTitle(
                         ContentProcessor.get(book.name, book.origin).getTitleReplaceRules(),
@@ -177,18 +179,21 @@ object ReadManga : CoroutineScope by MainScope() {
     private fun download(
         scope: CoroutineScope,
         chapter: BookChapter,
+        semaphore: Semaphore? = null,
     ) {
         val book = book ?: return removeLoading(chapter.index)
         val bookSource = bookSource
         if (bookSource != null) {
-            downloadNetworkContent(bookSource, scope, chapter, book, success = {
+            downloadNetworkContent(bookSource, scope, chapter, book, semaphore, success = {
                 downloadedChapters.add(chapter.index)
                 downloadFailChapters.remove(chapter.index)
-                contentLoadFinish(chapter, it, book)
+                contentLoadFinish(chapter, it)
             }, error = {
                 downloadFailChapters[chapter.index] =
                     (downloadFailChapters[chapter.index] ?: 0) + 1
-                contentLoadFinish(chapter, null, book)
+                contentLoadFinish(chapter, null)
+            }, cancel = {
+                contentLoadFinish(chapter, null, true)
             })
         }
     }
@@ -196,8 +201,8 @@ object ReadManga : CoroutineScope by MainScope() {
     fun loadContent() {
         clearMangaChapter()
         loadContent(durChapterIndex)
-        loadContent(durChapterIndex - 1)
         loadContent(durChapterIndex + 1)
+        loadContent(durChapterIndex - 1)
     }
 
     fun loadOrUpContent() {
@@ -220,7 +225,7 @@ object ReadManga : CoroutineScope by MainScope() {
                 val book = book!!
                 appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let { chapter ->
                     BookHelp.getContent(book, chapter)?.let {
-                        contentLoadFinish(chapter, it, book)
+                        contentLoadFinish(chapter, it)
                     } ?: download(
                         downloadScope,
                         chapter,
@@ -239,10 +244,10 @@ object ReadManga : CoroutineScope by MainScope() {
     suspend fun contentLoadFinish(
         chapter: BookChapter,
         content: String?,
-        book: Book,
+        canceled: Boolean = false
     ) {
         removeLoading(chapter.index)
-        if (chapter.index !in durChapterIndex - 1..durChapterIndex + 1) {
+        if (canceled || chapter.index !in durChapterIndex - 1..durChapterIndex + 1) {
             return
         }
         when (val offset = chapter.index - durChapterIndex) {
@@ -354,8 +359,10 @@ object ReadManga : CoroutineScope by MainScope() {
         scope: CoroutineScope,
         chapter: BookChapter,
         book: Book,
+        semaphore: Semaphore?,
         success: suspend (String) -> Unit = {},
         error: suspend () -> Unit = {},
+        cancel: suspend () -> Unit = {},
     ) {
         WebBook.getContent(
             scope,
@@ -364,11 +371,13 @@ object ReadManga : CoroutineScope by MainScope() {
             chapter,
             start = CoroutineStart.LAZY,
             executeContext = IO,
-            needSave = true
+            semaphore = semaphore
         ).onSuccess { content ->
             success.invoke(content)
         }.onError {
             error.invoke()
+        }.onCancel {
+            cancel.invoke()
         }.start()
     }
 
@@ -384,7 +393,7 @@ object ReadManga : CoroutineScope by MainScope() {
                 launch {
                     val maxChapterIndex =
                         min(durChapterIndex + AppConfig.preDownloadNum, chapterSize)
-                    for (i in durChapterIndex.plus(2)..maxChapterIndex) {
+                    for (i in durChapterIndex.plus(1)..maxChapterIndex) {
                         if (downloadedChapters.contains(i)) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         downloadIndex(i)
@@ -392,7 +401,7 @@ object ReadManga : CoroutineScope by MainScope() {
                 }
                 launch {
                     val minChapterIndex = durChapterIndex - min(5, AppConfig.preDownloadNum)
-                    for (i in durChapterIndex.minus(2) downTo minChapterIndex) {
+                    for (i in durChapterIndex.minus(1) downTo minChapterIndex) {
                         if (downloadedChapters.contains(i)) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         downloadIndex(i)
@@ -402,6 +411,13 @@ object ReadManga : CoroutineScope by MainScope() {
         }
     }
 
+    fun cancelPreDownloadTask() {
+        if (curMangaChapter != null && nextMangaChapter != null) {
+            preDownloadTask?.cancel()
+            downloadScope.coroutineContext.cancelChildren()
+        }
+    }
+
     private suspend fun downloadIndex(index: Int) {
         if (index < 0) return
         if (index > chapterSize - 1) {
@@ -417,11 +433,12 @@ object ReadManga : CoroutineScope by MainScope() {
                         downloadedChapters.add(chapter.index)
                     } else {
                         delay(1000)
-                        download(downloadScope, chapter)
+                        download(downloadScope, chapter, preDownloadSemaphore)
                     }
                 } ?: removeLoading(index)
             } catch (_: Exception) {
                 removeLoading(index)
+                coroutineContext.ensureActive()
             }
         }
     }

+ 1 - 0
app/src/main/java/io/legado/app/ui/book/manga/ReadMangaActivity.kt

@@ -372,6 +372,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
                 Backup.autoBack(this)
             }
         }
+        ReadManga.cancelPreDownloadTask()
         networkChangedListener.unRegister()
         stopAutoPage()
     }