Prechádzať zdrojové kódy

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
arkon 1 rok pred
rodič
commit
6f59c6c6bb

+ 0 - 1
app/build.gradle.kts

@@ -210,7 +210,6 @@ dependencies {
     // Disk
     implementation(libs.disklrucache)
     implementation(libs.unifile)
-    implementation(libs.compress)
     implementation(libs.junrar)
 
     // Preferences

+ 0 - 3
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.** { *; }

+ 19 - 24
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<ReaderPage> {
-        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()
     }
 
     /**

+ 24 - 30
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()
+    private val zip = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+        ZipFile(file, StandardCharsets.ISO_8859_1)
+    } else {
+        ZipFile(file)
     }
 
-    init {
-        ByteArrayOutputStream().use { byteArrayOutputStream ->
-            FileInputStream(file).use { it.copyTo(byteArrayOutputStream) }
+    override var isLocal: Boolean = true
 
-            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()
-                            }
-                    }
+    override suspend fun getPages(): List<ReaderPage> {
+        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 var isLocal: Boolean = true
-
-    override suspend fun getPages(): List<ReaderPage> {
-        return DirectoryPageLoader(tmpDir).getPages()
+    override suspend fun loadPage(page: ReaderPage) {
+        check(!isRecycled)
     }
 
     override fun recycle() {
         super.recycle()
-        tmpDir.deleteRecursively()
+        zip.close()
     }
 }

+ 0 - 1
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" }