下载优化
This commit is contained in:
@@ -78,7 +78,7 @@ object CacheBook {
|
||||
}
|
||||
var emitted = false
|
||||
taskMap.forEach { (_, model) ->
|
||||
if (model.hasRunnableDownloads()) {
|
||||
if (model.hasLaunchableChapters()) {
|
||||
emit(model)
|
||||
emitted = true
|
||||
}
|
||||
|
||||
@@ -153,6 +153,16 @@ class CacheBookModel(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 有可启动的下载任务(队列中有待下载章节或正在加载目录)。
|
||||
* 与 [hasRunnableDownloads] 不同,不包含已在执行中的任务。
|
||||
* 用于判断是否需要向下载循环 emit 模型,避免无新章节可取时的高频空转。
|
||||
*/
|
||||
@Synchronized
|
||||
fun hasLaunchableChapters(): Boolean {
|
||||
return !isPaused && (queue.waitingCount() > 0 || isLoading)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun diagnostics(): Diagnostics {
|
||||
return Diagnostics(
|
||||
@@ -579,7 +589,7 @@ class CacheBookModel(
|
||||
return true
|
||||
}
|
||||
}
|
||||
repository.downloadContentTask(
|
||||
val task = repository.downloadContentTask(
|
||||
scope = scope,
|
||||
bookSource = bookSource,
|
||||
book = book,
|
||||
@@ -604,8 +614,13 @@ class CacheBookModel(
|
||||
onCancel(chapter.index, requeue = false)
|
||||
downloadFinish(chapter, "download canceled", resetPageOffset, true)
|
||||
}.onFinally {
|
||||
chapterTasks.remove(chapter.index)
|
||||
host.onTaskQueuesChanged(book.bookUrl)
|
||||
}.start()
|
||||
}
|
||||
task.start()
|
||||
synchronized(this) {
|
||||
chapterTasks[chapter.index] = task
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,21 @@ class CacheDownloadQueue {
|
||||
val indexCount = indices.count {
|
||||
!emittedIndices.contains(it) && !removedIndices.contains(it)
|
||||
}
|
||||
val rangeCount = ranges.sumOf { it.remainingCount(emittedIndices, removedIndices) }
|
||||
val rangeCount = if (ranges.size <= 1) {
|
||||
ranges.sumOf { it.remainingCount(emittedIndices, removedIndices) }
|
||||
} else {
|
||||
val seen = mutableSetOf<Int>()
|
||||
ranges.forEach { cursor ->
|
||||
var i = cursor.next
|
||||
while (i <= cursor.end) {
|
||||
if (!emittedIndices.contains(i) && !removedIndices.contains(i)) {
|
||||
seen.add(i)
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
seen.size
|
||||
}
|
||||
return indexCount + rangeCount
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import io.legado.app.constant.NotificationId
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.help.book.update
|
||||
import io.legado.app.model.CacheBook
|
||||
import io.legado.app.model.CacheBookModel
|
||||
import io.legado.app.model.cache.CacheDownloadAdmissionQueue
|
||||
import io.legado.app.model.cache.CacheDownloadRequest
|
||||
import io.legado.app.model.cache.CacheDownloadSource
|
||||
@@ -24,11 +25,11 @@ import io.legado.app.utils.activityPendingIntent
|
||||
import io.legado.app.utils.servicePendingIntent
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExecutorCoroutineDispatcher
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -310,10 +311,10 @@ class CacheBookService : BaseService() {
|
||||
kotlin.runCatching {
|
||||
WebBook.getBookInfoAwait(cacheBook.bookSource, book)
|
||||
}.onFailure {
|
||||
removeDownload(request.bookUrl)
|
||||
markBookAdmissionFailed(
|
||||
request.bookUrl,
|
||||
getString(R.string.error_get_book_info)
|
||||
getString(R.string.error_get_book_info),
|
||||
model = cacheBook,
|
||||
)
|
||||
AppLog.put(
|
||||
"《$name》目录为空且加载详情页失败\n${it.localizedMessage}",
|
||||
@@ -333,10 +334,10 @@ class CacheBookService : BaseService() {
|
||||
book.totalChapterNum = 0
|
||||
book.update()
|
||||
}
|
||||
removeDownload(request.bookUrl)
|
||||
markBookAdmissionFailed(
|
||||
request.bookUrl,
|
||||
getString(R.string.error_get_chapter_list)
|
||||
getString(R.string.error_get_chapter_list),
|
||||
model = cacheBook,
|
||||
)
|
||||
AppLog.put(
|
||||
"《$name》目录为空且加载目录失败\n${it.localizedMessage}",
|
||||
@@ -408,8 +409,15 @@ class CacheBookService : BaseService() {
|
||||
return removedQueued || removedAdmission || removedActive
|
||||
}
|
||||
|
||||
private fun markBookAdmissionFailed(bookUrl: String, message: String) {
|
||||
private fun markBookAdmissionFailed(
|
||||
bookUrl: String,
|
||||
message: String,
|
||||
model: CacheBookModel? = null,
|
||||
) {
|
||||
removeQueuedBook(bookUrl)
|
||||
if (model != null) {
|
||||
CacheBook.removeModelFromService(bookUrl, model)
|
||||
}
|
||||
CacheBook.markBookFailed(bookUrl, message)
|
||||
}
|
||||
|
||||
@@ -476,15 +484,6 @@ class CacheBookService : BaseService() {
|
||||
}
|
||||
|
||||
|
||||
private fun removeDownload(bookUrl: String?) {
|
||||
CacheBook.cacheBookMap[bookUrl]?.stop()
|
||||
if (CacheBook.isRun) {
|
||||
ensureDownloadJob()
|
||||
return
|
||||
}
|
||||
stopIfIdle()
|
||||
}
|
||||
|
||||
private suspend fun runDownloadLoop() {
|
||||
try {
|
||||
var idleSince = -1L
|
||||
|
||||
Reference in New Issue
Block a user