From c8ca321be2cebbaa726740bd39799579f4ae88ca Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 4 Jan 2024 18:02:40 -0500 Subject: [PATCH] Remove tmp chapter files after exiting reader (cherry picked from commit 4e221397ceaec334307546920b3e1168e56f5433) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt # source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt --- .../java/eu/kanade/tachiyomi/di/AppModule.kt | 3 ++ .../tachiyomi/ui/reader/ReaderViewModel.kt | 4 ++ .../ui/reader/loader/ChapterLoader.kt | 15 ++++--- .../ui/reader/loader/DownloadPageLoader.kt | 7 +-- .../core/storage/UniFileExtensions.kt | 29 ------------ .../core/storage/UniFileTempFileManager.kt | 44 +++++++++++++++++++ .../tachiyomi/source/local/LocalSource.kt | 17 +++---- 7 files changed, 72 insertions(+), 47 deletions(-) create mode 100644 core/src/main/java/tachiyomi/core/storage/UniFileTempFileManager.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt b/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt index 74f8f41e2..2de9a9ecc 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt @@ -32,6 +32,7 @@ import nl.adaptivity.xmlutil.XmlDeclMode import nl.adaptivity.xmlutil.core.XmlVersion import nl.adaptivity.xmlutil.serialization.XML import tachiyomi.core.storage.AndroidStorageFolderProvider +import tachiyomi.core.storage.UniFileTempFileManager import tachiyomi.data.AndroidDatabaseHandler import tachiyomi.data.Database import tachiyomi.data.DatabaseHandler @@ -139,6 +140,8 @@ class AppModule(val app: Application) : InjektModule { ProtoBuf } + addSingletonFactory { UniFileTempFileManager(app) } + addSingletonFactory { ChapterCache(app, get(), get()) } addSingletonFactory { CoverCache(app) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt index fd89208fb..ec81e324f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt @@ -71,6 +71,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.runBlocking import logcat.LogPriority import tachiyomi.core.preference.toggle +import tachiyomi.core.storage.UniFileTempFileManager import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.withIOContext @@ -108,6 +109,7 @@ class ReaderViewModel @JvmOverloads constructor( private val sourceManager: SourceManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(), private val downloadProvider: DownloadProvider = Injekt.get(), + private val tempFileManager: UniFileTempFileManager = Injekt.get(), private val imageSaver: ImageSaver = Injekt.get(), preferences: BasePreferences = Injekt.get(), val readerPreferences: ReaderPreferences = Injekt.get(), @@ -380,6 +382,7 @@ class ReaderViewModel @JvmOverloads constructor( context = context, downloadManager = downloadManager, downloadProvider = downloadProvider, + tempFileManager = tempFileManager, manga = manga, source = source, /* SY --> */ sourceManager = sourceManager, @@ -1274,6 +1277,7 @@ class ReaderViewModel @JvmOverloads constructor( private fun deletePendingChapters() { viewModelScope.launchNonCancellable { downloadManager.deletePendingChapters() + tempFileManager.deleteTempFiles() } } 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 d3364677f..5dd4cad48 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,7 @@ 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.i18n.stringResource -import tachiyomi.core.storage.toTempFile +import tachiyomi.core.storage.UniFileTempFileManager import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.system.logcat import tachiyomi.domain.manga.model.Manga @@ -28,6 +28,7 @@ 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 --> @@ -125,13 +126,13 @@ class ChapterLoader( source is LocalSource -> source.getFormat(chapter.chapter).let { format -> when (format) { is Format.Directory -> DirectoryPageLoader(format.file) - is Format.Zip -> ZipPageLoader(format.file.toTempFile(context)) + is Format.Zip -> ZipPageLoader(tempFileManager.createTempFile(format.file)) is Format.Rar -> try { - RarPageLoader(format.file.toTempFile(context)) + RarPageLoader(tempFileManager.createTempFile(format.file)) } catch (e: UnsupportedRarV5Exception) { error(context.stringResource(MR.strings.loader_rar5_error)) } - is Format.Epub -> EpubPageLoader(format.file.toTempFile(context)) + is Format.Epub -> EpubPageLoader(tempFileManager.createTempFile(format.file)) } } else -> error(context.stringResource(MR.strings.loader_not_implemented_error)) @@ -142,13 +143,13 @@ class ChapterLoader( source is LocalSource -> source.getFormat(chapter.chapter).let { format -> when (format) { is Format.Directory -> DirectoryPageLoader(format.file) - is Format.Zip -> ZipPageLoader(format.file.toTempFile(context)) + is Format.Zip -> ZipPageLoader(tempFileManager.createTempFile(format.file)) is Format.Rar -> try { - RarPageLoader(format.file.toTempFile(context)) + RarPageLoader(tempFileManager.createTempFile(format.file)) } catch (e: UnsupportedRarV5Exception) { error(context.stringResource(MR.strings.loader_rar5_error)) } - is Format.Epub -> EpubPageLoader(format.file.toTempFile(context)) + is Format.Epub -> EpubPageLoader(tempFileManager.createTempFile(format.file)) } } source is HttpSource -> HttpPageLoader(chapter, source) 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 d2fe3de04..a1de1b433 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 @@ -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 tachiyomi.core.storage.toTempFile +import tachiyomi.core.storage.UniFileTempFileManager import tachiyomi.domain.manga.model.Manga import uy.kohesive.injekt.injectLazy @@ -23,6 +23,7 @@ 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() @@ -46,8 +47,8 @@ internal class DownloadPageLoader( zipPageLoader?.recycle() } - private suspend fun getPagesFromArchive(chapterPath: UniFile): List { - val loader = ZipPageLoader(chapterPath.toTempFile(context)).also { zipPageLoader = it } + private suspend fun getPagesFromArchive(file: UniFile): List { + val loader = ZipPageLoader(tempFileManager.createTempFile(file)).also { zipPageLoader = it } return loader.getPages() } diff --git a/core/src/main/java/tachiyomi/core/storage/UniFileExtensions.kt b/core/src/main/java/tachiyomi/core/storage/UniFileExtensions.kt index 8e2bf43fc..afe60ed35 100644 --- a/core/src/main/java/tachiyomi/core/storage/UniFileExtensions.kt +++ b/core/src/main/java/tachiyomi/core/storage/UniFileExtensions.kt @@ -1,11 +1,6 @@ package tachiyomi.core.storage -import android.content.Context -import android.os.Build -import android.os.FileUtils import com.hippo.unifile.UniFile -import java.io.BufferedOutputStream -import java.io.File val UniFile.extension: String? get() = name?.substringAfterLast('.') @@ -15,27 +10,3 @@ val UniFile.nameWithoutExtension: String? val UniFile.displayablePath: String get() = filePath ?: uri.toString() - -fun UniFile.toTempFile(context: Context): File { - val inputStream = context.contentResolver.openInputStream(uri)!! - val tempFile = File.createTempFile( - nameWithoutExtension.orEmpty().padEnd(3), // Prefix must be 3+ chars - null, - ) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - FileUtils.copy(inputStream, tempFile.outputStream()) - } else { - BufferedOutputStream(tempFile.outputStream()).use { tmpOut -> - inputStream.use { input -> - val buffer = ByteArray(8192) - var count: Int - while (input.read(buffer).also { count = it } > 0) { - tmpOut.write(buffer, 0, count) - } - } - } - } - - return tempFile -} diff --git a/core/src/main/java/tachiyomi/core/storage/UniFileTempFileManager.kt b/core/src/main/java/tachiyomi/core/storage/UniFileTempFileManager.kt new file mode 100644 index 000000000..938494613 --- /dev/null +++ b/core/src/main/java/tachiyomi/core/storage/UniFileTempFileManager.kt @@ -0,0 +1,44 @@ +package tachiyomi.core.storage + +import android.content.Context +import android.os.Build +import android.os.FileUtils +import com.hippo.unifile.UniFile +import java.io.BufferedOutputStream +import java.io.File + +class UniFileTempFileManager( + private val context: Context, +) { + + private val dir = File(context.externalCacheDir, "tmp").also { it.mkdir() } + + fun createTempFile(file: UniFile): File { + val inputStream = context.contentResolver.openInputStream(file.uri)!! + val tempFile = File.createTempFile( + file.nameWithoutExtension.orEmpty().padEnd(3), // Prefix must be 3+ chars + null, + dir, + ) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + FileUtils.copy(inputStream, tempFile.outputStream()) + } else { + BufferedOutputStream(tempFile.outputStream()).use { tmpOut -> + inputStream.use { input -> + val buffer = ByteArray(8192) + var count: Int + while (input.read(buffer).also { count = it } > 0) { + tmpOut.write(buffer, 0, count) + } + } + } + } + + return tempFile + } + + fun deleteTempFiles() { + dir.deleteRecursively() + } +} diff --git a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt index aa5f03d2f..61a723a51 100755 --- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt +++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt @@ -28,9 +28,9 @@ import tachiyomi.core.metadata.comicinfo.ComicInfo import tachiyomi.core.metadata.comicinfo.copyFromComicInfo import tachiyomi.core.metadata.comicinfo.getComicInfo import tachiyomi.core.metadata.tachiyomi.MangaDetails +import tachiyomi.core.storage.UniFileTempFileManager import tachiyomi.core.storage.extension import tachiyomi.core.storage.nameWithoutExtension -import tachiyomi.core.storage.toTempFile import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.system.ImageUtil import tachiyomi.core.util.system.logcat @@ -62,6 +62,7 @@ actual class LocalSource( private val json: Json by injectLazy() private val xml: XML by injectLazy() + private val tempFileManager: UniFileTempFileManager by injectLazy() private val POPULAR_FILTERS = FilterList(OrderBy.Popular(context)) private val LATEST_FILTERS = FilterList(OrderBy.Latest(context)) @@ -198,7 +199,7 @@ actual class LocalSource( } // SY --> comicInfoArchiveFile != null -> { - val comicInfoArchive = ZipFile(comicInfoArchiveFile.toTempFile(context)) + val comicInfoArchive = ZipFile(tempFileManager.createTempFile(comicInfoArchiveFile)) noXmlFile?.delete() if (CbzCrypto.checkCbzPassword(comicInfoArchive, CbzCrypto.getDecryptedPasswordCbz())) { @@ -268,7 +269,7 @@ actual class LocalSource( for (chapter in chapterArchives) { when (Format.valueOf(chapter)) { is Format.Zip -> { - ZipFile(chapter.toTempFile(context)).use { zip: ZipFile -> + ZipFile(tempFileManager.createTempFile(chapter)).use { zip: ZipFile -> // SY --> if (zip.isEncrypted && !CbzCrypto.checkCbzPassword(zip, CbzCrypto.getDecryptedPasswordCbz()) ) { @@ -287,7 +288,7 @@ actual class LocalSource( } } is Format.Rar -> { - JunrarArchive(chapter.toTempFile(context)).use { rar -> + JunrarArchive(tempFileManager.createTempFile(chapter)).use { rar -> rar.fileHeaders.firstOrNull { it.fileName == COMIC_INFO_FILE }?.let { comicInfoFile -> rar.getInputStream(comicInfoFile).buffered().use { stream -> return copyComicInfoFile(stream, folderPath) @@ -353,7 +354,7 @@ actual class LocalSource( val format = Format.valueOf(chapterFile) if (format is Format.Epub) { - EpubFile(format.file.toTempFile(context)).use { epub -> + EpubFile(tempFileManager.createTempFile(format.file)).use { epub -> epub.fillMetadata(manga, this) } } @@ -412,7 +413,7 @@ actual class LocalSource( entry?.let { coverManager.update(manga, it.openInputStream()) } } is Format.Zip -> { - ZipFile(format.file.toTempFile(context)).use { zip -> + ZipFile(tempFileManager.createTempFile(format.file)).use { zip -> // SY --> var encrypted = false if (zip.isEncrypted) { @@ -427,7 +428,7 @@ actual class LocalSource( } } is Format.Rar -> { - JunrarArchive(format.file.toTempFile(context)).use { archive -> + JunrarArchive(tempFileManager.createTempFile(format.file)).use { archive -> val entry = archive.fileHeaders .sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) } .find { !it.isDirectory && ImageUtil.isImage(it.fileName) { archive.getInputStream(it) } } @@ -436,7 +437,7 @@ actual class LocalSource( } } is Format.Epub -> { - EpubFile(format.file.toTempFile(context)).use { epub -> + EpubFile(tempFileManager.createTempFile(format.file)).use { epub -> val entry = epub.getImagesFromPages() .firstOrNull() ?.let { epub.getEntry(it) }