Avoid hard crash if cached image file was already deleted

Closes #9720

(cherry picked from commit 3ea026e3116a77fd58bf656e1ecdb5e1ab6de28a)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt
This commit is contained in:
arkon 2024-01-06 18:15:17 -05:00 committed by Jobobby04
parent 3e561f7b67
commit bd96864895
2 changed files with 79 additions and 63 deletions

View File

@ -158,55 +158,62 @@ class PagerPageHolder(
val streamFn = page.stream ?: return
val streamFn2 = extraPage?.stream
val (bais, isAnimated, background) = withIOContext {
streamFn().buffered(16).use { stream ->
// SY -->
(
if (extraPage != null) {
streamFn2?.invoke()
?.buffered(16)
} else {
null
}
).use { stream2 ->
if (viewer.config.dualPageSplit) {
process(item.first, stream)
} else {
mergePages(stream, stream2)
}.use { itemStream ->
// SY <--
val bais = ByteArrayInputStream(itemStream.readBytes())
val isAnimated = ImageUtil.isAnimatedAndSupported(bais)
bais.reset()
val background = if (!isAnimated && viewer.config.automaticBackground) {
ImageUtil.chooseBackground(context, bais)
try {
val (bais, isAnimated, background) = withIOContext {
streamFn().buffered(16).use { stream ->
// SY -->
(
if (extraPage != null) {
streamFn2?.invoke()
?.buffered(16)
} else {
null
}
bais.reset()
Triple(bais, isAnimated, background)
).use { stream2 ->
if (viewer.config.dualPageSplit) {
process(item.first, stream)
} else {
mergePages(stream, stream2)
}.use { itemStream ->
// SY <--
val bais = ByteArrayInputStream(itemStream.readBytes())
val isAnimated = ImageUtil.isAnimatedAndSupported(bais)
bais.reset()
val background = if (!isAnimated && viewer.config.automaticBackground) {
ImageUtil.chooseBackground(context, bais)
} else {
null
}
bais.reset()
Triple(bais, isAnimated, background)
}
}
}
}
withUIContext {
bais.use {
setImage(
it,
isAnimated,
Config(
zoomDuration = viewer.config.doubleTapAnimDuration,
minimumScaleType = viewer.config.imageScaleType,
cropBorders = viewer.config.imageCropBorders,
zoomStartPosition = viewer.config.imageZoomType,
landscapeZoom = viewer.config.landscapeZoom,
),
)
if (!isAnimated) {
pageBackground = background
}
}
removeErrorLayout()
}
}
withUIContext {
bais.use {
setImage(
it,
isAnimated,
Config(
zoomDuration = viewer.config.doubleTapAnimDuration,
minimumScaleType = viewer.config.imageScaleType,
cropBorders = viewer.config.imageCropBorders,
zoomStartPosition = viewer.config.imageZoomType,
landscapeZoom = viewer.config.landscapeZoom,
),
)
if (!isAnimated) {
pageBackground = background
}
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e)
withUIContext {
setError()
}
removeErrorLayout()
}
}

View File

@ -23,10 +23,12 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.supervisorScope
import kotlinx.coroutines.suspendCancellableCoroutine
import logcat.LogPriority
import tachiyomi.core.util.lang.launchIO
import tachiyomi.core.util.lang.withIOContext
import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.ImageUtil
import tachiyomi.core.util.system.logcat
import java.io.BufferedInputStream
import java.io.InputStream
@ -184,28 +186,35 @@ class WebtoonPageHolder(
val streamFn = page?.stream ?: return
val (openStream, isAnimated) = withIOContext {
val stream = streamFn().buffered(16)
val openStream = process(stream)
try {
val (openStream, isAnimated) = withIOContext {
val stream = streamFn().buffered(16)
val openStream = process(stream)
val isAnimated = ImageUtil.isAnimatedAndSupported(stream)
Pair(openStream, isAnimated)
}
withUIContext {
frame.setImage(
openStream,
isAnimated,
ReaderPageImageView.Config(
zoomDuration = viewer.config.doubleTapAnimDuration,
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_FIT_WIDTH,
cropBorders = (viewer.config.imageCropBorders && viewer.isContinuous) || (viewer.config.continuousCropBorders && !viewer.isContinuous),
),
)
removeErrorLayout()
}
// Suspend the coroutine to close the input stream only when the WebtoonPageHolder is recycled
suspendCancellableCoroutine<Nothing> { continuation ->
continuation.invokeOnCancellation { openStream.close() }
val isAnimated = ImageUtil.isAnimatedAndSupported(stream)
Pair(openStream, isAnimated)
}
withUIContext {
frame.setImage(
openStream,
isAnimated,
ReaderPageImageView.Config(
zoomDuration = viewer.config.doubleTapAnimDuration,
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_FIT_WIDTH,
cropBorders = (viewer.config.imageCropBorders && viewer.isContinuous) || (viewer.config.continuousCropBorders && !viewer.isContinuous),
),
)
removeErrorLayout()
}
// Suspend the coroutine to close the input stream only when the WebtoonPageHolder is recycled
suspendCancellableCoroutine<Nothing> { continuation ->
continuation.invokeOnCancellation { openStream.close() }
}
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e)
withUIContext {
setError()
}
}
}