From 6f59c6c6bb12f1ef123abd418001c7a86d43ef7a Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 7 May 2023 12:03:58 -0400 Subject: [PATCH] Revert attempts to read archives to cache first Issues: - Apache implementation relies on methods unavailable on lower Android API levels - Using input stream implementation doesn't seem to read some files properly, but using ZipFile implementation still requires reading the entire thing into memory --- app/build.gradle.kts | 1 - app/proguard-rules.pro | 3 - .../ui/reader/loader/RarPageLoader.kt | 43 +++++++------- .../ui/reader/loader/ZipPageLoader.kt | 56 +++++++++---------- gradle/libs.versions.toml | 1 - 5 files changed, 44 insertions(+), 60 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6620b74541..282b293241 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -210,7 +210,6 @@ dependencies { // Disk implementation(libs.disklrucache) implementation(libs.unifile) - implementation(libs.compress) implementation(libs.junrar) // Preferences diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 58603160a9..e8f9b52202 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -71,9 +71,6 @@ # XmlUtil -keep public enum nl.adaptivity.xmlutil.EventType { *; } -# org.apache.commons:commons-compress --keep,allowoptimization class org.apache.commons.compress.archivers.zip.** - # Firebase -keep class com.google.firebase.installations.** { *; } -keep interface com.google.firebase.installations.** { *; } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt index 7231a45a03..056319d4e6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt @@ -1,10 +1,11 @@ package eu.kanade.tachiyomi.ui.reader.loader -import android.app.Application import com.github.junrar.Archive import com.github.junrar.rarfile.FileHeader +import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.ui.reader.model.ReaderPage -import uy.kohesive.injekt.injectLazy +import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder +import tachiyomi.core.util.system.ImageUtil import java.io.File import java.io.InputStream import java.io.PipedInputStream @@ -15,36 +16,30 @@ import java.io.PipedOutputStream */ internal class RarPageLoader(file: File) : PageLoader() { - private val context: Application by injectLazy() - private val tmpDir = File(context.externalCacheDir, "reader_${file.hashCode()}").also { - it.deleteRecursively() - it.mkdirs() - } - - init { - Archive(file).use { rar -> - rar.fileHeaders.asSequence() - .filterNot { it.isDirectory } - .forEach { header -> - val pageOutputStream = File(tmpDir, header.fileName.substringAfterLast("/")) - .also { it.createNewFile() } - .outputStream() - getStream(rar, header).use { - it.copyTo(pageOutputStream) - } - } - } - } + private val rar = Archive(file) override var isLocal: Boolean = true override suspend fun getPages(): List { - return DirectoryPageLoader(tmpDir).getPages() + return rar.fileHeaders.asSequence() + .filter { !it.isDirectory && ImageUtil.isImage(it.fileName) { rar.getInputStream(it) } } + .sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) } + .mapIndexed { i, header -> + ReaderPage(i).apply { + stream = { getStream(rar, header) } + status = Page.State.READY + } + } + .toList() + } + + override suspend fun loadPage(page: ReaderPage) { + check(!isRecycled) } override fun recycle() { super.recycle() - tmpDir.deleteRecursively() + rar.close() } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt index c10552b4ee..e04fe78e6a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt @@ -1,52 +1,46 @@ package eu.kanade.tachiyomi.ui.reader.loader -import android.app.Application +import android.os.Build +import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.ui.reader.model.ReaderPage -import org.apache.commons.compress.archivers.zip.ZipFile -import org.apache.commons.compress.utils.SeekableInMemoryByteChannel -import uy.kohesive.injekt.injectLazy -import java.io.ByteArrayOutputStream +import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder +import tachiyomi.core.util.system.ImageUtil import java.io.File -import java.io.FileInputStream +import java.nio.charset.StandardCharsets +import java.util.zip.ZipFile /** * Loader used to load a chapter from a .zip or .cbz file. */ internal class ZipPageLoader(file: File) : PageLoader() { - private val context: Application by injectLazy() - private val tmpDir = File(context.externalCacheDir, "reader_${file.hashCode()}").also { - it.deleteRecursively() - it.mkdirs() - } - - init { - ByteArrayOutputStream().use { byteArrayOutputStream -> - FileInputStream(file).use { it.copyTo(byteArrayOutputStream) } - - ZipFile(SeekableInMemoryByteChannel(byteArrayOutputStream.toByteArray())).use { zip -> - zip.entries.asSequence() - .filterNot { it.isDirectory } - .forEach { entry -> - File(tmpDir, entry.name.substringAfterLast("/")) - .also { it.createNewFile() } - .outputStream().use { pageOutputStream -> - zip.getInputStream(entry).copyTo(pageOutputStream) - pageOutputStream.flush() - } - } - } - } + private val zip = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + ZipFile(file, StandardCharsets.ISO_8859_1) + } else { + ZipFile(file) } override var isLocal: Boolean = true override suspend fun getPages(): List { - return DirectoryPageLoader(tmpDir).getPages() + return zip.entries().asSequence() + .filter { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } } + .sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) } + .mapIndexed { i, entry -> + ReaderPage(i).apply { + stream = { zip.getInputStream(entry) } + status = Page.State.READY + } + } + .toList() + } + + override suspend fun loadPage(page: ReaderPage) { + check(!isRecycled) } override fun recycle() { super.recycle() - tmpDir.deleteRecursively() + zip.close() } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 77aeddad09..477839884d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,7 +32,6 @@ jsoup = "org.jsoup:jsoup:1.16.1" disklrucache = "com.jakewharton:disklrucache:2.0.2" unifile = "com.github.tachiyomiorg:unifile:17bec43" -compress = "org.apache.commons:commons-compress:1.23.0" junrar = "com.github.junrar:junrar:7.5.4" sqlite-framework = { module = "androidx.sqlite:sqlite-framework", version.ref = "sqlite" }