Don't rely on cache when deleting empty manga folders

In case the cache hasn't actually been indexed yet. Maybe fixes #8438.
This commit is contained in:
arkon 2022-11-14 22:42:36 -05:00
parent 10e349f76e
commit f5873d70c6
4 changed files with 61 additions and 65 deletions

View file

@ -214,12 +214,8 @@ class DownloadCache(
} }
@Synchronized @Synchronized
fun removeSourceIfEmpty(source: Source) { fun removeSource(source: Source) {
val sourceDir = provider.findSourceDir(source) rootDownloadsDir.sourceDirs -= source.id
if (sourceDir?.listFiles()?.isEmpty() == true) {
sourceDir.delete()
rootDownloadsDir.sourceDirs -= source.id
}
notifyChanges() notifyChanges()
} }

View file

@ -247,21 +247,27 @@ class DownloadManager(
getChaptersToDelete(chapters, manga) getChaptersToDelete(chapters, manga)
} }
launchIO { if (filteredChapters.isNotEmpty()) {
removeFromDownloadQueue(filteredChapters) launchIO {
removeFromDownloadQueue(filteredChapters)
val chapterDirs = provider.findChapterDirs(filteredChapters, manga, source) val (mangaDir, chapterDirs) = provider.findChapterDirs(filteredChapters, manga, source)
chapterDirs.forEach { it.delete() } chapterDirs.forEach { it.delete() }
cache.removeChapters(filteredChapters, manga) cache.removeChapters(filteredChapters, manga)
// Delete manga directory if empty // Delete manga directory if empty
if (cache.getDownloadCount(manga) == 0) { if (mangaDir?.listFiles()?.isEmpty() == true) {
chapterDirs.firstOrNull()?.parentFile?.delete() mangaDir.delete()
cache.removeManga(manga) cache.removeManga(manga)
// Delete source directory if empty
val sourceDir = provider.findSourceDir(source)
if (sourceDir?.listFiles()?.isEmpty() == true) {
sourceDir.delete()
cache.removeSource(source)
}
}
} }
// Delete source directory if empty
cache.removeSourceIfEmpty(source)
} }
return filteredChapters return filteredChapters
@ -334,13 +340,13 @@ class DownloadManager(
if (capitalizationChanged) { if (capitalizationChanged) {
val tempName = newName + "_tmp" val tempName = newName + "_tmp"
if (oldFolder.renameTo(tempName).not()) { if (oldFolder.renameTo(tempName).not()) {
logcat(LogPriority.ERROR) { "Could not rename source download folder: ${oldFolder.name}." } logcat(LogPriority.ERROR) { "Failed to rename source download folder: ${oldFolder.name}." }
return return
} }
} }
if (oldFolder.renameTo(newName).not()) { if (oldFolder.renameTo(newName).not()) {
logcat(LogPriority.ERROR) { "Could not rename source download folder: ${oldFolder.name}." } logcat(LogPriority.ERROR) { "Failed to rename source download folder: ${oldFolder.name}." }
} }
} }

View file

@ -8,16 +8,18 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
/** /**
* Class used to keep a list of chapters for future deletion. * Class used to keep a list of chapters for future deletion.
* *
* @param context the application context. * @param context the application context.
*/ */
class DownloadPendingDeleter(context: Context) { class DownloadPendingDeleter(
context: Context,
private val json: Json by injectLazy() private val json: Json = Injekt.get(),
) {
/** /**
* Preferences used to store the list of chapters to delete. * Preferences used to store the list of chapters to delete.
@ -120,6 +122,36 @@ class DownloadPendingDeleter(context: Context) {
return newList return newList
} }
/**
* Returns a manga entry from a manga model.
*/
private fun Manga.toEntry() = MangaEntry(id, url, title, source)
/**
* Returns a chapter entry from a chapter model.
*/
private fun Chapter.toEntry() = ChapterEntry(id, url, name, scanlator)
/**
* Returns a manga model from a manga entry.
*/
private fun MangaEntry.toModel() = Manga.create().copy(
url = url,
title = title,
source = source,
id = id,
)
/**
* Returns a chapter model from a chapter entry.
*/
private fun ChapterEntry.toModel() = Chapter.create().copy(
id = id,
url = url,
name = name,
scanlator = scanlator,
)
/** /**
* Class used to save an entry of chapters with their manga into preferences. * Class used to save an entry of chapters with their manga into preferences.
*/ */
@ -150,42 +182,4 @@ class DownloadPendingDeleter(context: Context) {
val title: String, val title: String,
val source: Long, val source: Long,
) )
/**
* Returns a manga entry from a manga model.
*/
private fun Manga.toEntry(): MangaEntry {
return MangaEntry(id, url, title, source)
}
/**
* Returns a chapter entry from a chapter model.
*/
private fun Chapter.toEntry(): ChapterEntry {
return ChapterEntry(id!!, url, name, scanlator)
}
/**
* Returns a manga model from a manga entry.
*/
private fun MangaEntry.toModel(): Manga {
return Manga.create().copy(
url = url,
title = title,
source = source,
id = id,
)
}
/**
* Returns a chapter model from a chapter entry.
*/
private fun ChapterEntry.toModel(): Chapter {
return Chapter.create().copy(
id = id,
url = url,
name = name,
scanlator = scanlator,
)
}
} }

View file

@ -104,9 +104,9 @@ class DownloadProvider(
* @param manga the manga of the chapter. * @param manga the manga of the chapter.
* @param source the source of the chapter. * @param source the source of the chapter.
*/ */
fun findChapterDirs(chapters: List<Chapter>, manga: Manga, source: Source): List<UniFile> { fun findChapterDirs(chapters: List<Chapter>, manga: Manga, source: Source): Pair<UniFile?, List<UniFile>> {
val mangaDir = findMangaDir(manga.title, source) ?: return emptyList() val mangaDir = findMangaDir(manga.title, source) ?: return null to emptyList()
return chapters.mapNotNull { chapter -> return mangaDir to chapters.mapNotNull { chapter ->
getValidChapterDirNames(chapter.name, chapter.scanlator).asSequence() getValidChapterDirNames(chapter.name, chapter.scanlator).asSequence()
.mapNotNull { mangaDir.findFile(it) } .mapNotNull { mangaDir.findFile(it) }
.firstOrNull() .firstOrNull()