Skip to content

Commit

Permalink
implement mihonapp/mihon#326 (#1104)
Browse files Browse the repository at this point in the history
* implement mihonapp/mihon#326

Archives are now being read from channels

Co-authored-by: FooIbar <[email protected]>
Co-authored-by: AntsyLich <[email protected]>

* disable parallelisms for loading into memory

* switched to mutex

* detekt changes

* more detekt baseline changes

---------

Co-authored-by: FooIbar <[email protected]>
Co-authored-by: AntsyLich <[email protected]>
  • Loading branch information
3 people authored and cuong-tran committed Mar 18, 2024
1 parent edcd339 commit 053515c
Show file tree
Hide file tree
Showing 27 changed files with 1,654 additions and 581 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ dependencies {
// Disk
implementation(libs.disklrucache)
implementation(libs.unifile)
implementation(libs.junrar)
implementation(libs.bundles.archive)
// SY -->
implementation(libs.zip4j)
// SY <--
Expand Down
3 changes: 3 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@
# 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.** { *; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -570,10 +570,14 @@ object SettingsReaderScreen : SearchableSettings {
.toMap()
.toImmutableMap(),
),
Preference.PreferenceItem.SwitchPreference(
pref = readerPreferences.cacheArchiveMangaOnDisk(),
title = stringResource(SYMR.strings.cache_archived_manga_to_disk),
subtitle = stringResource(SYMR.strings.cache_archived_manga_to_disk_subtitle),
Preference.PreferenceItem.ListPreference(
pref = readerPreferences.archiveReaderMode(),
title = stringResource(SYMR.strings.pref_archive_reader_mode),
subtitle = stringResource(SYMR.strings.pref_archive_reader_mode_summary),
entries = ReaderPreferences.archiveModeTypes
.mapIndexed { index, it -> index to stringResource(it) }
.toMap()
.toImmutableMap(),
),
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.source.UnmeteredSource
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.storage.CbzCrypto
import eu.kanade.tachiyomi.util.storage.CbzCrypto.addFilesToZip
import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.DiskUtil.NOMEDIA_FILE
import eu.kanade.tachiyomi.util.storage.saveTo
Expand Down Expand Up @@ -46,6 +45,7 @@ import logcat.LogPriority
import nl.adaptivity.xmlutil.serialization.XML
import okhttp3.Response
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.core.common.storage.addFilesToZip
import tachiyomi.core.common.storage.extension
import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.core.common.util.lang.launchNow
Expand Down Expand Up @@ -572,10 +572,6 @@ class Downloader(
tmpDir,
imageFile,
filenamePrefix,
// SY -->
zip4jFile = null,
zip4jEntry = null,
// SY <--
)
} catch (e: Exception) {
logcat(LogPriority.ERROR, e) { "Failed to split downloaded image" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,6 @@ class ReaderViewModel @JvmOverloads constructor(
context = context,
downloadManager = downloadManager,
downloadProvider = downloadProvider,
tempFileManager = tempFileManager,
manga = manga,
source = source, /* SY --> */
sourceManager = sourceManager,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import eu.kanade.tachiyomi.source.online.all.MergedSource
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.core.common.storage.UniFileTempFileManager
import tachiyomi.core.common.util.lang.withIOContext
import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.manga.model.Manga
Expand All @@ -28,7 +27,6 @@ class ChapterLoader(
private val context: Context,
private val downloadManager: DownloadManager,
private val downloadProvider: DownloadProvider,
private val tempFileManager: UniFileTempFileManager,
private val manga: Manga,
private val source: Source,
// SY -->
Expand Down Expand Up @@ -121,36 +119,39 @@ class ChapterLoader(
source = source,
downloadManager = downloadManager,
downloadProvider = downloadProvider,
tempFileManager = tempFileManager,
)
source is HttpSource -> HttpPageLoader(chapter, source)
source is LocalSource -> source.getFormat(chapter.chapter).let { format ->
when (format) {
is Format.Directory -> DirectoryPageLoader(format.file)
is Format.Zip -> ZipPageLoader(tempFileManager.createTempFile(format.file))
is Format.Zip -> ZipPageLoader(format.file, context)
is Format.Rar -> try {
RarPageLoader(tempFileManager.createTempFile(format.file))
RarPageLoader(format.file)
} catch (e: UnsupportedRarV5Exception) {
error(context.stringResource(MR.strings.loader_rar5_error))
}
is Format.Epub -> EpubPageLoader(tempFileManager.createTempFile(format.file))
is Format.Epub -> EpubPageLoader(format.file, context)
}
}
else -> error(context.stringResource(MR.strings.loader_not_implemented_error))
}
}
// SY <--
isDownloaded -> DownloadPageLoader(chapter, manga, source, downloadManager, downloadProvider, tempFileManager)
isDownloaded -> DownloadPageLoader(chapter, manga, source, downloadManager, downloadProvider)
source is LocalSource -> source.getFormat(chapter.chapter).let { format ->
when (format) {
is Format.Directory -> DirectoryPageLoader(format.file)
is Format.Zip -> ZipPageLoader(tempFileManager.createTempFile(format.file))
// SY -->
is Format.Zip -> ZipPageLoader(format.file, context)
is Format.Rar -> try {
RarPageLoader(tempFileManager.createTempFile(format.file))
RarPageLoader(format.file)
// SY <--
} catch (e: UnsupportedRarV5Exception) {
error(context.stringResource(MR.strings.loader_rar5_error))
}
is Format.Epub -> EpubPageLoader(tempFileManager.createTempFile(format.file))
// SY -->
is Format.Epub -> EpubPageLoader(format.file, context)
// SY <--
}
}
source is HttpSource -> HttpPageLoader(chapter, source)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ 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.UniFileTempFileManager
import tachiyomi.domain.manga.model.Manga
import uy.kohesive.injekt.injectLazy

Expand All @@ -23,7 +22,6 @@ internal class DownloadPageLoader(
private val source: Source,
private val downloadManager: DownloadManager,
private val downloadProvider: DownloadProvider,
private val tempFileManager: UniFileTempFileManager,
) : PageLoader() {

private val context: Application by injectLazy()
Expand All @@ -48,7 +46,9 @@ internal class DownloadPageLoader(
}

private suspend fun getPagesFromArchive(file: UniFile): List<ReaderPage> {
val loader = ZipPageLoader(tempFileManager.createTempFile(file)).also { zipPageLoader = it }
// SY -->
val loader = ZipPageLoader(file, context).also { zipPageLoader = it }
// SY <--
return loader.getPages()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package eu.kanade.tachiyomi.ui.reader.loader

import android.content.Context
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
import eu.kanade.tachiyomi.util.storage.EpubFile
import java.io.File

/**
* Loader used to load a chapter from a .epub file.
*/
internal class EpubPageLoader(file: File) : PageLoader() {
// SY -->
internal class EpubPageLoader(file: UniFile, context: Context) : PageLoader() {

private val epub = EpubFile(file)
private val epub = EpubFile(file, context)
// SY <--

override var isLocal: Boolean = true

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
package eu.kanade.tachiyomi.ui.reader.loader

import android.app.Application
import android.os.Build
import com.github.junrar.Archive
import com.github.junrar.rarfile.FileHeader
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import tachiyomi.core.common.storage.UniFileTempFileManager
import tachiyomi.core.common.util.system.ImageUtil
import uy.kohesive.injekt.injectLazy
import java.io.File
Expand All @@ -19,32 +28,39 @@ import java.util.concurrent.Executors
/**
* Loader used to load a chapter from a .rar or .cbr file.
*/
internal class RarPageLoader(file: File) : PageLoader() {

private val rar = Archive(file)
internal class RarPageLoader(file: UniFile) : PageLoader() {

// SY -->
private val tempFileManager: UniFileTempFileManager by injectLazy()

private val rar = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
Archive(tempFileManager.createTempFile(file))
} else {
Archive(file.openInputStream())
}

private val context: Application by injectLazy()
private val readerPreferences: ReaderPreferences by injectLazy()
private val tmpDir = File(context.externalCacheDir, "reader_${file.hashCode()}").also {
it.deleteRecursively()
}

init {
if (readerPreferences.cacheArchiveMangaOnDisk().get()) {
if (readerPreferences.archiveReaderMode().get() == ReaderPreferences.ArchiveReaderMode.CACHE_TO_DISK) {
tmpDir.mkdirs()
Archive(file).use { rar ->
rar.fileHeaders.asSequence()
.filterNot { it.isDirectory }
.forEach { header ->
val pageOutputStream = File(tmpDir, header.fileName.substringAfterLast("/"))
.also { it.createNewFile() }
.outputStream()
getStream(header).use {
it.copyTo(pageOutputStream)
rar.fileHeaders.asSequence()
.filter { !it.isDirectory && ImageUtil.isImage(it.fileName) { rar.getInputStream(it) } }
.sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) }
.forEach { header ->
File(tmpDir, header.fileName.substringAfterLast("/"))
.also { it.createNewFile() }
.outputStream()
.use { output ->
rar.getInputStream(header).use { input ->
input.copyTo(output)
}
}
}
}
}
}
}
// SY <--
Expand All @@ -58,16 +74,37 @@ internal class RarPageLoader(file: File) : PageLoader() {

override suspend fun getPages(): List<ReaderPage> {
// SY -->
if (readerPreferences.cacheArchiveMangaOnDisk().get()) {
if (readerPreferences.archiveReaderMode().get() == ReaderPreferences.ArchiveReaderMode.CACHE_TO_DISK) {
return DirectoryPageLoader(UniFile.fromFile(tmpDir)!!).getPages()
}
val mutex = Mutex()
// SY <--
return rar.fileHeaders.asSequence()
.filter { !it.isDirectory && ImageUtil.isImage(it.fileName) { rar.getInputStream(it) } }
.sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) }
.mapIndexed { i, header ->
// SY -->
val imageBytesDeferred: Deferred<ByteArray>? =
when (readerPreferences.archiveReaderMode().get()) {
ReaderPreferences.ArchiveReaderMode.LOAD_INTO_MEMORY -> {
CoroutineScope(Dispatchers.IO).async {
mutex.withLock {
getStream(header).buffered().use { stream ->
stream.readBytes()
}
}
}
}

else -> null
}

val imageBytes by lazy { runBlocking { imageBytesDeferred?.await() } }
// SY <--
ReaderPage(i).apply {
stream = { getStream(header) }
// SY -->
stream = { imageBytes?.copyOf()?.inputStream() ?: getStream(header) }
// SY <--
status = Page.State.READY
}
}
Expand Down
Loading

0 comments on commit 053515c

Please sign in to comment.