ソースを参照

Actually use configured storage location for local source

Fixes #10178
arkon 1 年間 前
コミット
27c4db752c

+ 2 - 0
app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt

@@ -42,6 +42,7 @@ import eu.kanade.tachiyomi.data.backup.BackupCreateJob
 import eu.kanade.tachiyomi.data.backup.BackupFileValidator
 import eu.kanade.tachiyomi.data.backup.BackupFileValidator
 import eu.kanade.tachiyomi.data.backup.BackupRestoreJob
 import eu.kanade.tachiyomi.data.backup.BackupRestoreJob
 import eu.kanade.tachiyomi.data.cache.ChapterCache
 import eu.kanade.tachiyomi.data.cache.ChapterCache
+import eu.kanade.tachiyomi.data.download.DownloadCache
 import eu.kanade.tachiyomi.util.storage.DiskUtil
 import eu.kanade.tachiyomi.util.storage.DiskUtil
 import eu.kanade.tachiyomi.util.system.DeviceUtil
 import eu.kanade.tachiyomi.util.system.DeviceUtil
 import eu.kanade.tachiyomi.util.system.copyToClipboard
 import eu.kanade.tachiyomi.util.system.copyToClipboard
@@ -100,6 +101,7 @@ object SettingsDataScreen : SearchableSettings {
 
 
                 val file = UniFile.fromUri(context, uri)
                 val file = UniFile.fromUri(context, uri)
                 storageDirPref.set(file.uri.toString())
                 storageDirPref.set(file.uri.toString())
+                Injekt.get<DownloadCache>().invalidateCache()
             }
             }
         }
         }
 
 

+ 6 - 8
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateJob.kt

@@ -21,7 +21,7 @@ import eu.kanade.tachiyomi.util.system.workManager
 import logcat.LogPriority
 import logcat.LogPriority
 import tachiyomi.core.util.system.logcat
 import tachiyomi.core.util.system.logcat
 import tachiyomi.domain.backup.service.BackupPreferences
 import tachiyomi.domain.backup.service.BackupPreferences
-import tachiyomi.domain.storage.service.StoragePreferences
+import tachiyomi.domain.storage.service.StorageManager
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 import uy.kohesive.injekt.api.get
 import java.util.Date
 import java.util.Date
@@ -43,6 +43,8 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete
 
 
         val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
         val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
             ?: getAutomaticBackupLocation()
             ?: getAutomaticBackupLocation()
+            ?: return Result.failure()
+
         val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupCreateFlags.AutomaticDefaults)
         val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupCreateFlags.AutomaticDefaults)
 
 
         try {
         try {
@@ -75,13 +77,9 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete
         )
         )
     }
     }
 
 
-    private fun getAutomaticBackupLocation(): Uri {
-        val storagePreferences = Injekt.get<StoragePreferences>()
-        return storagePreferences.baseStorageDirectory().get().let {
-            val dir = UniFile.fromUri(context, it.toUri())
-                .createDirectory(StoragePreferences.BACKUP_DIR)
-            dir.uri
-        }
+    private fun getAutomaticBackupLocation(): Uri? {
+        val storageManager = Injekt.get<StorageManager>()
+        return storageManager.getAutomaticBackupsDirectory()?.uri
     }
     }
 
 
     companion object {
     companion object {

+ 3 - 24
app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt

@@ -1,20 +1,15 @@
 package eu.kanade.tachiyomi.data.download
 package eu.kanade.tachiyomi.data.download
 
 
 import android.content.Context
 import android.content.Context
-import androidx.core.net.toUri
 import com.hippo.unifile.UniFile
 import com.hippo.unifile.UniFile
 import eu.kanade.tachiyomi.source.Source
 import eu.kanade.tachiyomi.source.Source
 import eu.kanade.tachiyomi.util.storage.DiskUtil
 import eu.kanade.tachiyomi.util.storage.DiskUtil
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
 import logcat.LogPriority
 import logcat.LogPriority
 import tachiyomi.core.i18n.stringResource
 import tachiyomi.core.i18n.stringResource
 import tachiyomi.core.util.system.logcat
 import tachiyomi.core.util.system.logcat
 import tachiyomi.domain.chapter.model.Chapter
 import tachiyomi.domain.chapter.model.Chapter
 import tachiyomi.domain.manga.model.Manga
 import tachiyomi.domain.manga.model.Manga
-import tachiyomi.domain.storage.service.StoragePreferences
+import tachiyomi.domain.storage.service.StorageManager
 import tachiyomi.i18n.MR
 import tachiyomi.i18n.MR
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 import uy.kohesive.injekt.api.get
@@ -27,27 +22,11 @@ import uy.kohesive.injekt.api.get
  */
  */
 class DownloadProvider(
 class DownloadProvider(
     private val context: Context,
     private val context: Context,
-    storagePreferences: StoragePreferences = Injekt.get(),
+    private val storageManager: StorageManager = Injekt.get(),
 ) {
 ) {
 
 
-    private val scope = CoroutineScope(Dispatchers.IO)
-
-    private var _downloadsDir: UniFile? =
-        storagePreferences.baseStorageDirectory().get().let(::getDownloadsLocation)
     val downloadsDir: UniFile?
     val downloadsDir: UniFile?
-        get() = _downloadsDir
-
-    init {
-        storagePreferences.baseStorageDirectory().changes()
-            .onEach { _downloadsDir = getDownloadsLocation(it) }
-            .launchIn(scope)
-    }
-
-    private fun getDownloadsLocation(dir: String): UniFile? {
-        return UniFile.fromUri(context, dir.toUri())
-            ?.createDirectory(StoragePreferences.DOWNLOADS_DIR)
-            ?.also { DiskUtil.createNoMediaFile(it, context) }
-    }
+        get() = storageManager.getDownloadsDirectory()
 
 
     /**
     /**
      * Returns the download directory for a manga. For internal use only.
      * Returns the download directory for a manga. For internal use only.

+ 3 - 1
app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt

@@ -35,6 +35,7 @@ import tachiyomi.data.Mangas
 import tachiyomi.data.StringListColumnAdapter
 import tachiyomi.data.StringListColumnAdapter
 import tachiyomi.data.UpdateStrategyColumnAdapter
 import tachiyomi.data.UpdateStrategyColumnAdapter
 import tachiyomi.domain.source.service.SourceManager
 import tachiyomi.domain.source.service.SourceManager
+import tachiyomi.domain.storage.service.StorageManager
 import tachiyomi.source.local.image.LocalCoverManager
 import tachiyomi.source.local.image.LocalCoverManager
 import tachiyomi.source.local.io.LocalSourceFileSystem
 import tachiyomi.source.local.io.LocalSourceFileSystem
 import uy.kohesive.injekt.api.InjektModule
 import uy.kohesive.injekt.api.InjektModule
@@ -125,8 +126,9 @@ class AppModule(val app: Application) : InjektModule {
         addSingletonFactory { ImageSaver(app) }
         addSingletonFactory { ImageSaver(app) }
 
 
         addSingletonFactory { AndroidStorageFolderProvider(app) }
         addSingletonFactory { AndroidStorageFolderProvider(app) }
-        addSingletonFactory { LocalSourceFileSystem(app, get<AndroidStorageFolderProvider>()) }
+        addSingletonFactory { LocalSourceFileSystem(get()) }
         addSingletonFactory { LocalCoverManager(app, get()) }
         addSingletonFactory { LocalCoverManager(app, get()) }
+        addSingletonFactory { StorageManager(app, get()) }
 
 
         // Asynchronously init expensive components for a faster cold start
         // Asynchronously init expensive components for a faster cold start
         ContextCompat.getMainExecutor(app).execute {
         ContextCompat.getMainExecutor(app).execute {

+ 2 - 0
domain/build.gradle.kts

@@ -19,6 +19,8 @@ dependencies {
     implementation(platform(kotlinx.coroutines.bom))
     implementation(platform(kotlinx.coroutines.bom))
     implementation(kotlinx.bundles.coroutines)
     implementation(kotlinx.bundles.coroutines)
 
 
+    implementation(libs.unifile)
+
     api(libs.sqldelight.android.paging)
     api(libs.sqldelight.android.paging)
 
 
     testImplementation(libs.bundles.test)
     testImplementation(libs.bundles.test)

+ 54 - 0
domain/src/main/java/tachiyomi/domain/storage/service/StorageManager.kt

@@ -0,0 +1,54 @@
+package tachiyomi.domain.storage.service
+
+import android.content.Context
+import androidx.core.net.toUri
+import com.hippo.unifile.UniFile
+import eu.kanade.tachiyomi.util.storage.DiskUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+
+class StorageManager(
+    private val context: Context,
+    storagePreferences: StoragePreferences,
+) {
+
+    private val scope = CoroutineScope(Dispatchers.IO)
+
+    private var baseDir: UniFile? = storagePreferences.baseStorageDirectory().get().let(::getBaseDir)
+
+    init {
+        storagePreferences.baseStorageDirectory().changes()
+            .onEach { baseDir = getBaseDir(it) }
+            .launchIn(scope)
+    }
+
+    private fun getBaseDir(path: String): UniFile? {
+        val file = UniFile.fromUri(context, path.toUri())
+
+        return file.takeIf { it?.exists() == true }?.also { parent ->
+            parent.createDirectory(AUTOMATIC_BACKUPS_PATH)
+            parent.createDirectory(LOCAL_SOURCE_PATH)
+            parent.createDirectory(DOWNLOADS_PATH).also {
+                DiskUtil.createNoMediaFile(it, context)
+            }
+        }
+    }
+
+    fun getAutomaticBackupsDirectory(): UniFile? {
+        return baseDir?.createDirectory(AUTOMATIC_BACKUPS_PATH)
+    }
+
+    fun getDownloadsDirectory(): UniFile? {
+        return baseDir?.createDirectory(DOWNLOADS_PATH)
+    }
+
+    fun getLocalSourceDirectory(): UniFile? {
+        return baseDir?.createDirectory(LOCAL_SOURCE_PATH)
+    }
+}
+
+private const val AUTOMATIC_BACKUPS_PATH = "autobackup"
+private const val DOWNLOADS_PATH = "downloads"
+private const val LOCAL_SOURCE_PATH = "local"

+ 0 - 5
domain/src/main/java/tachiyomi/domain/storage/service/StoragePreferences.kt

@@ -9,9 +9,4 @@ class StoragePreferences(
 ) {
 ) {
 
 
     fun baseStorageDirectory() = preferenceStore.getString("storage_dir", folderProvider.path())
     fun baseStorageDirectory() = preferenceStore.getString("storage_dir", folderProvider.path())
-
-    companion object {
-        const val BACKUP_DIR = "autobackup"
-        const val DOWNLOADS_DIR = "downloads"
-    }
 }
 }

+ 3 - 1
source-local/src/androidMain/kotlin/tachiyomi/source/local/LocalSource.kt

@@ -310,8 +310,10 @@ actual class LocalSource(
 
 
     fun getFormat(chapter: SChapter): Format {
     fun getFormat(chapter: SChapter): Format {
         try {
         try {
+            val (mangaDirName, chapterName) = chapter.url.split(File.separator, limit = 2)
             return fileSystem.getBaseDirectory()
             return fileSystem.getBaseDirectory()
-                ?.findFile(chapter.url)
+                ?.findFile(mangaDirName)
+                ?.findFile(chapterName)
                 ?.let(Format.Companion::valueOf)
                 ?.let(Format.Companion::valueOf)
                 ?: throw Exception(context.stringResource(MR.strings.chapter_not_found))
                 ?: throw Exception(context.stringResource(MR.strings.chapter_not_found))
         } catch (e: Format.UnknownFormatException) {
         } catch (e: Format.UnknownFormatException) {

+ 3 - 7
source-local/src/androidMain/kotlin/tachiyomi/source/local/io/LocalSourceFileSystem.kt

@@ -1,18 +1,14 @@
 package tachiyomi.source.local.io
 package tachiyomi.source.local.io
 
 
-import android.content.Context
-import androidx.core.net.toUri
 import com.hippo.unifile.UniFile
 import com.hippo.unifile.UniFile
-import tachiyomi.core.storage.FolderProvider
+import tachiyomi.domain.storage.service.StorageManager
 
 
 actual class LocalSourceFileSystem(
 actual class LocalSourceFileSystem(
-    private val context: Context,
-    private val folderProvider: FolderProvider,
+    private val storageManager: StorageManager,
 ) {
 ) {
 
 
     actual fun getBaseDirectory(): UniFile? {
     actual fun getBaseDirectory(): UniFile? {
-        return UniFile.fromUri(context, folderProvider.path().toUri())
-            ?.createDirectory("local")
+        return storageManager.getLocalSourceDirectory()
     }
     }
 
 
     actual fun getFilesInBaseDirectory(): List<UniFile> {
     actual fun getFilesInBaseDirectory(): List<UniFile> {