mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-22 04:22:32 +01:00
Minor cleanup of TachideskPageLoader
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user