mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-21 20:47:03 -05:00
Move archive related code to :core:archive
This commit is contained in:
parent
70c1a842b2
commit
bd7b354198
20 changed files with 70 additions and 52 deletions
|
@ -141,6 +141,7 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation(projects.i18n)
|
||||
implementation(projects.core.archive)
|
||||
implementation(projects.core.common)
|
||||
implementation(projects.coreMetadata)
|
||||
implementation(projects.sourceApi)
|
||||
|
|
|
@ -38,7 +38,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 tachiyomi.core.common.i18n.stringResource
|
||||
|
|
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,7 +6,8 @@ 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 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
|
||||
|
@ -95,7 +96,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)
|
||||
|
|
|
@ -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 mihon.core.common.archive.archiveReader
|
||||
import mihon.core.archive.archiveReader
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
|
|
|
@ -2,27 +2,22 @@ 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)!! }
|
||||
ReaderPage(i).apply {
|
||||
stream = streamFn
|
||||
status = Page.State.READY
|
||||
}
|
||||
return reader.getImagesFromPages().mapIndexed { i, path ->
|
||||
ReaderPage(i).apply {
|
||||
stream = { reader.getInputStream(path)!! }
|
||||
status = Page.State.READY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadPage(page: ReaderPage) {
|
||||
|
@ -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
1
core/archive/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
15
core/archive/build.gradle.kts
Normal file
15
core/archive/build.gradle.kts
Normal 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)
|
||||
}
|
2
core/archive/src/main/AndroidManifest.xml
Normal file
2
core/archive/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest />
|
|
@ -1,4 +1,4 @@
|
|||
package mihon.core.common.archive
|
||||
package mihon.core.archive
|
||||
|
||||
class ArchiveEntry(
|
||||
val name: String,
|
|
@ -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
|
|
@ -1,21 +1,19 @@
|
|||
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)
|
||||
|
@ -38,5 +36,3 @@ class ArchiveReader(pfd: ParcelFileDescriptor) : Closeable {
|
|||
Os.munmap(address, size)
|
||||
}
|
||||
}
|
||||
|
||||
fun UniFile.archiveReader(context: Context) = openFileDescriptor(context, "r").use { ArchiveReader(it) }
|
|
@ -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.
|
|
@ -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))
|
|
@ -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 }
|
|
@ -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")
|
||||
|
|
|
@ -40,6 +40,7 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
|||
rootProject.name = "Mihon"
|
||||
include(":app")
|
||||
include(":core-metadata")
|
||||
include(":core:archive")
|
||||
include(":core:common")
|
||||
include(":data")
|
||||
include(":domain")
|
||||
|
|
|
@ -16,6 +16,7 @@ kotlin {
|
|||
}
|
||||
val androidMain by getting {
|
||||
dependencies {
|
||||
implementation(projects.core.archive)
|
||||
implementation(projects.core.common)
|
||||
implementation(projects.coreMetadata)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -253,7 +253,7 @@ actual class LocalSource(
|
|||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ actual class LocalSource(
|
|||
}
|
||||
}
|
||||
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)!!) }
|
||||
|
|
|
@ -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)
|
||||
|
Loading…
Reference in a new issue