Use unified storage location for local source

This commit is contained in:
arkon 2023-11-25 17:06:15 -05:00
parent 21ae04d25d
commit cf9e60fd92
6 changed files with 19 additions and 49 deletions

View File

@ -25,6 +25,7 @@ import kotlinx.serialization.json.Json
import nl.adaptivity.xmlutil.XmlDeclMode import nl.adaptivity.xmlutil.XmlDeclMode
import nl.adaptivity.xmlutil.core.XmlVersion import nl.adaptivity.xmlutil.core.XmlVersion
import nl.adaptivity.xmlutil.serialization.XML import nl.adaptivity.xmlutil.serialization.XML
import tachiyomi.core.provider.AndroidStorageFolderProvider
import tachiyomi.data.AndroidDatabaseHandler import tachiyomi.data.AndroidDatabaseHandler
import tachiyomi.data.Database import tachiyomi.data.Database
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
@ -123,7 +124,8 @@ class AppModule(val app: Application) : InjektModule {
addSingletonFactory { ImageSaver(app) } addSingletonFactory { ImageSaver(app) }
addSingletonFactory { LocalSourceFileSystem(app) } addSingletonFactory { AndroidStorageFolderProvider(app) }
addSingletonFactory { LocalSourceFileSystem(get<AndroidStorageFolderProvider>()) }
addSingletonFactory { LocalCoverManager(app, get()) } addSingletonFactory { LocalCoverManager(app, get()) }
// Asynchronously init expensive components for a faster cold start // Asynchronously init expensive components for a faster cold start

View File

@ -54,9 +54,6 @@ class PreferenceModule(val app: Application) : InjektModule {
addSingletonFactory { addSingletonFactory {
BackupPreferences(get()) BackupPreferences(get())
} }
addSingletonFactory {
AndroidStorageFolderProvider(app)
}
addSingletonFactory { addSingletonFactory {
StoragePreferences( StoragePreferences(
folderProvider = get<AndroidStorageFolderProvider>(), folderProvider = get<AndroidStorageFolderProvider>(),

View File

@ -3,9 +3,7 @@ package eu.kanade.tachiyomi.util.storage
import android.content.Context import android.content.Context
import android.media.MediaScannerConnection import android.media.MediaScannerConnection
import android.net.Uri import android.net.Uri
import android.os.Environment
import android.os.StatFs import android.os.StatFs
import androidx.core.content.ContextCompat
import com.hippo.unifile.UniFile import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.util.lang.Hash import eu.kanade.tachiyomi.util.lang.Hash
import java.io.File import java.io.File
@ -64,23 +62,6 @@ object DiskUtil {
} }
} }
/**
* Returns the root folders of all the available external storages.
*/
fun getExternalStorages(context: Context): List<File> {
return ContextCompat.getExternalFilesDirs(context, null)
.filterNotNull()
.mapNotNull {
val file = File(it.absolutePath.substringBefore("/Android/"))
val state = Environment.getExternalStorageState(file)
if (state == Environment.MEDIA_MOUNTED || state == Environment.MEDIA_MOUNTED_READ_ONLY) {
file
} else {
null
}
}
}
/** /**
* Don't display downloaded chapters in gallery apps creating `.nomedia`. * Don't display downloaded chapters in gallery apps creating `.nomedia`.
*/ */

View File

@ -73,7 +73,7 @@ actual class LocalSource(
override suspend fun getLatestUpdates(page: Int) = getSearchManga(page, "", LATEST_FILTERS) override suspend fun getLatestUpdates(page: Int) = getSearchManga(page, "", LATEST_FILTERS)
override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage { override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage {
val baseDirsFiles = fileSystem.getFilesInBaseDirectories() val baseDirFiles = fileSystem.getFilesInBaseDirectory()
val lastModifiedLimit by lazy { val lastModifiedLimit by lazy {
if (filters === LATEST_FILTERS) { if (filters === LATEST_FILTERS) {
System.currentTimeMillis() - LATEST_THRESHOLD System.currentTimeMillis() - LATEST_THRESHOLD
@ -81,7 +81,7 @@ actual class LocalSource(
0L 0L
} }
} }
var mangaDirs = baseDirsFiles var mangaDirs = baseDirFiles
// Filter out files that are hidden and is not a folder // Filter out files that are hidden and is not a folder
.filter { it.isDirectory && !it.name.startsWith('.') } .filter { it.isDirectory && !it.name.startsWith('.') }
.distinctBy { it.name } .distinctBy { it.name }
@ -308,9 +308,8 @@ actual class LocalSource(
fun getFormat(chapter: SChapter): Format { fun getFormat(chapter: SChapter): Format {
try { try {
return fileSystem.getBaseDirectories() return File(fileSystem.getBaseDirectory(), chapter.url)
.map { dir -> File(dir, chapter.url) } .takeIf { it.exists() }
.find { it.exists() }
?.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,37 +1,28 @@
package tachiyomi.source.local.io package tachiyomi.source.local.io
import android.content.Context import tachiyomi.core.provider.FolderProvider
import eu.kanade.tachiyomi.util.storage.DiskUtil
import tachiyomi.core.i18n.stringResource
import tachiyomi.i18n.MR
import java.io.File import java.io.File
actual class LocalSourceFileSystem( actual class LocalSourceFileSystem(
private val context: Context, private val folderProvider: FolderProvider,
) { ) {
private val baseFolderLocation = "${context.stringResource(MR.strings.app_name)}${File.separator}local" actual fun getBaseDirectory(): File {
return File(folderProvider.directory(), "local")
actual fun getBaseDirectories(): Sequence<File> {
return DiskUtil.getExternalStorages(context)
.map { File(it.absolutePath, baseFolderLocation) }
.asSequence()
} }
actual fun getFilesInBaseDirectories(): Sequence<File> { actual fun getFilesInBaseDirectory(): List<File> {
return getBaseDirectories() return getBaseDirectory().listFiles().orEmpty().toList()
// Get all the files inside all baseDir
.flatMap { it.listFiles().orEmpty().toList() }
} }
actual fun getMangaDirectory(name: String): File? { actual fun getMangaDirectory(name: String): File? {
return getFilesInBaseDirectories() return getFilesInBaseDirectory()
// Get the first mangaDir or null // Get the first mangaDir or null
.firstOrNull { it.isDirectory && it.name == name } .firstOrNull { it.isDirectory && it.name == name }
} }
actual fun getFilesInMangaDirectory(name: String): Sequence<File> { actual fun getFilesInMangaDirectory(name: String): List<File> {
return getFilesInBaseDirectories() return getFilesInBaseDirectory()
// Filter out ones that are not related to the manga and is not a directory // Filter out ones that are not related to the manga and is not a directory
.filter { it.isDirectory && it.name == name } .filter { it.isDirectory && it.name == name }
// Get all the files inside the filtered folders // Get all the files inside the filtered folders

View File

@ -4,11 +4,11 @@ import java.io.File
expect class LocalSourceFileSystem { expect class LocalSourceFileSystem {
fun getBaseDirectories(): Sequence<File> fun getBaseDirectory(): File
fun getFilesInBaseDirectories(): Sequence<File> fun getFilesInBaseDirectory(): List<File>
fun getMangaDirectory(name: String): File? fun getMangaDirectory(name: String): File?
fun getFilesInMangaDirectory(name: String): Sequence<File> fun getFilesInMangaDirectory(name: String): List<File>
} }