From 19e5b74a5f8fc149be86ccf14f8b0e7883c1d629 Mon Sep 17 00:00:00 2001 From: Horis <8674809+821938089@users.noreply.github.com> Date: Fri, 7 Mar 2025 21:59:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/legado/app/model/ReadBook.kt | 5 ++- .../java/io/legado/app/model/ReadManga.kt | 43 +++++++++++++------ .../app/ui/book/manga/ReadMangaActivity.kt | 1 + 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/ReadBook.kt b/app/src/main/java/io/legado/app/model/ReadBook.kt index 0ef483dbf..c8f9712a2 100644 --- a/app/src/main/java/io/legado/app/model/ReadBook.kt +++ b/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) diff --git a/app/src/main/java/io/legado/app/model/ReadManga.kt b/app/src/main/java/io/legado/app/model/ReadManga.kt index 182857fcd..3795f97de 100644 --- a/app/src/main/java/io/legado/app/model/ReadManga.kt +++ b/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() val downloadFailChapters = hashMapOf() 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() } } } diff --git a/app/src/main/java/io/legado/app/ui/book/manga/ReadMangaActivity.kt b/app/src/main/java/io/legado/app/ui/book/manga/ReadMangaActivity.kt index 5242ff9ef..d9ad8876d 100644 --- a/app/src/main/java/io/legado/app/ui/book/manga/ReadMangaActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/manga/ReadMangaActivity.kt @@ -372,6 +372,7 @@ class ReadMangaActivity : VMBaseActivity