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 c8f9712a2..5eb9ece5c 100644 --- a/app/src/main/java/io/legado/app/model/ReadBook.kt +++ b/app/src/main/java/io/legado/app/model/ReadBook.kt @@ -85,7 +85,7 @@ object ReadBook : CoroutineScope by MainScope() { var readStartTime: Long = System.currentTimeMillis() /* 跳转进度前进度记录 */ - var lastBookPress: BookProgress? = null + var lastBookProgress: BookProgress? = null /* web端阅读进度记录 */ var webBookProgress: BookProgress? = null @@ -98,20 +98,6 @@ object ReadBook : CoroutineScope by MainScope() { val preDownloadSemaphore = Semaphore(2) val executor = globalExecutor - //暂时保存跳转前进度 - fun saveCurrentBookProcess() { - if (lastBookPress != null) return //避免进度条连续跳转不能覆盖最初的进度记录 - lastBookPress = book?.let { BookProgress(it) } - } - - //恢复跳转前进度 - fun restoreLastBookProcess() { - lastBookPress?.let { - setProgress(it) - lastBookPress = null - } - } - fun resetData(book: Book) { ReadBook.book = book readRecord.bookName = book.name @@ -131,7 +117,7 @@ object ReadBook : CoroutineScope by MainScope() { callBack?.upMenuView() callBack?.upPageAnim() upWebBook(book) - lastBookPress = null + lastBookProgress = null webBookProgress = null TextFile.clear() synchronized(this) { @@ -219,6 +205,20 @@ object ReadBook : CoroutineScope by MainScope() { } } + //暂时保存跳转前进度 + fun saveCurrentBookProgress() { + if (lastBookProgress != null) return //避免进度条连续跳转不能覆盖最初的进度记录 + lastBookProgress = book?.let { BookProgress(it) } + } + + //恢复跳转前进度 + fun restoreLastBookProgress() { + lastBookProgress?.let { + setProgress(it) + lastBookProgress = null + } + } + fun clearTextChapter() { prevTextChapter = null curTextChapter = null @@ -558,29 +558,27 @@ object ReadBook : CoroutineScope by MainScope() { resetPageOffset: Boolean = false, success: (() -> Unit)? = null ) { - if (addLoading(index)) { - Coroutine.async { - val book = book!! - appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let { chapter -> - BookHelp.getContent(book, chapter)?.let { - contentLoadFinish( - book, - chapter, - it, - upContent, - resetPageOffset, - success = success - ) - } ?: download( - downloadScope, + Coroutine.async { + val book = book!! + val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, index) ?: return@async + if (addLoading(index)) { + BookHelp.getContent(book, chapter)?.let { + contentLoadFinish( + book, chapter, - resetPageOffset + it, + upContent, + resetPageOffset, + success = success ) - } ?: removeLoading(index) - }.onError { - removeLoading(index) - AppLog.put("加载正文出错\n${it.localizedMessage}") + } ?: download( + downloadScope, + chapter, + resetPageOffset + ) } + }.onError { + AppLog.put("加载正文出错\n${it.localizedMessage}") } } @@ -615,20 +613,13 @@ object ReadBook : CoroutineScope by MainScope() { return } val book = book ?: return - if (addLoading(index)) { - try { - appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let { chapter -> - if (BookHelp.hasContent(book, chapter)) { - removeLoading(chapter.index) - downloadedChapters.add(chapter.index) - } else { - delay(1000) - download(downloadScope, chapter, false, preDownloadSemaphore) - } - } ?: removeLoading(index) - } catch (_: Exception) { - removeLoading(index) - coroutineContext.ensureActive() + val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, index) ?: return + if (BookHelp.hasContent(book, chapter)) { + addDownloadedChapter(chapter.index) + } else { + delay(1000) + if (addLoading(index)) { + download(downloadScope, chapter, false, preDownloadSemaphore) } } } @@ -670,18 +661,21 @@ object ReadBook : CoroutineScope by MainScope() { } } + @Synchronized private fun addLoading(index: Int): Boolean { - synchronized(this) { - if (loadingChapters.contains(index)) return false - loadingChapters.add(index) - return true - } + if (loadingChapters.contains(index)) return false + loadingChapters.add(index) + return true } + @Synchronized fun removeLoading(index: Int) { - synchronized(this) { - loadingChapters.remove(index) - } + loadingChapters.remove(index) + } + + @Synchronized + fun addDownloadedChapter(index: Int) { + downloadedChapters.add(index) } /** @@ -901,7 +895,7 @@ object ReadBook : CoroutineScope by MainScope() { launch { val maxChapterIndex = min(durChapterIndex + AppConfig.preDownloadNum, chapterSize) - for (i in durChapterIndex.plus(1)..maxChapterIndex) { + for (i in durChapterIndex.plus(2)..maxChapterIndex) { if (downloadedChapters.contains(i)) continue if ((downloadFailChapters[i] ?: 0) >= 3) continue downloadIndex(i) @@ -909,7 +903,7 @@ object ReadBook : CoroutineScope by MainScope() { } launch { val minChapterIndex = durChapterIndex - min(5, AppConfig.preDownloadNum) - for (i in durChapterIndex.minus(1) downTo minChapterIndex) { + for (i in durChapterIndex.minus(2) 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 3795f97de..67eedbf96 100644 --- a/app/src/main/java/io/legado/app/model/ReadManga.kt +++ b/app/src/main/java/io/legado/app/model/ReadManga.kt @@ -70,23 +70,24 @@ object ReadManga : CoroutineScope by MainScope() { val mangaContents get() = buildContentList() val hasNextChapter get() = durChapterIndex < simulatedChapterSize - 1 - fun saveRead(pageChanged: Boolean = false) { - executor.execute { - val book = book ?: return@execute - book.lastCheckCount = 0 - book.durChapterTime = System.currentTimeMillis() - val chapterChanged = book.durChapterIndex != durChapterIndex - book.durChapterIndex = durChapterIndex - book.durChapterPos = durChapterPos - if (!pageChanged || chapterChanged) { - appDb.bookChapterDao.getChapter(book.bookUrl, durChapterIndex)?.let { - book.durChapterTitle = it.getDisplayTitle( - ContentProcessor.get(book.name, book.origin).getTitleReplaceRules(), - book.getUseReplaceRule() - ) - } - } - appDb.bookDao.update(book) + fun resetData(book: Book) { + ReadManga.book = book + readRecord.bookName = book.name + readRecord.readTime = appDb.readRecordDao.getReadTime(book.name) ?: 0 + chapterSize = appDb.bookChapterDao.getChapterCount(book.bookUrl) + simulatedChapterSize = if (book.readSimulating()) { + book.simulatedTotalChapterNum() + } else { + chapterSize + } + durChapterIndex = book.durChapterIndex + durChapterPos = book.durChapterPos + clearMangaChapter() + upWebBook(book) + synchronized(this) { + loadingChapters.clear() + downloadedChapters.clear() + downloadFailChapters.clear() } } @@ -110,27 +111,6 @@ object ReadManga : CoroutineScope by MainScope() { } } - fun resetData(book: Book) { - ReadManga.book = book - readRecord.bookName = book.name - readRecord.readTime = appDb.readRecordDao.getReadTime(book.name) ?: 0 - chapterSize = appDb.bookChapterDao.getChapterCount(book.bookUrl) - simulatedChapterSize = if (book.readSimulating()) { - book.simulatedTotalChapterNum() - } else { - chapterSize - } - durChapterIndex = book.durChapterIndex - durChapterPos = book.durChapterPos - clearMangaChapter() - upWebBook(book) - synchronized(this) { - loadingChapters.clear() - downloadedChapters.clear() - downloadFailChapters.clear() - } - } - fun upWebBook(book: Book) { appDb.bookSourceDao.getBookSource(book.origin)?.let { bookSource = it @@ -159,43 +139,21 @@ object ReadManga : CoroutineScope by MainScope() { } } + @Synchronized private fun addLoading(index: Int): Boolean { - synchronized(this) { - if (loadingChapters.contains(index)) return false - loadingChapters.add(index) - return true - } + if (loadingChapters.contains(index)) return false + loadingChapters.add(index) + return true } + @Synchronized fun removeLoading(index: Int) { - synchronized(this) { - loadingChapters.remove(index) - } + loadingChapters.remove(index) } - /** - * 获取正文 - */ - 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, semaphore, success = { - downloadedChapters.add(chapter.index) - downloadFailChapters.remove(chapter.index) - contentLoadFinish(chapter, it) - }, error = { - downloadFailChapters[chapter.index] = - (downloadFailChapters[chapter.index] ?: 0) + 1 - contentLoadFinish(chapter, null) - }, cancel = { - contentLoadFinish(chapter, null, true) - }) - } + @Synchronized + fun addDownloadedChapter(index: Int) { + downloadedChapters.add(index) } fun loadContent() { @@ -220,21 +178,18 @@ object ReadManga : CoroutineScope by MainScope() { } private fun loadContent(index: Int) { - if (addLoading(index)) { - Coroutine.async { - val book = book!! - appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let { chapter -> - BookHelp.getContent(book, chapter)?.let { - contentLoadFinish(chapter, it) - } ?: download( - downloadScope, - chapter, - ) - } ?: removeLoading(index) - }.onError { - removeLoading(index) - AppLog.put("加载正文出错\n${it.localizedMessage}") + Coroutine.async { + val book = book!! + val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, index) ?: return@async + if (addLoading(index)) { + BookHelp.getContent(book, chapter)?.let { + contentLoadFinish(chapter, it) + } ?: run { + download(downloadScope, chapter) + } } + }.onError { + AppLog.put("加载正文出错\n${it.localizedMessage}") } } @@ -244,6 +199,7 @@ object ReadManga : CoroutineScope by MainScope() { suspend fun contentLoadFinish( chapter: BookChapter, content: String?, + errorMsg: String = "加载内容失败", canceled: Boolean = false ) { removeLoading(chapter.index) @@ -253,7 +209,7 @@ object ReadManga : CoroutineScope by MainScope() { when (val offset = chapter.index - durChapterIndex) { 0 -> { if (content == null) { - mCallback?.loadFail("加载内容失败") + mCallback?.loadFail(errorMsg) return } if (content.isEmpty()) { @@ -354,6 +310,26 @@ object ReadManga : CoroutineScope by MainScope() { preDownload() } + fun saveRead(pageChanged: Boolean = false) { + executor.execute { + val book = book ?: return@execute + book.lastCheckCount = 0 + book.durChapterTime = System.currentTimeMillis() + val chapterChanged = book.durChapterIndex != durChapterIndex + book.durChapterIndex = durChapterIndex + book.durChapterPos = durChapterPos + if (!pageChanged || chapterChanged) { + appDb.bookChapterDao.getChapter(book.bookUrl, durChapterIndex)?.let { + book.durChapterTitle = it.getDisplayTitle( + ContentProcessor.get(book.name, book.origin).getTitleReplaceRules(), + book.getUseReplaceRule() + ) + } + } + appDb.bookDao.update(book) + } + } + private fun downloadNetworkContent( bookSource: BookSource, scope: CoroutineScope, @@ -393,7 +369,7 @@ object ReadManga : CoroutineScope by MainScope() { launch { val maxChapterIndex = min(durChapterIndex + AppConfig.preDownloadNum, chapterSize) - for (i in durChapterIndex.plus(1)..maxChapterIndex) { + for (i in durChapterIndex.plus(2)..maxChapterIndex) { if (downloadedChapters.contains(i)) continue if ((downloadFailChapters[i] ?: 0) >= 3) continue downloadIndex(i) @@ -401,7 +377,7 @@ object ReadManga : CoroutineScope by MainScope() { } launch { val minChapterIndex = durChapterIndex - min(5, AppConfig.preDownloadNum) - for (i in durChapterIndex.minus(1) downTo minChapterIndex) { + for (i in durChapterIndex.minus(2) downTo minChapterIndex) { if (downloadedChapters.contains(i)) continue if ((downloadFailChapters[i] ?: 0) >= 3) continue downloadIndex(i) @@ -425,24 +401,44 @@ object ReadManga : CoroutineScope by MainScope() { return } val book = book ?: return - if (addLoading(index)) { - try { - appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let { chapter -> - if (BookHelp.hasContent(book, chapter)) { - removeLoading(chapter.index) - downloadedChapters.add(chapter.index) - } else { - delay(1000) - download(downloadScope, chapter, preDownloadSemaphore) - } - } ?: removeLoading(index) - } catch (_: Exception) { - removeLoading(index) - coroutineContext.ensureActive() + val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, index) ?: return + if (BookHelp.hasContent(book, chapter)) { + addDownloadedChapter(chapter.index) + } else { + delay(1000) + if (addLoading(index)) { + download(downloadScope, chapter, preDownloadSemaphore) } } } + /** + * 获取正文 + */ + private suspend 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, semaphore, success = { + downloadedChapters.add(chapter.index) + downloadFailChapters.remove(chapter.index) + contentLoadFinish(chapter, it) + }, error = { + downloadFailChapters[chapter.index] = + (downloadFailChapters[chapter.index] ?: 0) + 1 + contentLoadFinish(chapter, null) + }, cancel = { + contentLoadFinish(chapter, null, canceled = true) + }) + } else { + contentLoadFinish(chapter, null, "加载内容失败 没有书源") + } + } + @Synchronized fun upToc() { val bookSource = bookSource ?: return diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index df0cac6e4..3f770444b 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -186,7 +186,7 @@ class ReadBookActivity : BaseReadBookActivity(), viewModel.searchResultIndex = index binding.searchMenu.updateSearchResultIndex(index) binding.searchMenu.selectedSearchResult?.let { currentResult -> - ReadBook.saveCurrentBookProcess() //退出全文搜索恢复此时进度 + ReadBook.saveCurrentBookProgress() //退出全文搜索恢复此时进度 skipToSearch(currentResult) showActionMenu() } @@ -269,7 +269,7 @@ class ReadBookActivity : BaseReadBookActivity(), return@addCallback } //拦截返回供恢复阅读进度 - if (ReadBook.lastBookPress != null && confirmRestoreProcess != false) { + if (ReadBook.lastBookProgress != null && confirmRestoreProcess != false) { restoreLastBookProcess() return@addCallback } @@ -1239,20 +1239,20 @@ class ReadBookActivity : BaseReadBookActivity(), /* 恢复到 全文搜索/进度条跳转前的位置 */ private fun restoreLastBookProcess() { if (confirmRestoreProcess == true) { - ReadBook.restoreLastBookProcess() + ReadBook.restoreLastBookProgress() } else if (confirmRestoreProcess == null) { alert(R.string.draw) { setMessage(R.string.restore_last_book_process) yesButton { confirmRestoreProcess = true - ReadBook.restoreLastBookProcess() //恢复启动全文搜索前的进度 + ReadBook.restoreLastBookProgress() //恢复启动全文搜索前的进度 } noButton { - ReadBook.lastBookPress = null + ReadBook.lastBookProgress = null confirmRestoreProcess = false } onCancelled { - ReadBook.lastBookPress = null + ReadBook.lastBookProgress = null confirmRestoreProcess = false } } @@ -1451,7 +1451,7 @@ class ReadBookActivity : BaseReadBookActivity(), /* 进度条跳转到指定章节 */ override fun skipToChapter(index: Int) { - ReadBook.saveCurrentBookProcess() //退出章节跳转恢复此时进度 + ReadBook.saveCurrentBookProgress() //退出章节跳转恢复此时进度 viewModel.openChapter(index) }