Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor archive support with libarchive #949

Merged
merged 8 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ dependencies {
// Disk
implementation(libs.disklrucache)
implementation(libs.unifile)
implementation(libs.bundles.archive)

// Preferences
implementation(libs.preferencektx)
Expand Down
3 changes: 0 additions & 3 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,6 @@
# XmlUtil
-keep public enum nl.adaptivity.xmlutil.EventType { *; }

# Apache Commons Compress
-keep class * extends org.apache.commons.compress.archivers.zip.ZipExtraField { <init>(); }

# Firebase
-keep class com.google.firebase.installations.** { *; }
-keep interface com.google.firebase.installations.** { *; }
25 changes: 3 additions & 22 deletions app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import kotlinx.coroutines.supervisorScope
import logcat.LogPriority
import nl.adaptivity.xmlutil.serialization.XML
import okhttp3.Response
import tachiyomi.core.common.archive.ZipWriter
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.core.common.storage.extension
import tachiyomi.core.common.util.lang.launchIO
Expand All @@ -58,12 +59,8 @@ import tachiyomi.domain.track.interactor.GetTracks
import tachiyomi.i18n.MR
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.BufferedOutputStream
import java.io.File
import java.util.Locale
import java.util.zip.CRC32
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream

/**
* This class is the one in charge of downloading chapters.
Expand Down Expand Up @@ -594,25 +591,9 @@ class Downloader(
tmpDir: UniFile,
) {
val zip = mangaDir.createFile("$dirname.cbz$TMP_DIR_SUFFIX")!!
ZipOutputStream(BufferedOutputStream(zip.openOutputStream())).use { zipOut ->
zipOut.setMethod(ZipEntry.STORED)

ZipWriter(context, zip).use { writer ->
tmpDir.listFiles()?.forEach { img ->
AntsyLich marked this conversation as resolved.
Show resolved Hide resolved
img.openInputStream().use { input ->
val data = input.readBytes()
val size = img.length()
val entry = ZipEntry(img.name).apply {
val crc = CRC32().apply {
update(data)
}
setCrc(crc.value)

compressedSize = size
setSize(size)
}
zipOut.putNextEntry(entry)
zipOut.write(data)
}
writer.write(img)
}
}
zip.renameTo("$dirname.cbz")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package eu.kanade.tachiyomi.ui.reader.loader

import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
import tachiyomi.core.common.archive.ArchiveReader
import tachiyomi.core.common.util.system.ImageUtil

/**
* Loader used to load a chapter from an archive file.
*/
internal class ArchivePageLoader(private val reader: ArchiveReader) : PageLoader() {
override var isLocal: Boolean = true

override suspend fun getPages(): List<ReaderPage> =
reader.useEntries { entries ->
entries
.filter { it.isFile && ImageUtil.isImage(it.name) { reader.getInputStream(it.name)!! } }
.sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }
.mapIndexed { i, entry ->
ReaderPage(i).apply {
stream = { reader.getInputStream(entry.name)!! }
status = Page.State.READY
}
}.toList()
}
AntsyLich marked this conversation as resolved.
Show resolved Hide resolved

override suspend fun loadPage(page: ReaderPage) {
check(!isRecycled)
}

override fun recycle() {
super.recycle()
reader.close()
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package eu.kanade.tachiyomi.ui.reader.loader

import android.content.Context
import com.github.junrar.exception.UnsupportedRarV5Exception
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadProvider
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
import tachiyomi.core.common.archive.archiveReader
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.core.common.storage.openReadOnlyChannel
import tachiyomi.core.common.util.lang.withIOContext
import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.manga.model.Manga
Expand Down Expand Up @@ -95,13 +94,8 @@ class ChapterLoader(
source is LocalSource -> source.getFormat(chapter.chapter).let { format ->
when (format) {
is Format.Directory -> DirectoryPageLoader(format.file)
is Format.Zip -> ZipPageLoader(format.file.openReadOnlyChannel(context))
is Format.Rar -> try {
RarPageLoader(format.file.openInputStream())
} catch (e: UnsupportedRarV5Exception) {
error(context.stringResource(MR.strings.loader_rar5_error))
}
is Format.Epub -> EpubPageLoader(format.file.openReadOnlyChannel(context))
is Format.Archive -> ArchivePageLoader(format.file.archiveReader(context))
is Format.Epub -> EpubPageLoader(format.file.archiveReader(context))
}
}
source is HttpSource -> HttpPageLoader(chapter, source)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
import tachiyomi.core.common.storage.openReadOnlyChannel
import tachiyomi.core.common.archive.archiveReader
import tachiyomi.domain.manga.model.Manga
import uy.kohesive.injekt.injectLazy

Expand All @@ -27,7 +27,7 @@ internal class DownloadPageLoader(

private val context: Application by injectLazy()

private var zipPageLoader: ZipPageLoader? = null
private var archivePageLoader: ArchivePageLoader? = null

override var isLocal: Boolean = true

Expand All @@ -43,11 +43,11 @@ internal class DownloadPageLoader(

override fun recycle() {
super.recycle()
zipPageLoader?.recycle()
archivePageLoader?.recycle()
}

private suspend fun getPagesFromArchive(file: UniFile): List<ReaderPage> {
val loader = ZipPageLoader(file.openReadOnlyChannel(context)).also { zipPageLoader = it }
val loader = ArchivePageLoader(file.archiveReader(context)).also { archivePageLoader = it }
return loader.getPages()
}

Expand All @@ -63,6 +63,6 @@ internal class DownloadPageLoader(
}

override suspend fun loadPage(page: ReaderPage) {
zipPageLoader?.loadPage(page)
archivePageLoader?.loadPage(page)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@ package eu.kanade.tachiyomi.ui.reader.loader
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
import eu.kanade.tachiyomi.util.storage.EpubFile
import java.nio.channels.SeekableByteChannel
import tachiyomi.core.common.archive.ArchiveReader

/**
* Loader used to load a chapter from a .epub file.
*/
internal class EpubPageLoader(channel: SeekableByteChannel) : PageLoader() {
internal class EpubPageLoader(reader: ArchiveReader) : PageLoader() {

private val epub = EpubFile(channel)
private val epub = EpubFile(reader)

override var isLocal: Boolean = true

override suspend fun getPages(): List<ReaderPage> {
return epub.getImagesFromPages()
.mapIndexed { i, path ->
val streamFn = { epub.getInputStream(epub.getEntry(path)!!) }
val streamFn = { epub.getInputStream(path)!! }
ReaderPage(i).apply {
stream = streamFn
status = Page.State.READY
Expand Down

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion core/common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ dependencies {
implementation(libs.image.decoder)

implementation(libs.unifile)
implementation(libs.bundles.archive)
implementation(libs.libarchive)

api(kotlinx.coroutines.core)
api(kotlinx.serialization.json)
Expand Down
Loading