From b4377a46099167358b67fd503ab288124ddd3932 Mon Sep 17 00:00:00 2001 From: Ahmad Ansori Palembani Date: Wed, 1 Jan 2025 09:26:15 +0700 Subject: [PATCH] refactor: Move archive related code to core.archive module --- app/build.gradle.kts | 1 + .../eu/kanade/tachiyomi/source/LocalSource.kt | 10 +++++----- .../ui/reader/loader/ChapterLoader.kt | 5 +++-- .../ui/reader/loader/DownloadPageLoader.kt | 2 +- .../ui/reader/loader/EpubPageLoader.kt | 10 ++-------- .../EpubFile.kt => yokai/util/EpubReader.kt} | 7 ++++--- core/archive/build.gradle.kts | 15 +++++++++++++++ core/archive/src/main/AndroidManifest.xml | 2 ++ .../java}/yokai/core/archive/ArchiveEntry.kt | 0 .../yokai/core/archive/ArchiveInputStream.kt} | 3 ++- .../java/yokai/core/archive/ArchiveReader.kt} | 18 +++++++----------- .../java/yokai/core/archive/EpubReader.kt} | 5 ++--- .../main/java}/yokai/core/archive/ZipWriter.kt | 2 +- .../core/archive/util/UniFileExtensions.kt | 14 ++++++++++++++ core/main/build.gradle.kts | 2 +- .../tachiyomi/util/system/UniFileExtensions.kt | 4 ---- .../yokai/core/archive/ArchiveInputStream.kt | 6 ------ .../kotlin/yokai/core/archive/ArchiveReader.kt | 9 --------- settings.gradle.kts | 1 + 19 files changed, 61 insertions(+), 55 deletions(-) rename app/src/main/java/{eu/kanade/tachiyomi/util/storage/EpubFile.kt => yokai/util/EpubReader.kt} (90%) create mode 100644 core/archive/build.gradle.kts create mode 100644 core/archive/src/main/AndroidManifest.xml rename core/{main/src/androidMain/kotlin => archive/src/main/java}/yokai/core/archive/ArchiveEntry.kt (100%) rename core/{main/src/androidMain/kotlin/yokai/core/archive/AndroidArchiveInputStream.kt => archive/src/main/java/yokai/core/archive/ArchiveInputStream.kt} (94%) rename core/{main/src/androidMain/kotlin/yokai/core/archive/AndroidArchiveReader.kt => archive/src/main/java/yokai/core/archive/ArchiveReader.kt} (55%) rename core/{main/src/androidMain/kotlin/eu/kanade/tachiyomi/util/storage/EpubFile.kt => archive/src/main/java/yokai/core/archive/EpubReader.kt} (96%) rename core/{main/src/androidMain/kotlin => archive/src/main/java}/yokai/core/archive/ZipWriter.kt (97%) create mode 100644 core/archive/src/main/java/yokai/core/archive/util/UniFileExtensions.kt delete mode 100644 core/main/src/androidMain/kotlin/yokai/core/archive/ArchiveInputStream.kt delete mode 100644 core/main/src/androidMain/kotlin/yokai/core/archive/ArchiveReader.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1750bffd4e..75a95ee35e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -144,6 +144,7 @@ android { } dependencies { + implementation(projects.core.archive) implementation(projects.core.main) implementation(projects.data) implementation(projects.domain) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt index f7040a5c66..e8e9510f61 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt @@ -12,8 +12,6 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder import eu.kanade.tachiyomi.util.storage.DiskUtil -import eu.kanade.tachiyomi.util.storage.EpubFile -import eu.kanade.tachiyomi.util.storage.fillMetadata import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.extension import eu.kanade.tachiyomi.util.system.nameWithoutExtension @@ -33,7 +31,8 @@ import nl.adaptivity.xmlutil.serialization.XML import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy -import yokai.core.archive.archiveReader +import yokai.core.archive.util.archiveReader +import yokai.core.archive.util.epubReader import yokai.core.metadata.COMIC_INFO_FILE import yokai.core.metadata.ComicInfo import yokai.core.metadata.copyFromComicInfo @@ -42,6 +41,7 @@ import yokai.domain.chapter.services.ChapterRecognition import yokai.domain.source.SourcePreferences import yokai.domain.storage.StorageManager import yokai.i18n.MR +import yokai.util.fillMetadata import yokai.util.lang.getString class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSource { @@ -410,7 +410,7 @@ class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSour } } is Format.Epub -> { - EpubFile(format.file.archiveReader(context)).use { epub -> + format.file.epubReader(context).use { epub -> val entry = epub.getImagesFromPages().firstOrNull() entry?.let { updateCover(manga, epub.getInputStream(it)!!, context) } @@ -433,7 +433,7 @@ class LocalSource(private val context: Context) : CatalogueSource, UnmeteredSour true } is Format.Epub -> { - EpubFile(format.file.archiveReader(context)).use { epub -> + format.file.epubReader(context).use { epub -> epub.fillMetadata(chapter, manga) } true diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt index 7756cdd585..44f89294e9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt @@ -10,7 +10,8 @@ import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.util.system.withIOContext -import yokai.core.archive.archiveReader +import yokai.core.archive.util.archiveReader +import yokai.core.archive.util.epubReader import yokai.i18n.MR import yokai.util.lang.getString @@ -82,7 +83,7 @@ class ChapterLoader( when (format) { is LocalSource.Format.Directory -> DirectoryPageLoader(format.file) is LocalSource.Format.Archive -> ArchivePageLoader(format.file.archiveReader(context)) - is LocalSource.Format.Epub -> EpubPageLoader(format.file.archiveReader(context)) + is LocalSource.Format.Epub -> EpubPageLoader(format.file.epubReader(context)) } } else -> error(context.getString(MR.strings.source_not_installed)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt index 6535ce9847..254db17580 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt @@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import uy.kohesive.injekt.injectLazy -import yokai.core.archive.archiveReader +import yokai.core.archive.util.archiveReader /** * Loader used to load a chapter from the downloaded chapters. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt index 0823453d1c..77c782e87e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt @@ -2,21 +2,15 @@ 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 yokai.core.archive.ArchiveReader +import yokai.core.archive.EpubReader /** * Loader used to load a chapter from a .epub file. */ -class EpubPageLoader(reader: ArchiveReader) : PageLoader() { +class EpubPageLoader(private val epub: EpubReader) : PageLoader() { override val isLocal: Boolean = true - /** - * The epub file. - */ - private val epub = EpubFile(reader) - /** * Recycles this loader and the open zip. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt b/app/src/main/java/yokai/util/EpubReader.kt similarity index 90% rename from app/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt rename to app/src/main/java/yokai/util/EpubReader.kt index 54c9a3ebd6..2c0869aff4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt +++ b/app/src/main/java/yokai/util/EpubReader.kt @@ -1,15 +1,16 @@ -package eu.kanade.tachiyomi.util.storage +package yokai.util import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import java.text.ParseException import java.text.SimpleDateFormat -import java.util.* +import java.util.Locale +import yokai.core.archive.EpubReader /** * Fills manga and chapter metadata using this epub file's metadata. */ -fun EpubFile.fillMetadata(chapter: SChapter, manga: SManga) { +fun EpubReader.fillMetadata(chapter: SChapter, manga: SManga) { val ref = getPackageHref() val doc = getPackageDocument(ref) diff --git a/core/archive/build.gradle.kts b/core/archive/build.gradle.kts new file mode 100644 index 0000000000..e44e620ed5 --- /dev/null +++ b/core/archive/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("yokai.android.library") + kotlin("android") + alias(kotlinx.plugins.serialization) +} + +android { + namespace = "yokai.core.archive" +} + +dependencies { + implementation(libs.jsoup) + implementation(libs.libarchive) + implementation(libs.unifile) +} diff --git a/core/archive/src/main/AndroidManifest.xml b/core/archive/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..8072ee00db --- /dev/null +++ b/core/archive/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/core/main/src/androidMain/kotlin/yokai/core/archive/ArchiveEntry.kt b/core/archive/src/main/java/yokai/core/archive/ArchiveEntry.kt similarity index 100% rename from core/main/src/androidMain/kotlin/yokai/core/archive/ArchiveEntry.kt rename to core/archive/src/main/java/yokai/core/archive/ArchiveEntry.kt diff --git a/core/main/src/androidMain/kotlin/yokai/core/archive/AndroidArchiveInputStream.kt b/core/archive/src/main/java/yokai/core/archive/ArchiveInputStream.kt similarity index 94% rename from core/main/src/androidMain/kotlin/yokai/core/archive/AndroidArchiveInputStream.kt rename to core/archive/src/main/java/yokai/core/archive/ArchiveInputStream.kt index abe8da941b..5cd17aa026 100644 --- a/core/main/src/androidMain/kotlin/yokai/core/archive/AndroidArchiveInputStream.kt +++ b/core/archive/src/main/java/yokai/core/archive/ArchiveInputStream.kt @@ -1,12 +1,13 @@ package yokai.core.archive +import java.io.InputStream import java.nio.ByteBuffer import kotlin.concurrent.Volatile import me.zhanghai.android.libarchive.Archive import me.zhanghai.android.libarchive.ArchiveEntry import me.zhanghai.android.libarchive.ArchiveException -class AndroidArchiveInputStream(buffer: Long, size: Long) : ArchiveInputStream() { +class ArchiveInputStream(buffer: Long, size: Long) : InputStream() { private val lock = Any() @Volatile private var isClosed = false diff --git a/core/main/src/androidMain/kotlin/yokai/core/archive/AndroidArchiveReader.kt b/core/archive/src/main/java/yokai/core/archive/ArchiveReader.kt similarity index 55% rename from core/main/src/androidMain/kotlin/yokai/core/archive/AndroidArchiveReader.kt rename to core/archive/src/main/java/yokai/core/archive/ArchiveReader.kt index aee82a81fb..97584cc08f 100644 --- a/core/main/src/androidMain/kotlin/yokai/core/archive/AndroidArchiveReader.kt +++ b/core/archive/src/main/java/yokai/core/archive/ArchiveReader.kt @@ -1,23 +1,22 @@ package yokai.core.archive -import android.content.Context import android.os.ParcelFileDescriptor import android.system.Os import android.system.OsConstants -import com.hippo.unifile.UniFile -import eu.kanade.tachiyomi.util.system.openFileDescriptor +import java.io.Closeable import java.io.InputStream import me.zhanghai.android.libarchive.ArchiveException -class AndroidArchiveReader(pfd: ParcelFileDescriptor) : ArchiveReader { +class ArchiveReader(pfd: ParcelFileDescriptor) : Closeable { val size = pfd.statSize val address = Os.mmap(0, size, OsConstants.PROT_READ, OsConstants.MAP_PRIVATE, pfd.fileDescriptor, 0) - override fun useEntries(block: (Sequence) -> T): T = - AndroidArchiveInputStream(address, size).use { block(generateSequence { it.getNextEntry() }) } + fun useEntries(block: (Sequence) -> T): T = ArchiveInputStream(address, size).use { + block(generateSequence { it.getNextEntry() }) + } - override fun getInputStream(entryName: String): InputStream? { - val archive = AndroidArchiveInputStream(address, size) + fun getInputStream(entryName: String): InputStream? { + val archive = ArchiveInputStream(address, size) try { while (true) { val entry = archive.getNextEntry() ?: break @@ -37,6 +36,3 @@ class AndroidArchiveReader(pfd: ParcelFileDescriptor) : ArchiveReader { Os.munmap(address, size) } } - -fun UniFile.archiveReader(context: Context): ArchiveReader = - openFileDescriptor(context, "r").use { AndroidArchiveReader(it) } diff --git a/core/main/src/androidMain/kotlin/eu/kanade/tachiyomi/util/storage/EpubFile.kt b/core/archive/src/main/java/yokai/core/archive/EpubReader.kt similarity index 96% rename from core/main/src/androidMain/kotlin/eu/kanade/tachiyomi/util/storage/EpubFile.kt rename to core/archive/src/main/java/yokai/core/archive/EpubReader.kt index b1a2711749..89ba98096b 100644 --- a/core/main/src/androidMain/kotlin/eu/kanade/tachiyomi/util/storage/EpubFile.kt +++ b/core/archive/src/main/java/yokai/core/archive/EpubReader.kt @@ -1,16 +1,15 @@ -package eu.kanade.tachiyomi.util.storage +package yokai.core.archive import java.io.Closeable import java.io.File import java.io.InputStream import org.jsoup.Jsoup import org.jsoup.nodes.Document -import yokai.core.archive.ArchiveReader /** * Wrapper over ZipFile to load files in epub format. */ -class EpubFile(private val reader: ArchiveReader) : Closeable by reader { +class EpubReader(private val reader: ArchiveReader) : Closeable by reader { /** * Path separator used by this epub. diff --git a/core/main/src/androidMain/kotlin/yokai/core/archive/ZipWriter.kt b/core/archive/src/main/java/yokai/core/archive/ZipWriter.kt similarity index 97% rename from core/main/src/androidMain/kotlin/yokai/core/archive/ZipWriter.kt rename to core/archive/src/main/java/yokai/core/archive/ZipWriter.kt index a5d84edcfb..3ee02b02b7 100644 --- a/core/main/src/androidMain/kotlin/yokai/core/archive/ZipWriter.kt +++ b/core/archive/src/main/java/yokai/core/archive/ZipWriter.kt @@ -4,12 +4,12 @@ import android.content.Context import android.system.Os import android.system.StructStat import com.hippo.unifile.UniFile -import eu.kanade.tachiyomi.util.system.openFileDescriptor import java.io.Closeable import java.nio.ByteBuffer import me.zhanghai.android.libarchive.Archive import me.zhanghai.android.libarchive.ArchiveEntry import me.zhanghai.android.libarchive.ArchiveException +import yokai.core.archive.util.openFileDescriptor class ZipWriter(val context: Context, file: UniFile) : Closeable { private val pfd = file.openFileDescriptor(context, "wt") diff --git a/core/archive/src/main/java/yokai/core/archive/util/UniFileExtensions.kt b/core/archive/src/main/java/yokai/core/archive/util/UniFileExtensions.kt new file mode 100644 index 0000000000..588f8fcc81 --- /dev/null +++ b/core/archive/src/main/java/yokai/core/archive/util/UniFileExtensions.kt @@ -0,0 +1,14 @@ +package yokai.core.archive.util + +import android.content.Context +import android.os.ParcelFileDescriptor +import com.hippo.unifile.UniFile +import yokai.core.archive.ArchiveReader +import yokai.core.archive.EpubReader + +fun UniFile.openFileDescriptor(context: Context, mode: String): ParcelFileDescriptor = + context.contentResolver.openFileDescriptor(uri, mode) ?: error("Failed to open file descriptor: ${filePath ?: uri.toString()}") + +fun UniFile.archiveReader(context: Context): ArchiveReader = openFileDescriptor(context, "r").use { ArchiveReader(it) } + +fun UniFile.epubReader(context: Context): EpubReader = EpubReader(archiveReader(context)) diff --git a/core/main/build.gradle.kts b/core/main/build.gradle.kts index d78b8e4392..db1374c6ab 100644 --- a/core/main/build.gradle.kts +++ b/core/main/build.gradle.kts @@ -60,7 +60,7 @@ kotlin { } android { - namespace = "yokai.core" + namespace = "yokai.core.main" } tasks { diff --git a/core/main/src/androidMain/kotlin/eu/kanade/tachiyomi/util/system/UniFileExtensions.kt b/core/main/src/androidMain/kotlin/eu/kanade/tachiyomi/util/system/UniFileExtensions.kt index ce50162b3e..1e55656c32 100644 --- a/core/main/src/androidMain/kotlin/eu/kanade/tachiyomi/util/system/UniFileExtensions.kt +++ b/core/main/src/androidMain/kotlin/eu/kanade/tachiyomi/util/system/UniFileExtensions.kt @@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.util.system import android.content.Context import android.os.Build import android.os.FileUtils -import android.os.ParcelFileDescriptor import com.hippo.unifile.UniFile import java.io.BufferedOutputStream import java.io.File @@ -48,6 +47,3 @@ fun UniFile.writeText(string: String, onComplete: () -> Unit = {}) { onComplete() } } - -fun UniFile.openFileDescriptor(context: Context, mode: String): ParcelFileDescriptor = - context.contentResolver.openFileDescriptor(uri, mode) ?: error("Failed to open file descriptor: $displayablePath") diff --git a/core/main/src/androidMain/kotlin/yokai/core/archive/ArchiveInputStream.kt b/core/main/src/androidMain/kotlin/yokai/core/archive/ArchiveInputStream.kt deleted file mode 100644 index 6a9cd0185b..0000000000 --- a/core/main/src/androidMain/kotlin/yokai/core/archive/ArchiveInputStream.kt +++ /dev/null @@ -1,6 +0,0 @@ -package yokai.core.archive - -import java.io.InputStream - -// TODO: Use Okio's Source -abstract class ArchiveInputStream : InputStream() diff --git a/core/main/src/androidMain/kotlin/yokai/core/archive/ArchiveReader.kt b/core/main/src/androidMain/kotlin/yokai/core/archive/ArchiveReader.kt deleted file mode 100644 index 00d646f3a7..0000000000 --- a/core/main/src/androidMain/kotlin/yokai/core/archive/ArchiveReader.kt +++ /dev/null @@ -1,9 +0,0 @@ -package yokai.core.archive - -import java.io.Closeable -import java.io.InputStream - -interface ArchiveReader : Closeable { - fun useEntries(block: (Sequence) -> T): T - fun getInputStream(entryName: String): InputStream? -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 09869b29ff..bd2a49e70e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -31,6 +31,7 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") rootProject.name = "Yokai" include(":app") +include(":core:archive") include(":core:main") include(":data") include(":domain")