mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Remove tmp chapter files after exiting reader
This commit is contained in:
		@@ -27,6 +27,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
 | 
			
		||||
@@ -111,6 +112,8 @@ class AppModule(val app: Application) : InjektModule {
 | 
			
		||||
            ProtoBuf
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addSingletonFactory { UniFileTempFileManager(app) }
 | 
			
		||||
 | 
			
		||||
        addSingletonFactory { ChapterCache(app, get()) }
 | 
			
		||||
        addSingletonFactory { CoverCache(app) }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -55,6 +55,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
 | 
			
		||||
@@ -85,6 +86,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(),
 | 
			
		||||
@@ -269,7 +271,7 @@ class ReaderViewModel @JvmOverloads constructor(
 | 
			
		||||
 | 
			
		||||
                    val context = Injekt.get<Application>()
 | 
			
		||||
                    val source = sourceManager.getOrStub(manga.source)
 | 
			
		||||
                    loader = ChapterLoader(context, downloadManager, downloadProvider, manga, source)
 | 
			
		||||
                    loader = ChapterLoader(context, downloadManager, downloadProvider, tempFileManager, manga, source)
 | 
			
		||||
 | 
			
		||||
                    loadChapter(loader!!, chapterList.first { chapterId == it.chapter.id })
 | 
			
		||||
                    Result.success(true)
 | 
			
		||||
@@ -904,6 +906,7 @@ class ReaderViewModel @JvmOverloads constructor(
 | 
			
		||||
    private fun deletePendingChapters() {
 | 
			
		||||
        viewModelScope.launchNonCancellable {
 | 
			
		||||
            downloadManager.deletePendingChapters()
 | 
			
		||||
            tempFileManager.deleteTempFiles()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ import eu.kanade.tachiyomi.source.Source
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.HttpSource
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
 | 
			
		||||
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
 | 
			
		||||
@@ -24,6 +24,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,
 | 
			
		||||
) {
 | 
			
		||||
@@ -85,17 +86,24 @@ class ChapterLoader(
 | 
			
		||||
            skipCache = true,
 | 
			
		||||
        )
 | 
			
		||||
        return when {
 | 
			
		||||
            isDownloaded -> DownloadPageLoader(chapter, manga, source, downloadManager, downloadProvider)
 | 
			
		||||
            isDownloaded -> DownloadPageLoader(
 | 
			
		||||
                chapter,
 | 
			
		||||
                manga,
 | 
			
		||||
                source,
 | 
			
		||||
                downloadManager,
 | 
			
		||||
                downloadProvider,
 | 
			
		||||
                tempFileManager,
 | 
			
		||||
            )
 | 
			
		||||
            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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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<ReaderPage> {
 | 
			
		||||
        val loader = ZipPageLoader(chapterPath.toTempFile(context)).also { zipPageLoader = it }
 | 
			
		||||
    private suspend fun getPagesFromArchive(file: UniFile): List<ReaderPage> {
 | 
			
		||||
        val loader = ZipPageLoader(tempFileManager.createTempFile(file)).also { zipPageLoader = it }
 | 
			
		||||
        return loader.getPages()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -24,9 +24,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
 | 
			
		||||
@@ -56,6 +56,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))
 | 
			
		||||
@@ -213,7 +214,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 ->
 | 
			
		||||
                        zip.getEntry(COMIC_INFO_FILE)?.let { comicInfoFile ->
 | 
			
		||||
                            zip.getInputStream(comicInfoFile).buffered().use { stream ->
 | 
			
		||||
                                return copyComicInfoFile(stream, folderPath)
 | 
			
		||||
@@ -222,7 +223,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)
 | 
			
		||||
@@ -272,7 +273,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)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
@@ -331,7 +332,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 ->
 | 
			
		||||
                        val entry = zip.entries().toList()
 | 
			
		||||
                            .sortedWith { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }
 | 
			
		||||
                            .find { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } }
 | 
			
		||||
@@ -340,7 +341,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) } }
 | 
			
		||||
@@ -349,7 +350,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) }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user