refactor(downloader/split): Use UniFile to split tall images

Hopefully will improve stability
This commit is contained in:
Ahmad Ansori Palembani 2024-08-12 07:17:58 +07:00
parent 5ac816225f
commit d19aca3e0b
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
2 changed files with 26 additions and 29 deletions

View file

@ -55,6 +55,7 @@ import yokai.domain.download.DownloadPreferences
import yokai.i18n.MR
import yokai.util.lang.getString
import java.io.File
import java.util.*
import java.util.zip.*
/**
@ -540,23 +541,20 @@ class Downloader(
return ImageUtil.getExtensionFromMimeType(mime) { file.openInputStream() }
}
private fun splitTallImageIfNeeded(page: Page, tmpDir: UniFile): Boolean {
if (!preferences.splitTallImages().get()) return true
private fun splitTallImageIfNeeded(page: Page, tmpDir: UniFile) {
if (!preferences.splitTallImages().get()) return
val filename = String.format("%03d", page.number)
val imageFile = tmpDir.listFiles()?.find { it.name.orEmpty().startsWith(filename) }
?: throw Error(context.getString(MR.strings.download_notifier_split_page_not_found, page.number))
val imageFilePath = imageFile.filePath
?: throw Error(context.getString(MR.strings.download_notifier_split_page_not_found, page.number))
try {
val fileName = "%03d".format(Locale.ENGLISH, page.number)
val imageFile = tmpDir.listFiles()?.firstOrNull { it.name.orEmpty().startsWith(fileName) }
?: throw Error(context.getString(MR.strings.download_notifier_split_page_not_found, page.number))
// check if the original page was previously split before then skip.
if (imageFile.name.orEmpty().contains("__")) return true
// Check if the original page was previously split before then skip.
if (imageFile.name.orEmpty().startsWith("${fileName}__")) return
return try {
ImageUtil.splitTallImage(imageFile, imageFilePath)
ImageUtil.splitTallImage(tmpDir, imageFile, fileName)
} catch (e: Exception) {
Logger.e(e)
false
Logger.e(e) { "Failed to split downloaded image"}
}
}
@ -582,7 +580,7 @@ class Downloader(
val downloadedImagesCount = tmpDir.listFiles().orEmpty().count {
val fileName = it.name.orEmpty()
when {
fileName in listOf(/*COMIC_INFO_FILE, */NOMEDIA_FILE) -> false
fileName in listOf(COMIC_INFO_FILE, NOMEDIA_FILE) -> false
fileName.endsWith(".tmp") -> false
// Only count the first split page and not the others
fileName.contains("__") && !fileName.endsWith("__001.jpg") -> false

View file

@ -15,7 +15,6 @@ import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.webkit.MimeTypeMap
import androidx.annotation.ColorInt
import androidx.core.graphics.ColorUtils
import androidx.core.graphics.alpha
@ -26,17 +25,12 @@ import androidx.core.graphics.scale
import co.touchlab.kermit.Logger
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.R
import yokai.i18n.MR
import yokai.util.lang.getString
import dev.icerock.moko.resources.compose.stringResource
import okio.Buffer
import okio.BufferedSource
import tachiyomi.decoder.Format
import tachiyomi.decoder.ImageDecoder
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.net.URLConnection
import java.util.*
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
@ -539,7 +533,7 @@ object ImageUtil {
/**
* Splits tall images to improve performance of reader
*/
fun splitTallImage(imageFile: UniFile, imageFilePath: String): Boolean {
fun splitTallImage(tmpDir: UniFile, imageFile: UniFile, fileName: String): Boolean {
val imageSource = imageFile.openInputStream().use { Buffer().readFrom(it) }
if (isAnimatedAndSupported(imageSource) || !isTallImage(imageSource)) {
return true
@ -564,17 +558,22 @@ object ImageUtil {
return try {
splitDataList.forEach { splitData ->
val splitPath = splitImagePath(imageFilePath, splitData.index)
val splitImageName = splitImageName(fileName, splitData.index)
// Remove pre-existing split if exists (this split shouldn't exist under normal circumstances)
tmpDir.findFile(splitImageName)?.delete()
val splitFile = tmpDir.createFile(splitImageName)!!
val region = Rect(0, splitData.topOffset, splitData.splitWidth, splitData.bottomOffset)
FileOutputStream(splitPath).use { outputStream ->
splitFile.openOutputStream().use { outputStream ->
val splitBitmap = bitmapRegionDecoder.decodeRegion(region, options)
splitBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
splitBitmap.recycle()
}
Logger.d {
"Success: Split #${splitData.index + 1} with topOffset=${splitData.topOffset} height=${splitData.splitHeight} bottomOffset=${splitData.bottomOffset}"
"Success: Split #${splitData.index + 1} with topOffset=${splitData.topOffset} " +
"height=${splitData.splitHeight} bottomOffset=${splitData.bottomOffset}"
}
}
imageFile.delete()
@ -582,8 +581,8 @@ object ImageUtil {
} catch (e: Exception) {
// Image splits were not successfully saved so delete them and keep the original image
splitDataList
.map { splitImagePath(imageFilePath, it.index) }
.forEach { File(it).delete() }
.map { splitImageName(fileName, it.index) }
.forEach { tmpDir.findFile(it)?.delete() }
Logger.e(e)
false
} finally {
@ -591,8 +590,8 @@ object ImageUtil {
}
}
private fun splitImagePath(imageFilePath: String, index: Int) =
imageFilePath.substringBeforeLast(".") + "__${"%03d".format(index + 1)}.jpg"
private fun splitImageName(fileName: String, index: Int) =
"${fileName}__${"%03d".format(Locale.ENGLISH, index + 1)}.jpg"
private val BitmapFactory.Options.splitData
get(): List<SplitData> {