mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-23 12:41:50 +01:00
Added toasts to cleanup download
This commit is contained in:
parent
0577c45194
commit
24f5351701
@ -43,6 +43,7 @@ import uy.kohesive.injekt.injectLazy
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores backup from json file
|
* Restores backup from json file
|
||||||
@ -117,7 +118,7 @@ class BackupRestoreService : Service() {
|
|||||||
startForeground(Notifications.ID_RESTORE_PROGRESS, progressNotification.build())
|
startForeground(Notifications.ID_RESTORE_PROGRESS, progressNotification.build())
|
||||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
||||||
PowerManager.PARTIAL_WAKE_LOCK, "BackupRestoreService:WakeLock")
|
PowerManager.PARTIAL_WAKE_LOCK, "BackupRestoreService:WakeLock")
|
||||||
wakeLock.acquire()
|
wakeLock.acquire(TimeUnit.HOURS.toMillis(3))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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.
|
* Removes a manga that has been deleted from this cache.
|
||||||
*
|
*
|
||||||
|
@ -219,16 +219,21 @@ class DownloadManager(val context: Context) {
|
|||||||
* @param manga the manga of the chapters.
|
* @param manga the manga of the chapters.
|
||||||
* @param source the source 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)
|
val filesWithNoChapter = provider.findUnmatchedChapterDirs(allChapters, manga, source)
|
||||||
|
cleaned += filesWithNoChapter.size
|
||||||
|
cache.removeFolders(filesWithNoChapter.mapNotNull { it.name }, manga)
|
||||||
filesWithNoChapter.forEach { it.delete() }
|
filesWithNoChapter.forEach { it.delete() }
|
||||||
val readChapters = allChapters.filter { it.read }
|
val readChapters = allChapters.filter { it.read }
|
||||||
val readChapterDirs = provider.findChapterDirs(readChapters, manga, source)
|
val readChapterDirs = provider.findChapterDirs(readChapters, manga, source)
|
||||||
readChapterDirs.forEach { it.delete() }
|
readChapterDirs.forEach { it.delete() }
|
||||||
|
cleaned += readChapterDirs.size
|
||||||
cache.removeChapters(readChapters, manga)
|
cache.removeChapters(readChapters, manga)
|
||||||
if (cache.getDownloadCount(manga) == 0) {
|
if (cache.getDownloadCount(manga) == 0) {
|
||||||
provider.findChapterDirs(allChapters, manga, source).firstOrNull()?.parentFile?.delete()// Delete manga directory if empty
|
provider.findChapterDirs(allChapters, manga, source).firstOrNull()?.parentFile?.delete()// Delete manga directory if empty
|
||||||
}
|
}
|
||||||
|
return cleaned
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -142,13 +142,11 @@ class DownloadProvider(private val context: Context) {
|
|||||||
fun findUnmatchedChapterDirs(chapters: List<Chapter>, manga: Manga, source: Source): List<UniFile> {
|
fun findUnmatchedChapterDirs(chapters: List<Chapter>, manga: Manga, source: Source): List<UniFile> {
|
||||||
val mangaDir = findMangaDir(manga, source) ?: return emptyList()
|
val mangaDir = findMangaDir(manga, source) ?: return emptyList()
|
||||||
return mangaDir.listFiles()!!.asList().filter {
|
return mangaDir.listFiles()!!.asList().filter {
|
||||||
chapters.find { chp ->
|
(chapters.find { chp ->
|
||||||
(getValidChapterDirNames(chp) + "${getChapterDirName(chp)}_tmp").any { dir ->
|
getValidChapterDirNames(chp).any { dir ->
|
||||||
mangaDir.findFile(
|
mangaDir.findFile(dir) != null
|
||||||
dir
|
|
||||||
) != null
|
|
||||||
}
|
}
|
||||||
} == null
|
} == null) || it.name?.endsWith("_tmp") == true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,9 +40,6 @@ import eu.kanade.tachiyomi.util.notification
|
|||||||
import eu.kanade.tachiyomi.util.notificationManager
|
import eu.kanade.tachiyomi.util.notificationManager
|
||||||
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
@ -52,6 +49,7 @@ import uy.kohesive.injekt.api.get
|
|||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,8 +78,6 @@ class LibraryUpdateService(
|
|||||||
*/
|
*/
|
||||||
private var subscription: Subscription? = null
|
private var subscription: Subscription? = null
|
||||||
|
|
||||||
var job: Job? = null
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pending intent of action that cancels the library update
|
* Pending intent of action that cancels the library update
|
||||||
@ -116,8 +112,7 @@ class LibraryUpdateService(
|
|||||||
enum class Target {
|
enum class Target {
|
||||||
CHAPTERS, // Manga chapters
|
CHAPTERS, // Manga chapters
|
||||||
DETAILS, // Manga metadata
|
DETAILS, // Manga metadata
|
||||||
TRACKING, // Tracking metadata
|
TRACKING // Tracking metadata
|
||||||
CLEANUP // Clean up downloads
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -184,7 +179,7 @@ class LibraryUpdateService(
|
|||||||
startForeground(Notifications.ID_LIBRARY_PROGRESS, progressNotification.build())
|
startForeground(Notifications.ID_LIBRARY_PROGRESS, progressNotification.build())
|
||||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
||||||
PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock")
|
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.
|
// Unsubscribe from any previous subscription if needed.
|
||||||
subscription?.unsubscribe()
|
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 ->
|
val handler = CoroutineExceptionHandler { _, exception ->
|
||||||
Timber.e(exception)
|
Timber.e(exception)
|
||||||
stopSelf(startId)
|
stopSelf(startId)
|
||||||
}
|
}
|
||||||
// Update either chapter list or manga details.
|
// Update either chapter list or manga details.
|
||||||
if (target == Target.CLEANUP) {
|
val selectedScheme = preferences.libraryUpdatePrioritization().getOrDefault()
|
||||||
job = GlobalScope.launch(handler) {
|
// Update favorite manga. Destroy service when completed or in case of an error.
|
||||||
cleanupDownloads()
|
val mangaList = getMangaToUpdate(intent, target)
|
||||||
}
|
.sortedWith(rankingScheme[selectedScheme])
|
||||||
job?.invokeOnCompletion { stopSelf(startId) }
|
|
||||||
} else {
|
|
||||||
subscription = Observable.defer {
|
subscription = Observable.defer {
|
||||||
when (target) {
|
when (target) {
|
||||||
Target.CHAPTERS -> updateChapterList(mangaList)
|
Target.CHAPTERS -> updateChapterList(mangaList)
|
||||||
@ -250,7 +239,6 @@ class LibraryUpdateService(
|
|||||||
}, {
|
}, {
|
||||||
stopSelf(startId)
|
stopSelf(startId)
|
||||||
})
|
})
|
||||||
}
|
|
||||||
return START_REDELIVER_INTENT
|
return START_REDELIVER_INTENT
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,11 +348,13 @@ class LibraryUpdateService(
|
|||||||
|
|
||||||
private fun cleanupDownloads() {
|
private fun cleanupDownloads() {
|
||||||
val mangaList = db.getMangas().executeAsBlocking()
|
val mangaList = db.getMangas().executeAsBlocking()
|
||||||
|
var foldersCleared = 0
|
||||||
for (manga in mangaList) {
|
for (manga in mangaList) {
|
||||||
val chapterList = db.getChapters(manga).executeAsBlocking()
|
val chapterList = db.getChapters(manga).executeAsBlocking()
|
||||||
val source = sourceManager.getOrStub(manga.source)
|
val source = sourceManager.getOrStub(manga.source)
|
||||||
downloadManager.cleanupChapters(chapterList, manga, source)
|
foldersCleared += downloadManager.cleanupChapters(chapterList, manga, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
|
fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
|
||||||
|
@ -4,21 +4,33 @@ import android.app.Dialog
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.bluelinelabs.conductor.RouterTransaction
|
import com.bluelinelabs.conductor.RouterTransaction
|
||||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
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
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Target
|
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.network.NetworkHelper
|
||||||
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryController
|
import eu.kanade.tachiyomi.ui.library.LibraryController
|
||||||
|
import eu.kanade.tachiyomi.util.launchUI
|
||||||
import eu.kanade.tachiyomi.util.toast
|
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.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class SettingsAdvancedController : SettingsController() {
|
class SettingsAdvancedController : SettingsController() {
|
||||||
@ -74,10 +86,33 @@ class SettingsAdvancedController : SettingsController() {
|
|||||||
|
|
||||||
summaryRes = R.string.pref_clean_downloads_summary
|
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() {
|
private fun clearChapterCache() {
|
||||||
if (activity == null) return
|
if (activity == null) return
|
||||||
val files = chapterCache.cacheDir.listFiles() ?: return
|
val files = chapterCache.cacheDir.listFiles() ?: return
|
||||||
@ -128,5 +163,7 @@ class SettingsAdvancedController : SettingsController() {
|
|||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val CLEAR_CACHE_KEY = "pref_clear_cache_key"
|
const val CLEAR_CACHE_KEY = "pref_clear_cache_key"
|
||||||
|
|
||||||
|
private var job: Job? = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,9 +355,16 @@
|
|||||||
<string name="pref_refresh_library_tracking">Refresh tracking metadata</string>
|
<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_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">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>
|
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 -->
|
<!-- About section -->
|
||||||
<string name="version">Version</string>
|
<string name="version">Version</string>
|
||||||
<string name="build_time">Build time</string>
|
<string name="build_time">Build time</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user