diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 12effa462..3d12eaea6 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -165,7 +165,6 @@ dependencies {
implementation(compose.ui.tooling.preview)
implementation(compose.ui.util)
implementation(compose.accompanist.webview)
- implementation(compose.accompanist.permissions)
implementation(compose.accompanist.systemuicontroller)
lintChecks(compose.lintchecks)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f75531139..ccb3b15d0 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,9 +7,6 @@
-
-
-
@@ -40,7 +37,6 @@
android:largeHeap="true"
android:localeConfig="@xml/locales_config"
android:networkSecurityConfig="@xml/network_security_config"
- android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Tachiyomi">
diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt
index 0d86cabbe..4ffd15d77 100644
--- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt
+++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt
@@ -35,7 +35,6 @@ import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.more.settings.screen.data.CreateBackupScreen
import eu.kanade.presentation.more.settings.widget.BasePreferenceWidget
import eu.kanade.presentation.more.settings.widget.PrefsHorizontalPadding
-import eu.kanade.presentation.permissions.PermissionRequestHelper
import eu.kanade.presentation.util.relativeTimeSpanString
import eu.kanade.tachiyomi.data.backup.BackupCreateJob
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
@@ -73,8 +72,6 @@ object SettingsDataScreen : SearchableSettings {
val backupPreferences = Injekt.get()
val storagePreferences = Injekt.get()
- PermissionRequestHelper.requestStoragePermission()
-
return listOf(
getStorageLocationPref(storagePreferences = storagePreferences),
Preference.PreferenceItem.InfoPreference(stringResource(MR.strings.pref_storage_location_info)),
diff --git a/app/src/main/java/eu/kanade/presentation/permissions/PermissionRequestHelper.kt b/app/src/main/java/eu/kanade/presentation/permissions/PermissionRequestHelper.kt
deleted file mode 100644
index 7ce28f9da..000000000
--- a/app/src/main/java/eu/kanade/presentation/permissions/PermissionRequestHelper.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package eu.kanade.presentation.permissions
-
-import android.Manifest
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import com.google.accompanist.permissions.rememberPermissionState
-
-/**
- * Launches request for [Manifest.permission.WRITE_EXTERNAL_STORAGE] permission
- */
-object PermissionRequestHelper {
-
- @Composable
- fun requestStoragePermission() {
- val permissionState = rememberPermissionState(permission = Manifest.permission.WRITE_EXTERNAL_STORAGE)
- LaunchedEffect(Unit) {
- permissionState.launchPermissionRequest()
- }
- }
-}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt
index 8f103c47f..374839eea 100755
--- a/app/src/main/java/eu/kanade/tachiyomi/App.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt
@@ -27,7 +27,6 @@ import com.elvishew.xlog.XLog
import com.elvishew.xlog.printer.AndroidPrinter
import com.elvishew.xlog.printer.Printer
import com.elvishew.xlog.printer.file.backup.NeverBackupStrategy
-import com.elvishew.xlog.printer.file.clean.FileLastModifiedCleanStrategy
import com.elvishew.xlog.printer.file.naming.DateFileNameGenerator
import eu.kanade.domain.DomainModule
import eu.kanade.domain.SYDomainModule
@@ -67,7 +66,6 @@ import logcat.LogPriority
import logcat.LogcatLogger
import org.conscrypt.Conscrypt
import tachiyomi.core.i18n.stringResource
-import tachiyomi.core.storage.toFile
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.storage.service.StorageManager
import tachiyomi.i18n.MR
@@ -78,7 +76,6 @@ import uy.kohesive.injekt.injectLazy
import java.security.Security
import java.text.SimpleDateFormat
import java.util.Locale
-import kotlin.time.Duration.Companion.days
class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
@@ -250,8 +247,6 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
val printers = mutableListOf(AndroidPrinter())
val logFolder = Injekt.get().getLogsDirectory()
- ?.toFile()
- ?.absolutePath
if (logFolder != null) {
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
@@ -269,7 +264,6 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
flattener { timeMillis, level, tag, message ->
"${dateFormat.format(timeMillis)} ${LogLevel.getShortLevelName(level)}/$tag: $message"
}
- cleanStrategy = FileLastModifiedCleanStrategy(7.days.inWholeMilliseconds)
backupStrategy = NeverBackupStrategy()
}
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt
index 7624cfa0b..ec9daa07c 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt
@@ -17,7 +17,6 @@ import cafe.adriel.voyager.navigator.tab.TabOptions
import eu.kanade.core.preference.asState
import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.components.TabbedScreen
-import eu.kanade.presentation.permissions.PermissionRequestHelper
import eu.kanade.presentation.util.Tab
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsScreenModel
@@ -91,9 +90,6 @@ data class BrowseTab(
onChangeSearchQuery = extensionsScreenModel::search,
)
- // For local source
- PermissionRequestHelper.requestStoragePermission()
-
LaunchedEffect(Unit) {
(context as? MainActivity)?.ready = true
}
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 570cd3720..d3364677f 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,6 +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.util.lang.withIOContext
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.manga.model.Manga
@@ -124,13 +125,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)
+ is Format.Zip -> ZipPageLoader(format.file.toTempFile(context))
is Format.Rar -> try {
- RarPageLoader(format.file)
+ RarPageLoader(format.file.toTempFile(context))
} catch (e: UnsupportedRarV5Exception) {
error(context.stringResource(MR.strings.loader_rar5_error))
}
- is Format.Epub -> EpubPageLoader(format.file)
+ is Format.Epub -> EpubPageLoader(format.file.toTempFile(context))
}
}
else -> error(context.stringResource(MR.strings.loader_not_implemented_error))
@@ -141,13 +142,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)
+ is Format.Zip -> ZipPageLoader(format.file.toTempFile(context))
is Format.Rar -> try {
- RarPageLoader(format.file)
+ RarPageLoader(format.file.toTempFile(context))
} catch (e: UnsupportedRarV5Exception) {
error(context.stringResource(MR.strings.loader_rar5_error))
}
- is Format.Epub -> EpubPageLoader(format.file)
+ is Format.Epub -> EpubPageLoader(format.file.toTempFile(context))
}
}
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 d01706e3f..d2fe3de04 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,6 +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.domain.manga.model.Manga
import uy.kohesive.injekt.injectLazy
@@ -46,7 +47,7 @@ internal class DownloadPageLoader(
}
private suspend fun getPagesFromArchive(chapterPath: UniFile): List {
- val loader = ZipPageLoader(chapterPath).also { zipPageLoader = it }
+ val loader = ZipPageLoader(chapterPath.toTempFile(context)).also { zipPageLoader = it }
return loader.getPages()
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt
index cd00e3756..324af51bf 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt
@@ -1,14 +1,14 @@
package eu.kanade.tachiyomi.ui.reader.loader
-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: UniFile) : PageLoader() {
+internal class EpubPageLoader(file: File) : PageLoader() {
private val epub = EpubFile(file)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt
index 86c91dc7a..1d8598fe9 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt
@@ -8,7 +8,6 @@ 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 tachiyomi.core.storage.toFile
import tachiyomi.core.util.system.ImageUtil
import uy.kohesive.injekt.injectLazy
import java.io.File
@@ -19,9 +18,9 @@ import java.io.PipedOutputStream
/**
* Loader used to load a chapter from a .rar or .cbr file.
*/
-internal class RarPageLoader(file: UniFile) : PageLoader() {
+internal class RarPageLoader(file: File) : PageLoader() {
- private val rar = Archive(file.toFile())
+ private val rar = Archive(file)
// SY -->
private val context: Application by injectLazy()
@@ -33,7 +32,7 @@ internal class RarPageLoader(file: UniFile) : PageLoader() {
init {
if (readerPreferences.cacheArchiveMangaOnDisk().get()) {
tmpDir.mkdirs()
- Archive(file.toFile()).use { rar ->
+ Archive(file).use { rar ->
rar.fileHeaders.asSequence()
.filterNot { it.isDirectory }
.forEach { header ->
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt
index f9238f453..81c4d2509 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt
@@ -9,7 +9,6 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.util.lang.compareToCaseInsensitiveNaturalOrder
import eu.kanade.tachiyomi.util.storage.CbzCrypto
import tachiyomi.core.i18n.stringResource
-import tachiyomi.core.storage.toFile
import tachiyomi.core.util.system.ImageUtil
import tachiyomi.i18n.sy.SYMR
import uy.kohesive.injekt.injectLazy
@@ -21,7 +20,7 @@ import net.lingala.zip4j.ZipFile as Zip4jFile
/**
* Loader used to load a chapter from a .zip or .cbz file.
*/
-internal class ZipPageLoader(file: UniFile) : PageLoader() {
+internal class ZipPageLoader(file: File) : PageLoader() {
// SY -->
private val context: Application by injectLazy()
@@ -29,12 +28,12 @@ internal class ZipPageLoader(file: UniFile) : PageLoader() {
private val tmpDir = File(context.externalCacheDir, "reader_${file.hashCode()}").also {
it.deleteRecursively()
}
- private val zip4j: Zip4jFile = Zip4jFile(file.toFile())
+ private val zip4j: Zip4jFile = Zip4jFile(file)
private val zip: ZipFile? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- if (!zip4j.isEncrypted) ZipFile(file.toFile(), StandardCharsets.ISO_8859_1) else null
+ if (!zip4j.isEncrypted) ZipFile(file, StandardCharsets.ISO_8859_1) else null
} else {
- if (!zip4j.isEncrypted) ZipFile(file.toFile()) else null
+ if (!zip4j.isEncrypted) ZipFile(file) else null
}
init {
@@ -42,7 +41,7 @@ internal class ZipPageLoader(file: UniFile) : PageLoader() {
zip4j.charset = StandardCharsets.ISO_8859_1
}
- Zip4jFile(file.toFile()).use { zip ->
+ Zip4jFile(file).use { zip ->
if (zip.isEncrypted) {
if (!CbzCrypto.checkCbzPassword(zip, CbzCrypto.getDecryptedPasswordCbz())) {
this.recycle()
diff --git a/app/src/main/java/exh/log/EnhancedFilePrinter.kt b/app/src/main/java/exh/log/EnhancedFilePrinter.kt
index e3269c2aa..0bd6fee20 100644
--- a/app/src/main/java/exh/log/EnhancedFilePrinter.kt
+++ b/app/src/main/java/exh/log/EnhancedFilePrinter.kt
@@ -3,14 +3,14 @@ package exh.log
import com.elvishew.xlog.internal.DefaultsFactory
import com.elvishew.xlog.printer.Printer
import com.elvishew.xlog.printer.file.backup.BackupStrategy
-import com.elvishew.xlog.printer.file.clean.CleanStrategy
import com.elvishew.xlog.printer.file.naming.FileNameGenerator
+import com.hippo.unifile.UniFile
+import exh.log.EnhancedFilePrinter.Builder
import java.io.BufferedWriter
-import java.io.File
-import java.io.FileWriter
import java.io.IOException
import java.util.concurrent.BlockingQueue
import java.util.concurrent.LinkedBlockingQueue
+import kotlin.time.Duration.Companion.days
import com.elvishew.xlog.flattener.Flattener2 as Flattener
/**
@@ -18,7 +18,7 @@ import com.elvishew.xlog.flattener.Flattener2 as Flattener
*
* Use the [Builder] to construct a [EnhancedFilePrinter] object.
*
- * @param folderPath The folder path of log file.
+ * @param folder The folder path of log file.
* @param fileNameGenerator the file name generator for log file.
* @param backupStrategy the backup strategy for log file.
* @param cleanStrategy The clean strategy for log file.
@@ -27,10 +27,9 @@ import com.elvishew.xlog.flattener.Flattener2 as Flattener
*/
@Suppress("unused")
class EnhancedFilePrinter internal constructor(
- private val folderPath: String,
+ private val folder: UniFile,
private val fileNameGenerator: FileNameGenerator,
private val backupStrategy: BackupStrategy,
- private val cleanStrategy: CleanStrategy,
private val flattener: Flattener,
) : Printer {
/**
@@ -41,16 +40,6 @@ class EnhancedFilePrinter internal constructor(
@Volatile
private var worker: Worker? = null
- /**
- * Make sure the folder of log file exists.
- */
- private fun checkLogFolder() {
- val folder = File(folderPath)
- if (!folder.exists()) {
- folder.mkdirs()
- }
- }
-
override fun println(logLevel: Int, tag: String, msg: String) {
val timeMillis = System.currentTimeMillis()
if (USE_WORKER) {
@@ -68,8 +57,8 @@ class EnhancedFilePrinter internal constructor(
* Do the real job of writing log to file.
*/
private fun doPrintln(timeMillis: Long, logLevel: Int, tag: String, msg: String) {
- var lastFileName = writer.lastFileName
- if (lastFileName == null || fileNameGenerator.isFileNameChangeable) {
+ val lastFileName = writer.lastFileName
+ if (fileNameGenerator.isFileNameChangeable) {
val newFileName = fileNameGenerator.generateFileName(logLevel, System.currentTimeMillis())
require(!(newFileName == null || newFileName.trim { it <= ' ' }.isEmpty())) { "File name should not be empty." }
if (newFileName != lastFileName) {
@@ -77,37 +66,29 @@ class EnhancedFilePrinter internal constructor(
writer.close()
}
cleanLogFilesIfNecessary()
- if (writer.open(newFileName).not()) {
+ if (writer.open(folder.createFile(newFileName)!!).not()) {
return
}
- lastFileName = newFileName
- }
- }
- val lastFile = writer.file ?: return
- if (backupStrategy.shouldBackup(lastFile)) {
- // Backup the log file, and create a new log file.
- writer.close()
- val backupFile = File(folderPath, "$lastFileName.bak")
- if (backupFile.exists()) {
- backupFile.delete()
- }
- lastFile.renameTo(backupFile)
- if (writer.open(lastFileName).not()) {
- return
}
}
val flattenedLog = flattener.flatten(timeMillis, logLevel, tag, msg).toString()
writer.appendLog(flattenedLog)
}
+ private val maxTimeMillis = 7.days.inWholeMilliseconds
+ private fun shouldClean(file: UniFile): Boolean {
+ val currentTimeMillis = System.currentTimeMillis()
+ val lastModified = file.lastModified()
+ return currentTimeMillis - lastModified > maxTimeMillis
+ }
+
/**
* Clean log files if should clean follow strategy
*/
private fun cleanLogFilesIfNecessary() {
- val logDir = File(folderPath)
- logDir.listFiles().orEmpty()
+ folder.listFiles().orEmpty()
.asSequence()
- .filter { cleanStrategy.shouldClean(it) }
+ .filter { shouldClean(it) }
.forEach { it.delete() }
}
@@ -115,7 +96,7 @@ class EnhancedFilePrinter internal constructor(
* Builder for [EnhancedFilePrinter].
* @param folderPath the folder path of log file
*/
- class Builder(private val folderPath: String) {
+ class Builder(private val folder: UniFile) {
/**
* The file name generator for log file.
*/
@@ -126,11 +107,6 @@ class EnhancedFilePrinter internal constructor(
*/
var backupStrategy: BackupStrategy? = null
- /**
- * The clean strategy for log file.
- */
- var cleanStrategy: CleanStrategy? = null
-
/**
* The flattener when print a log.
*/
@@ -158,17 +134,6 @@ class EnhancedFilePrinter internal constructor(
return this
}
- /**
- * Set the clean strategy for log file.
- *
- * @param cleanStrategy the clean strategy for log file
- * @return the builder
- */
- fun cleanStrategy(cleanStrategy: CleanStrategy): Builder {
- this.cleanStrategy = cleanStrategy
- return this
- }
-
/**
* Set the flattener when print a log.
*
@@ -187,17 +152,16 @@ class EnhancedFilePrinter internal constructor(
*/
fun build(): EnhancedFilePrinter {
return EnhancedFilePrinter(
- folderPath,
+ folder,
fileNameGenerator ?: DefaultsFactory.createFileNameGenerator(),
backupStrategy ?: DefaultsFactory.createBackupStrategy(),
- cleanStrategy ?: DefaultsFactory.createCleanStrategy(),
flattener ?: DefaultsFactory.createFlattener2(),
)
}
companion object {
- operator fun invoke(folderPath: String, block: Builder.() -> Unit): EnhancedFilePrinter {
- return Builder(folderPath).apply(block).build()
+ operator fun invoke(folder: UniFile, block: Builder.() -> Unit): EnhancedFilePrinter {
+ return Builder(folder).apply(block).build()
}
}
}
@@ -271,9 +235,6 @@ class EnhancedFilePrinter internal constructor(
* Get the name of last used log file.
* @return the name of last used log file, maybe null
*/
- /**
- * The file name of last used log file.
- */
var lastFileName: String? = null
private set
/**
@@ -281,10 +242,7 @@ class EnhancedFilePrinter internal constructor(
*
* @return the current log file, maybe null
*/
- /**
- * The current log file.
- */
- var file: File? = null
+ var file: UniFile? = null
private set
private var bufferedWriter: BufferedWriter? = null
@@ -303,15 +261,10 @@ class EnhancedFilePrinter internal constructor(
* @param newFileName the specific file name
* @return true if opened successfully, false otherwise
*/
- fun open(newFileName: String): Boolean {
+ fun open(file: UniFile): Boolean {
return try {
- val file = File(folderPath, newFileName)
- if (file.exists().not()) {
- (file.parentFile ?: File(file.absolutePath.substringBeforeLast(File.separatorChar))).mkdirs()
- file.createNewFile()
- }
- bufferedWriter = FileWriter(file, true).buffered()
- lastFileName = newFileName
+ bufferedWriter = file.openOutputStream().bufferedWriter()
+ lastFileName = file.name
this.file = file
true
} catch (e: Exception) {
@@ -370,6 +323,5 @@ class EnhancedFilePrinter internal constructor(
if (USE_WORKER) {
worker = Worker()
}
- checkLogFolder()
}
}
diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt b/core/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt
index 7650f65b5..a00ee69e7 100644
--- a/core/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt
+++ b/core/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt
@@ -1,9 +1,7 @@
package eu.kanade.tachiyomi.util.storage
-import com.hippo.unifile.UniFile
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
-import tachiyomi.core.storage.toFile
import java.io.Closeable
import java.io.File
import java.io.InputStream
@@ -13,12 +11,12 @@ import java.util.zip.ZipFile
/**
* Wrapper over ZipFile to load files in epub format.
*/
-class EpubFile(file: UniFile) : Closeable {
+class EpubFile(file: File) : Closeable {
/**
* Zip file of this epub.
*/
- private val zip = ZipFile(file.toFile())
+ private val zip = ZipFile(file)
/**
* Path separator used by this epub.
diff --git a/core/src/main/java/tachiyomi/core/storage/UniFileExtensions.kt b/core/src/main/java/tachiyomi/core/storage/UniFileExtensions.kt
index 5343dfa3f..c5c2bbbc8 100644
--- a/core/src/main/java/tachiyomi/core/storage/UniFileExtensions.kt
+++ b/core/src/main/java/tachiyomi/core/storage/UniFileExtensions.kt
@@ -1,6 +1,10 @@
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?
@@ -9,4 +13,26 @@ val UniFile.extension: String?
val UniFile.nameWithoutExtension: String?
get() = name?.substringBeforeLast('.')
-fun UniFile.toFile(): File? = filePath?.let { File(it) }
+fun UniFile.toTempFile(context: Context): File {
+ val inputStream = context.contentResolver.openInputStream(uri)!!
+ val tempFile = File.createTempFile(
+ nameWithoutExtension.orEmpty(),
+ 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/gradle/compose.versions.toml b/gradle/compose.versions.toml
index 39074cb0c..ce7b074bf 100644
--- a/gradle/compose.versions.toml
+++ b/gradle/compose.versions.toml
@@ -22,7 +22,6 @@ material-core = { module = "androidx.compose.material:material" }
glance = "androidx.glance:glance-appwidget:1.0.0"
accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" }
-accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" }
lintchecks = { module = "com.slack.lint.compose:compose-lint-checks", version = "1.2.0" }
\ No newline at end of file
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 911ac4d93..f02760355 100755
--- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt
+++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt
@@ -30,7 +30,7 @@ import tachiyomi.core.metadata.comicinfo.getComicInfo
import tachiyomi.core.metadata.tachiyomi.MangaDetails
import tachiyomi.core.storage.extension
import tachiyomi.core.storage.nameWithoutExtension
-import tachiyomi.core.storage.toFile
+import tachiyomi.core.storage.toTempFile
import tachiyomi.core.util.lang.withIOContext
import tachiyomi.core.util.system.ImageUtil
import tachiyomi.core.util.system.logcat
@@ -154,12 +154,12 @@ actual class LocalSource(
// SY -->
fun updateMangaInfo(manga: SManga) {
- val directory = fileSystem.getFilesInBaseDirectory().map { File(it.toFile(), manga.url) }.find {
- it.exists()
+ val directory = fileSystem.getFilesInBaseDirectory().map { it.createDirectory(manga.url) }.find {
+ it?.exists() == true
} ?: return
- val existingFileName = directory.listFiles()?.find { it.extension == "json" }?.name
- val file = File(directory, existingFileName ?: "info.json")
- file.outputStream().use {
+ val existingFile = directory.listFiles()?.find { it.extension == "json" }
+ val file = existingFile ?: directory.createFile("info.json") ?: return
+ file.openOutputStream().use {
json.encodeToStream(manga.toJson(), it)
}
}
@@ -199,7 +199,7 @@ actual class LocalSource(
}
// SY -->
comicInfoArchiveFile != null -> {
- val comicInfoArchive = ZipFile(comicInfoArchiveFile.toFile())
+ val comicInfoArchive = ZipFile(comicInfoArchiveFile.toTempFile(context))
noXmlFile?.delete()
if (CbzCrypto.checkCbzPassword(comicInfoArchive, CbzCrypto.getDecryptedPasswordCbz())) {
@@ -269,7 +269,7 @@ actual class LocalSource(
for (chapter in chapterArchives) {
when (Format.valueOf(chapter)) {
is Format.Zip -> {
- ZipFile(chapter.toFile()).use { zip: ZipFile ->
+ ZipFile(chapter.toTempFile(context)).use { zip: ZipFile ->
// SY -->
if (zip.isEncrypted && !CbzCrypto.checkCbzPassword(zip, CbzCrypto.getDecryptedPasswordCbz())
) {
@@ -288,7 +288,7 @@ actual class LocalSource(
}
}
is Format.Rar -> {
- JunrarArchive(chapter.toFile()).use { rar ->
+ JunrarArchive(chapter.toTempFile(context)).use { rar ->
rar.fileHeaders.firstOrNull { it.fileName == COMIC_INFO_FILE }?.let { comicInfoFile ->
rar.getInputStream(comicInfoFile).buffered().use { stream ->
return copyComicInfoFile(stream, folderPath)
@@ -354,7 +354,7 @@ actual class LocalSource(
val format = Format.valueOf(chapterFile)
if (format is Format.Epub) {
- EpubFile(format.file).use { epub ->
+ EpubFile(format.file.toTempFile(context)).use { epub ->
epub.fillMetadata(manga, this)
}
}
@@ -413,7 +413,7 @@ actual class LocalSource(
entry?.let { coverManager.update(manga, it.openInputStream()) }
}
is Format.Zip -> {
- ZipFile(format.file.toFile()).use { zip ->
+ ZipFile(format.file.toTempFile(context)).use { zip ->
// SY -->
var encrypted = false
if (zip.isEncrypted) {
@@ -428,7 +428,7 @@ actual class LocalSource(
}
}
is Format.Rar -> {
- JunrarArchive(format.file.toFile()).use { archive ->
+ JunrarArchive(format.file.toTempFile(context)).use { archive ->
val entry = archive.fileHeaders
.sortedWith { f1, f2 -> f1.fileName.compareToCaseInsensitiveNaturalOrder(f2.fileName) }
.find { !it.isDirectory && ImageUtil.isImage(it.fileName) { archive.getInputStream(it) } }
@@ -437,7 +437,7 @@ actual class LocalSource(
}
}
is Format.Epub -> {
- EpubFile(format.file).use { epub ->
+ EpubFile(format.file.toTempFile(context)).use { epub ->
val entry = epub.getImagesFromPages()
.firstOrNull()
?.let { epub.getEntry(it) }
diff --git a/source-local/src/androidMain/kotlin/tachiyomi/source/local/image/LocalCoverManager.kt b/source-local/src/androidMain/kotlin/tachiyomi/source/local/image/LocalCoverManager.kt
index 3e81855a5..c78e28815 100644
--- a/source-local/src/androidMain/kotlin/tachiyomi/source/local/image/LocalCoverManager.kt
+++ b/source-local/src/androidMain/kotlin/tachiyomi/source/local/image/LocalCoverManager.kt
@@ -8,7 +8,6 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil
import net.lingala.zip4j.ZipFile
import net.lingala.zip4j.model.ZipParameters
import tachiyomi.core.storage.nameWithoutExtension
-import tachiyomi.core.storage.toFile
import tachiyomi.core.util.system.ImageUtil
import tachiyomi.source.local.io.LocalSourceFileSystem
import java.io.File
@@ -61,12 +60,22 @@ actual class LocalCoverManager(
inputStream.use { input ->
// SY -->
if (encrypted) {
- val zip4j = ZipFile(targetFile.toFile())
+ val tempFile = File.createTempFile(
+ targetFile.nameWithoutExtension.orEmpty(),
+ null,
+ )
+ val zip4j = ZipFile(tempFile)
val zipParameters = ZipParameters()
zip4j.setPassword(CbzCrypto.getDecryptedPasswordCbz())
CbzCrypto.setZipParametersEncrypted(zipParameters)
zipParameters.fileNameInZip = DEFAULT_COVER_NAME
zip4j.addStream(input, zipParameters)
+ zip4j.close()
+ targetFile.openOutputStream().use { output ->
+ tempFile.inputStream().use { input ->
+ input.copyTo(output)
+ }
+ }
DiskUtil.createNoMediaFile(directory, context)