|
|
@@ -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()
|
|
|
}
|
|
|
}
|
|
|
}
|