Minor cleanup of TachideskPageLoader

This commit is contained in:
Syer10
2023-02-02 21:18:44 -05:00
parent ea791a8bf6
commit 51547ae4df

View File

@@ -26,17 +26,21 @@ import com.seiko.imageloader.request.ImageRequestBuilder
import com.seiko.imageloader.request.Options import com.seiko.imageloader.request.Options
import com.seiko.imageloader.request.SourceResult import com.seiko.imageloader.request.SourceResult
import io.ktor.client.plugins.onDownload import io.ktor.client.plugins.onDownload
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.bodyAsChannel import io.ktor.client.statement.bodyAsChannel
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okio.BufferedSource import okio.BufferedSource
@@ -48,7 +52,7 @@ import org.lighthousegames.logging.logging
class TachideskPageLoader( class TachideskPageLoader(
val chapter: ReaderChapter, val chapter: ReaderChapter,
readerPreferences: ReaderPreferences, readerPreferences: ReaderPreferences,
getChapterPage: GetChapterPage, private val getChapterPage: GetChapterPage,
private val chapterCache: DiskCache, private val chapterCache: DiskCache,
private val bitmapDecoderFactory: BitmapDecoderFactory private val bitmapDecoderFactory: BitmapDecoderFactory
) : PageLoader() { ) : PageLoader() {
@@ -75,14 +79,34 @@ class TachideskPageLoader(
} }
init { init {
repeat(readerPreferences.threads().get()) { readerPreferences.threads()
scope.launch { .stateIn(scope)
.mapLatest {
coroutineScope {
repeat(it) {
launch {
while (true) { while (true) {
try { try {
for (priorityPage in channel) { for (priorityPage in channel) {
val page = priorityPage.page val page = priorityPage.page
if (page.status.value == ReaderPage.Status.QUEUE) { if (page.status.value == ReaderPage.Status.QUEUE) {
page.status.value = ReaderPage.Status.WORKING page.status.value = ReaderPage.Status.WORKING
fetchImage(page)
}
}
} catch (e: Exception) {
e.throwIfCancellation()
log.warn(e) { "Error in loop" }
}
}
}
}
}
}
.launchIn(scope)
}
private suspend fun fetchImage(page: ReaderPage) {
log.debug { "Loading page ${page.index}" } log.debug { "Loading page ${page.index}" }
getChapterPage.asFlow(chapter.chapter, page.index) { getChapterPage.asFlow(chapter.chapter, page.index) {
onDownload { bytesSentTotal, contentLength -> onDownload { bytesSentTotal, contentLength ->
@@ -90,11 +114,27 @@ class TachideskPageLoader(
} }
} }
.onEach { .onEach {
putImageInCache(it, page)
page.bitmap.value = StableHolder { getImageFromCache(page) }
page.status.value = ReaderPage.Status.READY
page.error.value = null
}
.catch {
page.bitmap.value = StableHolder(null)
page.status.value = ReaderPage.Status.ERROR
page.error.value = it.message
log.warn(it) { "Failed to get page ${page.index} for chapter ${chapter.chapter.index} for ${chapter.chapter.mangaId}" }
}
.flowOn(Dispatchers.IO)
.collect()
}
private suspend fun putImageInCache(response: HttpResponse, page: ReaderPage) {
val editor = chapterCache.edit(page.cacheKey) val editor = chapterCache.edit(page.cacheKey)
?: throw Exception("Couldn't open cache") ?: throw Exception("Couldn't open cache")
try { try {
FileSystem.SYSTEM.write(editor.data) { FileSystem.SYSTEM.write(editor.data) {
it.bodyAsChannel().toSource().use { response.bodyAsChannel().toSource().use {
writeAll(it) writeAll(it)
} }
} }
@@ -103,8 +143,10 @@ class TachideskPageLoader(
editor.abortQuietly() editor.abortQuietly()
throw e throw e
} }
page.bitmap.value = StableHolder { }
chapterCache[page.cacheKey]?.use {
private suspend fun getImageFromCache(page: ReaderPage): ReaderPage.ImageDecodeState {
return chapterCache[page.cacheKey]?.use {
it.source().use { source -> it.source().use { source ->
val decoder = bitmapDecoderFactory.create( val decoder = bitmapDecoderFactory.create(
SourceResult( SourceResult(
@@ -133,27 +175,6 @@ class TachideskPageLoader(
} }
} ?: ReaderPage.ImageDecodeState.FailedToGetSnapShot } ?: ReaderPage.ImageDecodeState.FailedToGetSnapShot
} }
page.status.value = ReaderPage.Status.READY
page.error.value = null
}
.catch {
page.bitmap.value = StableHolder(null)
page.status.value = ReaderPage.Status.ERROR
page.error.value = it.message
log.warn(it) { "Failed to get page ${page.index} for chapter ${chapter.chapter.index} for ${chapter.chapter.mangaId}" }
}
.flowOn(Dispatchers.IO)
.collect()
}
}
} catch (e: Exception) {
e.throwIfCancellation()
log.warn(e) { "Error in loop" }
}
}
}
}
}
/** /**
* Preloads the given [amount] of pages after the [currentPage] with a lower priority. * Preloads the given [amount] of pages after the [currentPage] with a lower priority.