下载优化

This commit is contained in:
HapeLee
2026-05-16 01:14:26 +08:00
parent d5ece78383
commit 59afc9dd94
4 changed files with 47 additions and 19 deletions
@@ -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