Added toasts to cleanup download

This commit is contained in:
Jay 2020-01-13 00:03:22 -08:00
parent 0577c45194
commit 24f5351701
7 changed files with 79 additions and 30 deletions

View File

@ -43,6 +43,7 @@ import uy.kohesive.injekt.injectLazy
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
/**
* Restores backup from json file
@ -117,7 +118,7 @@ class BackupRestoreService : Service() {
startForeground(Notifications.ID_RESTORE_PROGRESS, progressNotification.build())
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "BackupRestoreService:WakeLock")
wakeLock.acquire()
wakeLock.acquire(TimeUnit.HOURS.toMillis(3))
}
/**

View File

@ -217,6 +217,17 @@ class DownloadCache(
}
}
fun removeFolders(folders: List<String>, manga: Manga) {
val sourceDir = rootDir.files[manga.source] ?: return
val mangaDir = sourceDir.files[provider.getMangaDirName(manga)] ?: return
for (chapter in folders) {
if (chapter in mangaDir.files) {
mangaDir.files -= chapter
}
}
}
/**
* Removes a manga that has been deleted from this cache.
*

View File

@ -219,16 +219,21 @@ class DownloadManager(val context: Context) {
* @param manga the manga of the chapters.
* @param source the source of the chapters.
*/
fun cleanupChapters(allChapters: List<Chapter>, manga: Manga, source: Source) {
fun cleanupChapters(allChapters: List<Chapter>, manga: Manga, source: Source): Int {
var cleaned = 0
val filesWithNoChapter = provider.findUnmatchedChapterDirs(allChapters, manga, source)
cleaned += filesWithNoChapter.size
cache.removeFolders(filesWithNoChapter.mapNotNull { it.name }, manga)
filesWithNoChapter.forEach { it.delete() }
val readChapters = allChapters.filter { it.read }
val readChapterDirs = provider.findChapterDirs(readChapters, manga, source)
readChapterDirs.forEach { it.delete() }
cleaned += readChapterDirs.size
cache.removeChapters(readChapters, manga)
if (cache.getDownloadCount(manga) == 0) {
provider.findChapterDirs(allChapters, manga, source).firstOrNull()?.parentFile?.delete()// Delete manga directory if empty
}
return cleaned
}
/**

View File

@ -142,13 +142,11 @@ class DownloadProvider(private val context: Context) {
fun findUnmatchedChapterDirs(chapters: List<Chapter>, manga: Manga, source: Source): List<UniFile> {
val mangaDir = findMangaDir(manga, source) ?: return emptyList()
return mangaDir.listFiles()!!.asList().filter {
chapters.find { chp ->
(getValidChapterDirNames(chp) + "${getChapterDirName(chp)}_tmp").any { dir ->
mangaDir.findFile(
dir
) != null
(chapters.find { chp ->
getValidChapterDirNames(chp).any { dir ->
mangaDir.findFile(dir) != null
}
} == null
} == null) || it.name?.endsWith("_tmp") == true
}
}

View File

@ -40,9 +40,6 @@ import eu.kanade.tachiyomi.util.notification
import eu.kanade.tachiyomi.util.notificationManager
import eu.kanade.tachiyomi.util.syncChaptersWithSource
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import rx.Observable
import rx.Subscription
import rx.schedulers.Schedulers
@ -52,6 +49,7 @@ import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.util.ArrayList
import java.util.Date
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
/**
@ -80,8 +78,6 @@ class LibraryUpdateService(
*/
private var subscription: Subscription? = null
var job: Job? = null
/**
* Pending intent of action that cancels the library update
@ -116,8 +112,7 @@ class LibraryUpdateService(
enum class Target {
CHAPTERS, // Manga chapters
DETAILS, // Manga metadata
TRACKING, // Tracking metadata
CLEANUP // Clean up downloads
TRACKING // Tracking metadata
}
companion object {
@ -184,7 +179,7 @@ class LibraryUpdateService(
startForeground(Notifications.ID_LIBRARY_PROGRESS, progressNotification.build())
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock")
wakeLock.acquire()
wakeLock.acquire(TimeUnit.MINUTES.toMillis(30))
}
/**
@ -222,22 +217,16 @@ class LibraryUpdateService(
// Unsubscribe from any previous subscription if needed.
subscription?.unsubscribe()
val selectedScheme = preferences.libraryUpdatePrioritization().getOrDefault()
// Update favorite manga. Destroy service when completed or in case of an error.
val mangaList = getMangaToUpdate(intent, target)
.sortedWith(rankingScheme[selectedScheme])
val handler = CoroutineExceptionHandler { _, exception ->
Timber.e(exception)
stopSelf(startId)
}
// Update either chapter list or manga details.
if (target == Target.CLEANUP) {
job = GlobalScope.launch(handler) {
cleanupDownloads()
}
job?.invokeOnCompletion { stopSelf(startId) }
} else {
val selectedScheme = preferences.libraryUpdatePrioritization().getOrDefault()
// Update favorite manga. Destroy service when completed or in case of an error.
val mangaList = getMangaToUpdate(intent, target)
.sortedWith(rankingScheme[selectedScheme])
subscription = Observable.defer {
when (target) {
Target.CHAPTERS -> updateChapterList(mangaList)
@ -250,7 +239,6 @@ class LibraryUpdateService(
}, {
stopSelf(startId)
})
}
return START_REDELIVER_INTENT
}
@ -360,11 +348,13 @@ class LibraryUpdateService(
private fun cleanupDownloads() {
val mangaList = db.getMangas().executeAsBlocking()
var foldersCleared = 0
for (manga in mangaList) {
val chapterList = db.getChapters(manga).executeAsBlocking()
val source = sourceManager.getOrStub(manga.source)
downloadManager.cleanupChapters(chapterList, manga, source)
foldersCleared += downloadManager.cleanupChapters(chapterList, manga, source)
}
}
fun downloadChapters(manga: Manga, chapters: List<Chapter>) {

View File

@ -4,21 +4,33 @@ import android.app.Dialog
import android.os.Bundle
import androidx.preference.PreferenceScreen
import android.view.View
import android.widget.Toast
import com.afollestad.materialdialogs.MaterialDialog
import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Target
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.library.LibraryController
import eu.kanade.tachiyomi.util.launchUI
import eu.kanade.tachiyomi.util.toast
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
class SettingsAdvancedController : SettingsController() {
@ -74,10 +86,33 @@ class SettingsAdvancedController : SettingsController() {
summaryRes = R.string.pref_clean_downloads_summary
onClick { LibraryUpdateService.start(context, target = Target.CLEANUP) }
onClick { cleanupDownloads() }
}
}
private fun cleanupDownloads() {
if (job?.isActive == true) return
activity?.toast(R.string.starting_cleanup)
job = GlobalScope.launch(Dispatchers.IO, CoroutineStart.DEFAULT) {
val mangaList = db.getMangas().executeAsBlocking()
val sourceManager: SourceManager = Injekt.get()
val downloadManager: DownloadManager = Injekt.get()
var foldersCleared = 0
for (manga in mangaList) {
val chapterList = db.getChapters(manga).executeAsBlocking()
val source = sourceManager.getOrStub(manga.source)
foldersCleared += downloadManager.cleanupChapters(chapterList, manga, source)
}
launchUI {
val activity = activity ?: return@launchUI
val cleanupString = if (foldersCleared == 0) activity.getString(R.string.no_cleanup_done)
else resources!!.getQuantityString(R.plurals.cleanup_done, foldersCleared, foldersCleared)
activity.toast(cleanupString, Toast.LENGTH_LONG)
}
}
}
private fun clearChapterCache() {
if (activity == null) return
val files = chapterCache.cacheDir.listFiles() ?: return
@ -128,5 +163,7 @@ class SettingsAdvancedController : SettingsController() {
private companion object {
const val CLEAR_CACHE_KEY = "pref_clear_cache_key"
private var job: Job? = null
}
}

View File

@ -355,9 +355,16 @@
<string name="pref_refresh_library_tracking">Refresh tracking metadata</string>
<string name="pref_refresh_library_tracking_summary">Updates status, score and last chapter read from the tracking services</string>
<string name="pref_clean_downloads">Clean up downloaded chapters</string>
<string name="pref_clean_downloads_summary">Deletes non-existent, partially downloaded,
<string name="pref_clean_downloads_summary">Delete non-existent, partially downloaded,
and read chapter folders</string>
<string name="starting_cleanup">Starting cleanup</string>
<string name="no_cleanup_done">No folders to cleanup</string>
<plurals name="cleanup_done">
<item quantity="one">Cleanup done. Removed %d folder</item>
<item quantity="other">Cleanup done. Removed %d folders</item>
</plurals>
<!-- About section -->
<string name="version">Version</string>
<string name="build_time">Build time</string>