[优化] 下载优化

This commit is contained in:
HapeLee
2026-04-30 13:07:58 +08:00
parent 849943b787
commit 5ddaa70f67
3 changed files with 55 additions and 7 deletions
@@ -55,6 +55,7 @@ class CacheBookModel(
private val onDownloadSet = linkedSetOf<Int>()
private val canceledDownloadSet = hashSetOf<Int>()
private val pausedChapterSet = linkedSetOf<Int>()
private val pendingReadRequestMap = hashMapOf<Int, Boolean>()
private val chapterTasks = hashMapOf<Int, Coroutine<*>>()
private val tasks = CompositeCoroutine()
private val repository = CacheDownloadRepository()
@@ -197,6 +198,7 @@ class CacheBookModel(
canceledDownloadSet.clear()
pausedChapterSet.clear()
chapterTasks.clear()
pendingReadRequestMap.clear()
tasks.clear()
retryCountMap.clear()
isStopped = true
@@ -492,12 +494,17 @@ class CacheBookModel(
) {
task.onSuccess {
onSuccess(chapter)
(it as? String)?.let { content ->
emitPendingReadContent(chapter, content)
}
}.onError {
onPreError(chapter, it)
delay(1000)
onPostError(chapter, it)
emitPendingReadError(chapter, it)
}.onCancel {
onCancel(chapterIndex)
emitPendingReadCanceled(chapter)
}.onFinally {
chapterTasks.remove(chapterIndex)?.let { tasks.delete(it) }
onFinally()
@@ -536,7 +543,10 @@ class CacheBookModel(
semaphore: Semaphore?,
resetPageOffset: Boolean = false
) {
if (!markChapterDownloadStarted(chapter.index)) return
if (!markChapterDownloadStarted(chapter.index)) {
markPendingReadRequest(chapter.index, resetPageOffset)
return
}
repository.downloadContentTask(
scope = scope,
bookSource = bookSource,
@@ -551,11 +561,13 @@ class CacheBookModel(
ReadBook.downloadedChapters.add(chapter.index)
ReadBook.downloadFailChapters.remove(chapter.index)
downloadFinish(chapter, content, resetPageOffset)
emitPendingReadContent(chapter, content)
}.onError {
onError(chapter, it)
ReadBook.downloadFailChapters[chapter.index] =
(ReadBook.downloadFailChapters[chapter.index] ?: 0) + 1
downloadFinish(chapter, "获取正文失败\n${it.localizedMessage}", resetPageOffset)
emitPendingReadError(chapter, it)
}.onCancel {
onCancel(chapter.index, requeue = false)
downloadFinish(chapter, "download canceled", resetPageOffset, true)
@@ -573,6 +585,31 @@ class CacheBookModel(
return true
}
@Synchronized
private fun markPendingReadRequest(index: Int, resetPageOffset: Boolean) {
pendingReadRequestMap[index] = pendingReadRequestMap[index] == true || resetPageOffset
}
@Synchronized
private fun consumePendingReadRequest(index: Int): Boolean? {
return pendingReadRequestMap.remove(index)
}
private fun emitPendingReadContent(chapter: BookChapter, content: String) {
val resetPageOffset = consumePendingReadRequest(chapter.index) ?: return
downloadFinish(chapter, content, resetPageOffset)
}
private fun emitPendingReadError(chapter: BookChapter, error: Throwable) {
val resetPageOffset = consumePendingReadRequest(chapter.index) ?: return
downloadFinish(chapter, "获取正文失败\n${error.localizedMessage}", resetPageOffset)
}
private fun emitPendingReadCanceled(chapter: BookChapter) {
val resetPageOffset = consumePendingReadRequest(chapter.index) ?: return
downloadFinish(chapter, "download canceled", resetPageOffset)
}
private fun downloadFinish(
chapter: BookChapter,
content: String,
@@ -71,7 +71,7 @@ class CacheDownloadRepository {
context: CoroutineContext,
start: CoroutineStart = CoroutineStart.LAZY,
executeContext: CoroutineContext = context,
): Coroutine<Unit> {
): Coroutine<String> {
return Coroutine.async(
scope = scope,
context = context,
@@ -126,15 +126,17 @@ class SearchViewModel(
}
SearchIntent.SelectAllScope -> {
val oldScope = searchScope.toString()
searchScope.update("")
syncScopeState()
syncScopeState(restartSearch = true, oldScope = oldScope)
}
is SearchIntent.ToggleScopeGroup -> toggleScopeGroup(intent.groupName)
is SearchIntent.ToggleScopeSource -> toggleScopeSource(intent.source)
is SearchIntent.RemoveScopeItem -> {
val oldScope = searchScope.toString()
searchScope.remove(intent.scopeName)
syncScopeState()
syncScopeState(restartSearch = true, oldScope = oldScope)
}
is SearchIntent.TogglePrecision -> {
@@ -370,6 +372,7 @@ class SearchViewModel(
}
private fun toggleScopeGroup(groupName: String) {
val oldScope = searchScope.toString()
if (searchScope.isSource()) {
searchScope.update("")
}
@@ -380,10 +383,11 @@ class SearchViewModel(
selected.add(groupName)
}
searchScope.update(selected.toList())
syncScopeState()
syncScopeState(restartSearch = true, oldScope = oldScope)
}
private fun toggleScopeSource(source: BookSourcePart) {
val oldScope = searchScope.toString()
val selectedUrls = if (searchScope.isSource()) {
searchScope.sourceUrls.toMutableSet()
} else {
@@ -404,7 +408,7 @@ class SearchViewModel(
}
searchScope.updateSources(selectedSources)
}
syncScopeState()
syncScopeState(restartSearch = true, oldScope = oldScope)
}
private fun handleEmptyScopeActionConfirmed() {
@@ -429,7 +433,11 @@ class SearchViewModel(
}
}
private fun syncScopeState() {
private fun syncScopeState(
restartSearch: Boolean = false,
oldScope: String? = null,
) {
val scopeChanged = oldScope == null || oldScope != searchScope.toString()
_uiState.update {
it.copy(
scopeDisplay = searchScope.display,
@@ -439,6 +447,9 @@ class SearchViewModel(
isSourceScope = searchScope.isSource(),
)
}
if (restartSearch && scopeChanged) {
restartCommittedSearchIfNeeded()
}
}
private fun List<SearchBook>.toSearchResultItems(