Minor download location cleanup

This commit is contained in:
arkon 2023-11-25 16:51:32 -05:00
parent f1778ac5b4
commit 21ae04d25d
2 changed files with 54 additions and 41 deletions

View file

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.download
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import androidx.core.net.toUri
import com.hippo.unifile.UniFile import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
@ -19,6 +18,7 @@ import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart
@ -64,7 +64,7 @@ class DownloadCache(
private val provider: DownloadProvider = Injekt.get(), private val provider: DownloadProvider = Injekt.get(),
private val sourceManager: SourceManager = Injekt.get(), private val sourceManager: SourceManager = Injekt.get(),
private val extensionManager: ExtensionManager = Injekt.get(), private val extensionManager: ExtensionManager = Injekt.get(),
private val storagePreferences: StoragePreferences = Injekt.get(), storagePreferences: StoragePreferences = Injekt.get(),
) { ) {
private val scope = CoroutineScope(Dispatchers.IO) private val scope = CoroutineScope(Dispatchers.IO)
@ -95,16 +95,9 @@ class DownloadCache(
get() = File(context.cacheDir, "dl_index_cache") get() = File(context.cacheDir, "dl_index_cache")
private val rootDownloadsDirLock = Mutex() private val rootDownloadsDirLock = Mutex()
private var rootDownloadsDir = RootDirectory(getDirectoryFromPreference()) private var rootDownloadsDir = RootDirectory(provider.downloadsDir)
init { init {
storagePreferences.baseStorageDirectory().changes()
.onEach {
rootDownloadsDir = RootDirectory(getDirectoryFromPreference())
invalidateCache()
}
.launchIn(scope)
// Attempt to read cache file // Attempt to read cache file
scope.launch { scope.launch {
rootDownloadsDirLock.withLock { rootDownloadsDirLock.withLock {
@ -119,6 +112,14 @@ class DownloadCache(
} }
} }
} }
storagePreferences.baseStorageDirectory().changes()
.drop(1)
.onEach {
rootDownloadsDir = RootDirectory(provider.downloadsDir)
invalidateCache()
}
.launchIn(scope)
} }
/** /**
@ -293,17 +294,6 @@ class DownloadCache(
renewalJob?.cancel() renewalJob?.cancel()
} }
/**
* Returns the downloads directory from the user's preferences.
*/
private fun getDirectoryFromPreference(): UniFile {
return storagePreferences.baseStorageDirectory().get().let {
UniFile.fromUri(context, it.toUri()).also {
it?.createDirectory(StoragePreferences.DOWNLOADS_DIR)
}
}
}
/** /**
* Renews the downloads cache. * Renews the downloads cache.
*/ */
@ -335,7 +325,7 @@ class DownloadCache(
val sourceMap = sources.associate { provider.getSourceDirName(it).lowercase() to it.id } val sourceMap = sources.associate { provider.getSourceDirName(it).lowercase() to it.id }
rootDownloadsDirLock.withLock { rootDownloadsDirLock.withLock {
val sourceDirs = rootDownloadsDir.dir.listFiles().orEmpty() val sourceDirs = rootDownloadsDir.dir?.listFiles().orEmpty()
.filter { it.isDirectory && !it.name.isNullOrBlank() } .filter { it.isDirectory && !it.name.isNullOrBlank() }
.mapNotNull { dir -> .mapNotNull { dir ->
val sourceId = sourceMap[dir.name!!.lowercase()] val sourceId = sourceMap[dir.name!!.lowercase()]
@ -348,12 +338,12 @@ class DownloadCache(
sourceDirs.values sourceDirs.values
.map { sourceDir -> .map { sourceDir ->
async { async {
sourceDir.mangaDirs = sourceDir.dir.listFiles().orEmpty() sourceDir.mangaDirs = sourceDir.dir?.listFiles().orEmpty()
.filter { it.isDirectory && !it.name.isNullOrBlank() } .filter { it.isDirectory && !it.name.isNullOrBlank() }
.associate { it.name!! to MangaDirectory(it) } .associate { it.name!! to MangaDirectory(it) }
sourceDir.mangaDirs.values.forEach { mangaDir -> sourceDir.mangaDirs.values.forEach { mangaDir ->
val chapterDirs = mangaDir.dir.listFiles().orEmpty() val chapterDirs = mangaDir.dir?.listFiles().orEmpty()
.mapNotNull { .mapNotNull {
when { when {
// Ignore incomplete downloads // Ignore incomplete downloads
@ -430,7 +420,7 @@ class DownloadCache(
@Serializable @Serializable
private class RootDirectory( private class RootDirectory(
@Serializable(with = UniFileAsStringSerializer::class) @Serializable(with = UniFileAsStringSerializer::class)
val dir: UniFile, val dir: UniFile?,
var sourceDirs: Map<Long, SourceDirectory> = mapOf(), var sourceDirs: Map<Long, SourceDirectory> = mapOf(),
) )
@ -440,7 +430,7 @@ private class RootDirectory(
@Serializable @Serializable
private class SourceDirectory( private class SourceDirectory(
@Serializable(with = UniFileAsStringSerializer::class) @Serializable(with = UniFileAsStringSerializer::class)
val dir: UniFile, val dir: UniFile?,
var mangaDirs: Map<String, MangaDirectory> = mapOf(), var mangaDirs: Map<String, MangaDirectory> = mapOf(),
) )
@ -450,17 +440,26 @@ private class SourceDirectory(
@Serializable @Serializable
private class MangaDirectory( private class MangaDirectory(
@Serializable(with = UniFileAsStringSerializer::class) @Serializable(with = UniFileAsStringSerializer::class)
val dir: UniFile, val dir: UniFile?,
var chapterDirs: MutableSet<String> = mutableSetOf(), var chapterDirs: MutableSet<String> = mutableSetOf(),
) )
private object UniFileAsStringSerializer : KSerializer<UniFile> { private object UniFileAsStringSerializer : KSerializer<UniFile?> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("UniFile", PrimitiveKind.STRING) override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("UniFile", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: UniFile) { override fun serialize(encoder: Encoder, value: UniFile?) {
return encoder.encodeString(value.uri.toString()) return if (value == null) {
encoder.encodeNull()
} else {
encoder.encodeString(value.uri.toString())
}
} }
override fun deserialize(decoder: Decoder): UniFile {
return UniFile.fromUri(Injekt.get<Application>(), Uri.parse(decoder.decodeString())) override fun deserialize(decoder: Decoder): UniFile? {
return if (decoder.decodeNotNullMark()) {
UniFile.fromUri(Injekt.get<Application>(), Uri.parse(decoder.decodeString()))
} else {
decoder.decodeNull()
}
} }
} }

View file

@ -5,6 +5,10 @@ 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
@ -23,17 +27,27 @@ import uy.kohesive.injekt.api.get
*/ */
class DownloadProvider( class DownloadProvider(
private val context: Context, private val context: Context,
private val storagePreferences: StoragePreferences = Injekt.get(), storagePreferences: StoragePreferences = Injekt.get(),
) { ) {
private val downloadsDir: UniFile? private val scope = CoroutineScope(Dispatchers.IO)
get() = storagePreferences.baseStorageDirectory().get().let {
UniFile.fromUri(context, it.toUri()) private var _downloadsDir: UniFile? =
?.createDirectory(StoragePreferences.DOWNLOADS_DIR) storagePreferences.baseStorageDirectory().get().let(::getDownloadsLocation)
?.also { dir -> val downloadsDir: UniFile?
DiskUtil.createNoMediaFile(dir, context) 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) }
}
/** /**
* Returns the download directory for a manga. For internal use only. * Returns the download directory for a manga. For internal use only.