Move archive related code to :core:archive

Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
This commit is contained in:
AntsyLich 2024-09-05 12:00:46 +02:00 committed by Secozzi
parent c6b34e5bc6
commit 3599a38ad6
No known key found for this signature in database
GPG key ID: DD93E0B3A962AA86
20 changed files with 71 additions and 53 deletions

View file

@ -147,6 +147,7 @@ android {
dependencies {
implementation(projects.i18n)
implementation(projects.core.archive)
implementation(projects.core.common)
implementation(projects.coreMetadata)
implementation(projects.sourceApi)

View file

@ -41,7 +41,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.supervisorScope
import logcat.LogPriority
import mihon.core.common.archive.ZipWriter
import mihon.core.archive.ZipWriter
import nl.adaptivity.xmlutil.serialization.XML
import okhttp3.Response
import okio.Throttler

View file

@ -3,7 +3,7 @@ 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 mihon.core.common.archive.ArchiveReader
import mihon.core.archive.ArchiveReader
import tachiyomi.core.common.util.system.ImageUtil
/**

View file

@ -7,7 +7,8 @@ import eu.kanade.tachiyomi.source.MangaSource
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import mihon.core.common.archive.archiveReader
import mihon.core.archive.archiveReader
import mihon.core.archive.epubReader
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.core.common.util.lang.withIOContext
import tachiyomi.core.common.util.system.logcat
@ -98,7 +99,7 @@ class ChapterLoader(
when (format) {
is Format.Directory -> DirectoryPageLoader(format.file)
is Format.Archive -> ArchivePageLoader(format.file.archiveReader(context))
is Format.Epub -> EpubPageLoader(format.file.archiveReader(context))
is Format.Epub -> EpubPageLoader(format.file.epubReader(context))
}
}
source is HttpSource -> HttpPageLoader(chapter, source)

View file

@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.source.MangaSource
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
import mihon.core.common.archive.archiveReader
import mihon.core.archive.archiveReader
import tachiyomi.domain.entries.manga.model.Manga
import uy.kohesive.injekt.injectLazy

View file

@ -2,24 +2,19 @@ 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 mihon.core.common.archive.ArchiveReader
import mihon.core.archive.EpubReader
/**
* Loader used to load a chapter from a .epub file.
*/
internal class EpubPageLoader(reader: ArchiveReader) : PageLoader() {
private val epub = EpubFile(reader)
internal class EpubPageLoader(private val reader: EpubReader) : PageLoader() {
override var isLocal: Boolean = true
override suspend fun getPages(): List<ReaderPage> {
return epub.getImagesFromPages()
.mapIndexed { i, path ->
val streamFn = { epub.getInputStream(path)!! }
return reader.getImagesFromPages().mapIndexed { i, path ->
ReaderPage(i).apply {
stream = streamFn
stream = { reader.getInputStream(path)!! }
status = Page.State.READY
}
}
@ -31,6 +26,6 @@ internal class EpubPageLoader(reader: ArchiveReader) : PageLoader() {
override fun recycle() {
super.recycle()
epub.close()
reader.close()
}
}

1
core/archive/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,15 @@
plugins {
id("mihon.library")
kotlin("android")
kotlin("plugin.serialization")
}
android {
namespace = "mihon.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,4 +1,4 @@
package mihon.core.common.archive
package mihon.core.archive
class ArchiveEntry(
val name: String,

View file

@ -1,4 +1,4 @@
package mihon.core.common.archive
package mihon.core.archive
import me.zhanghai.android.libarchive.Archive
import me.zhanghai.android.libarchive.ArchiveEntry
@ -7,7 +7,7 @@ import java.io.InputStream
import java.nio.ByteBuffer
import kotlin.concurrent.Volatile
class ArchiveInputStream(buffer: Long, size: Long) : InputStream() {
internal class ArchiveInputStream(buffer: Long, size: Long) : InputStream() {
private val lock = Any()
@Volatile

View file

@ -1,24 +1,22 @@
package mihon.core.common.archive
package mihon.core.archive
import android.content.Context
import android.os.ParcelFileDescriptor
import android.system.Os
import android.system.OsConstants
import com.hippo.unifile.UniFile
import me.zhanghai.android.libarchive.ArchiveException
import tachiyomi.core.common.storage.openFileDescriptor
import java.io.Closeable
import java.io.InputStream
class ArchiveReader(pfd: ParcelFileDescriptor) : Closeable {
val size = pfd.statSize
val address = Os.mmap(0, size, OsConstants.PROT_READ, OsConstants.MAP_PRIVATE, pfd.fileDescriptor, 0)
private val size = pfd.statSize
private val address = Os.mmap(0, size, OsConstants.PROT_READ, OsConstants.MAP_PRIVATE, pfd.fileDescriptor, 0)
inline fun <T> useEntries(block: (Sequence<ArchiveEntry>) -> T): T =
ArchiveInputStream(address, size).use { block(generateSequence { it.getNextEntry() }) }
fun <T> useEntries(block: (Sequence<ArchiveEntry>) -> T): T = ArchiveInputStream(address, size).use {
block(generateSequence { it.getNextEntry() })
}
fun getInputStream(entryName: String): InputStream? {
val archive = ArchiveInputStream(address, size)
val archive = mihon.core.archive.ArchiveInputStream(address, size)
try {
while (true) {
val entry = archive.getNextEntry() ?: break
@ -38,5 +36,3 @@ class ArchiveReader(pfd: ParcelFileDescriptor) : Closeable {
Os.munmap(address, size)
}
}
fun UniFile.archiveReader(context: Context) = openFileDescriptor(context, "r").use { ArchiveReader(it) }

View file

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.util.storage
package mihon.core.archive
import mihon.core.common.archive.ArchiveReader
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import java.io.Closeable
@ -8,9 +7,9 @@ import java.io.File
import java.io.InputStream
/**
* Wrapper over ZipFile to load files in epub format.
* Wrapper over ArchiveReader 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

@ -0,0 +1,12 @@
package mihon.core.archive
import android.content.Context
import android.os.ParcelFileDescriptor
import com.hippo.unifile.UniFile
internal 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) = openFileDescriptor(context, "r").use { ArchiveReader(it) }
fun UniFile.epubReader(context: Context) = EpubReader(archiveReader(context))

View file

@ -1,4 +1,4 @@
package mihon.core.common.archive
package mihon.core.archive
import android.content.Context
import android.system.Os
@ -7,7 +7,6 @@ import com.hippo.unifile.UniFile
import me.zhanghai.android.libarchive.Archive
import me.zhanghai.android.libarchive.ArchiveEntry
import me.zhanghai.android.libarchive.ArchiveException
import tachiyomi.core.common.storage.openFileDescriptor
import java.io.Closeable
import java.nio.ByteBuffer
@ -65,10 +64,10 @@ private fun StructStat.toArchiveStat() = ArchiveEntry.StructStat().apply {
stSize = st_size
stBlksize = st_blksize
stBlocks = st_blocks
stAtim = timespec(st_atime)
stMtim = timespec(st_mtime)
stCtim = timespec(st_ctime)
stAtim = st_atime.toTimespec()
stMtim = st_mtime.toTimespec()
stCtim = st_ctime.toTimespec()
stIno = st_ino
}
private fun timespec(tvSec: Long) = ArchiveEntry.StructTimespec().also { it.tvSec = tvSec }
private fun Long.toTimespec() = ArchiveEntry.StructTimespec().also { it.tvSec = this }

View file

@ -1,7 +1,5 @@
package tachiyomi.core.common.storage
import android.content.Context
import android.os.ParcelFileDescriptor
import com.hippo.unifile.UniFile
val UniFile.extension: String?
@ -12,6 +10,3 @@ val UniFile.nameWithoutExtension: String?
val UniFile.displayablePath: String
get() = filePath ?: uri.toString()
fun UniFile.openFileDescriptor(context: Context, mode: String): ParcelFileDescriptor =
context.contentResolver.openFileDescriptor(uri, mode) ?: error("Failed to open file descriptor: $displayablePath")

View file

@ -40,6 +40,7 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
rootProject.name = "Aniyomi"
include(":app")
include(":core-metadata")
include(":core:archive")
include(":core:common")
include(":data")
include(":domain")

View file

@ -16,6 +16,7 @@ kotlin {
}
val androidMain by getting {
dependencies {
implementation(projects.core.archive)
implementation(projects.core.common)
implementation(projects.coreMetadata)

View file

@ -11,13 +11,13 @@ import eu.kanade.tachiyomi.source.model.Page
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.EpubFile
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import logcat.LogPriority
import mihon.core.common.archive.archiveReader
import mihon.core.archive.archiveReader
import mihon.core.archive.epubReader
import nl.adaptivity.xmlutil.AndroidXmlReader
import nl.adaptivity.xmlutil.serialization.XML
import tachiyomi.core.common.i18n.stringResource
@ -270,7 +270,7 @@ actual class LocalMangaSource(
val format = Format.valueOf(chapterFile)
if (format is Format.Epub) {
EpubFile(format.file.archiveReader(context)).use { epub ->
format.file.epubReader(context).use { epub ->
epub.fillMetadata(manga, this)
}
}
@ -359,7 +359,7 @@ actual class LocalMangaSource(
}
}
is Format.Epub -> {
EpubFile(format.file.archiveReader(context)).use { epub ->
format.file.epubReader(context).use { epub ->
val entry = epub.getImagesFromPages().firstOrNull()
entry?.let { coverManager.update(manga, epub.getInputStream(it)!!) }

View file

@ -2,7 +2,7 @@ package tachiyomi.source.local.metadata
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.storage.EpubFile
import mihon.core.archive.EpubReader
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
@ -10,7 +10,7 @@ import java.util.Locale
/**
* Fills manga and chapter metadata using this epub file's metadata.
*/
fun EpubFile.fillMetadata(manga: SManga, chapter: SChapter) {
fun EpubReader.fillMetadata(manga: SManga, chapter: SChapter) {
val ref = getPackageHref()
val doc = getPackageDocument(ref)