refactor: Move archive related code to core.archive module

This commit is contained in:
Ahmad Ansori Palembani 2025-01-01 09:26:15 +07:00
parent 54a3059730
commit b4377a4609
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
19 changed files with 61 additions and 55 deletions

View file

@ -144,6 +144,7 @@ android {
}
dependencies {
implementation(projects.core.archive)
implementation(projects.core.main)
implementation(projects.data)
implementation(projects.domain)

View file

@ -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

View file

@ -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))

View file

@ -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.

View file

@ -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.
*/

View file

@ -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)

View file

@ -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)
}

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />

View file

@ -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

View file

@ -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 <T> useEntries(block: (Sequence<ArchiveEntry>) -> T): T =
AndroidArchiveInputStream(address, size).use { block(generateSequence { it.getNextEntry() }) }
fun <T> useEntries(block: (Sequence<ArchiveEntry>) -> 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) }

View file

@ -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.

View file

@ -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")

View file

@ -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))

View file

@ -60,7 +60,7 @@ kotlin {
}
android {
namespace = "yokai.core"
namespace = "yokai.core.main"
}
tasks {

View file

@ -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")

View file

@ -1,6 +0,0 @@
package yokai.core.archive
import java.io.InputStream
// TODO: Use Okio's Source
abstract class ArchiveInputStream : InputStream()

View file

@ -1,9 +0,0 @@
package yokai.core.archive
import java.io.Closeable
import java.io.InputStream
interface ArchiveReader : Closeable {
fun <T> useEntries(block: (Sequence<ArchiveEntry>) -> T): T
fun getInputStream(entryName: String): InputStream?
}

View file

@ -31,6 +31,7 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
rootProject.name = "Yokai"
include(":app")
include(":core:archive")
include(":core:main")
include(":data")
include(":domain")