Actually use configured storage location for local source

Fixes #10178
This commit is contained in:
arkon 2023-11-25 22:31:26 -05:00
parent ca54984344
commit 27c4db752c
9 changed files with 76 additions and 46 deletions

View file

@ -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()
} }
} }

View file

@ -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 { private fun getAutomaticBackupLocation(): Uri? {
val storagePreferences = Injekt.get<StoragePreferences>() val storageManager = Injekt.get<StorageManager>()
return storagePreferences.baseStorageDirectory().get().let { return storageManager.getAutomaticBackupsDirectory()?.uri
val dir = UniFile.fromUri(context, it.toUri())
.createDirectory(StoragePreferences.BACKUP_DIR)
dir.uri
}
} }
companion object { companion object {

View file

@ -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 get() = storageManager.getDownloadsDirectory()
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) }
}
/** /**
* Returns the download directory for a manga. For internal use only. * Returns the download directory for a manga. For internal use only.

View file

@ -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 {

View file

@ -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)

View file

@ -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"

View file

@ -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"
}
} }

View file

@ -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) {

View file

@ -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 storageManager: StorageManager,
private val folderProvider: FolderProvider,
) { ) {
actual fun getBaseDirectory(): UniFile? { actual fun getBaseDirectory(): UniFile? {
return UniFile.fromUri(context, folderProvider.path().toUri()) return storageManager.getLocalSourceDirectory()
?.createDirectory("local")
} }
actual fun getFilesInBaseDirectory(): List<UniFile> { actual fun getFilesInBaseDirectory(): List<UniFile> {