More fixes to the library update service

Restored the claim that it still shows a notifcation when cancelling the update
This commit is contained in:
Jay 2020-02-21 19:56:54 -08:00
parent c88fc38238
commit 8e8cbbca3b
2 changed files with 74 additions and 60 deletions

View File

@ -25,19 +25,23 @@ import eu.kanade.tachiyomi.data.backup.models.Backup.TRACK
import eu.kanade.tachiyomi.data.backup.models.Backup.VERSION import eu.kanade.tachiyomi.data.backup.models.Backup.VERSION
import eu.kanade.tachiyomi.data.backup.models.DHistory import eu.kanade.tachiyomi.data.backup.models.DHistory
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.* import eu.kanade.tachiyomi.data.database.models.ChapterImpl
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaImpl
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.TrackImpl
import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.SourceNotFoundException import eu.kanade.tachiyomi.source.SourceNotFoundException
import eu.kanade.tachiyomi.util.lang.chop import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.isServiceRunning
import eu.kanade.tachiyomi.util.system.notificationManager import eu.kanade.tachiyomi.util.system.notificationManager
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import eu.kanade.tachiyomi.util.system.isServiceRunning
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File import java.io.File
@ -147,9 +151,7 @@ class BackupRestoreService : Service() {
* @return the start value of the command. * @return the start value of the command.
*/ */
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent == null) return START_NOT_STICKY val uri = intent?.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) ?: return START_NOT_STICKY
val uri = intent.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) ?: return START_NOT_STICKY
// Unsubscribe from any previous subscription if needed. // Unsubscribe from any previous subscription if needed.
job?.cancel() job?.cancel()
@ -159,7 +161,7 @@ class BackupRestoreService : Service() {
stopSelf(startId) stopSelf(startId)
} }
job = GlobalScope.launch(handler) { job = GlobalScope.launch(handler) {
restoreBackup(uri!!) restoreBackup(uri)
} }
job?.invokeOnCompletion { stopSelf(startId) } job?.invokeOnCompletion { stopSelf(startId) }

View File

@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaImpl import eu.kanade.tachiyomi.data.database.models.MangaImpl
@ -31,7 +32,6 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
@ -104,7 +104,7 @@ class LibraryUpdateService(
private val categoryIds = mutableSetOf<Int>() private val categoryIds = mutableSetOf<Int>()
// List containing new updates // List containing new updates
private val newUpdates = ArrayList<Pair<LibraryManga, Array<Chapter>>>() private val newUpdates = mutableMapOf<LibraryManga, Array<Chapter>>()
/** /**
* Cached progress notification to avoid creating a lot. * Cached progress notification to avoid creating a lot.
@ -187,6 +187,7 @@ class LibraryUpdateService(
* @param context the application context. * @param context the application context.
*/ */
fun stop(context: Context) { fun stop(context: Context) {
instance?.job?.cancel()
context.stopService(Intent(context, LibraryUpdateService::class.java)) context.stopService(Intent(context, LibraryUpdateService::class.java))
} }
@ -329,15 +330,7 @@ class LibraryUpdateService(
private fun updateChapters(mangaToAdd: List<LibraryManga>, startId: Int) { private fun updateChapters(mangaToAdd: List<LibraryManga>, startId: Int) {
val handler = CoroutineExceptionHandler { _, exception -> val handler = CoroutineExceptionHandler { _, exception ->
Timber.e(exception) Timber.e(exception)
// Boolean to determine if user wants to automatically download new chapters. // Boolean to determine if user wants to automatically download new chapters.
val downloadNew = preferences.downloadNew().getOrDefault()
if (newUpdates.isNotEmpty()) {
showResultNotification(newUpdates)
if (downloadNew && downloadManager.queue.isNotEmpty()) {
DownloadService.start(this)
}
}
stopSelf(startId) stopSelf(startId)
} }
job = GlobalScope.launch(handler) { job = GlobalScope.launch(handler) {
@ -347,52 +340,41 @@ class LibraryUpdateService(
} }
private suspend fun updateChaptersJob(mangaToAdd: List<LibraryManga>) { private suspend fun updateChaptersJob(mangaToAdd: List<LibraryManga>) {
// list containing failed updates
val failedUpdates = ArrayList<Manga>()
// List containing categories that get included in downloads. // List containing categories that get included in downloads.
val categoriesToDownload = preferences.downloadNewCategories().getOrDefault().map(String::toInt) val categoriesToDownload = preferences.downloadNewCategories().getOrDefault().map(String::toInt)
// Boolean to determine if user wants to automatically download new chapters. // Boolean to determine if user wants to automatically download new chapters.
val downloadNew = preferences.downloadNew().getOrDefault() val downloadNew = preferences.downloadNew().getOrDefault()
// Boolean to determine if DownloadManager has downloads // Boolean to determine if DownloadManager has downloads
var hasDownloads = false var hasDownloads = false
withContext(Dispatchers.IO) { val fakeM = LibraryManga()
// Initialize the variables holding the progress of the updates. fakeM.title = "Test"
var count = 0 fakeM.favorite = true
fakeM.id = -12
fakeM.initialized = true
fakeM.url = ""
val fakeC = ChapterImpl()
fakeC.chapter_number = 1.0f
fakeC.name = "Chapter Test"
fakeC.id = -15
fakeC.url = ""
newUpdates[fakeM] = arrayOf<Chapter>(fakeC)
// Initialize the variables holding the progress of the updates.
var count = 0
mangaToUpdate.addAll(mangaToAdd) mangaToUpdate.addAll(mangaToAdd)
while (count < mangaToUpdate.size) { while (count < mangaToUpdate.size) {
if (job?.isCancelled == true) break val shouldDownload = (downloadNew && (categoriesToDownload.isEmpty() ||
val manga = mangaToUpdate[count] mangaToUpdate[count].category in categoriesToDownload))
showProgressNotification(manga, count++, mangaToUpdate.size) if (updateMangaChapters(mangaToUpdate[count], count, shouldDownload)) {
val source = sourceManager.get(manga.source) as? HttpSource ?: continue hasDownloads = true
val fetchedChapters = try {
source.fetchChapterList(manga).toBlocking().single()
} catch (e: java.lang.Exception) {
failedUpdates.add(manga)
emptyList<SChapter>()
} ?: emptyList()
if (fetchedChapters.isNotEmpty()) {
val newChapters = syncChaptersWithSource(db, fetchedChapters, manga, source)
if (newChapters.first.isNotEmpty()) {
if (downloadNew && (categoriesToDownload.isEmpty() || manga.category in categoriesToDownload)) {
downloadChapters(
manga,
newChapters.first.sortedBy { it.chapter_number })
hasDownloads = true
}
newUpdates.add(manga to newChapters.first.sortedBy { it.chapter_number }.toTypedArray())
}
if (newChapters.first.size + newChapters.second.size > 0) listener?.onUpdateManga(
manga
)
}
} }
count++
} }
if (newUpdates.isNotEmpty()) { if (newUpdates.isNotEmpty()) {
showResultNotification(newUpdates) showResultNotification(newUpdates)
if (preferences.refreshCoversToo().getOrDefault()) { if (preferences.refreshCoversToo().getOrDefault() && job?.isCancelled == false) {
updateDetails(newUpdates.map { it.first }).observeOn(Schedulers.io()) updateDetails(newUpdates.map { it.key }).observeOn(Schedulers.io())
.doOnCompleted { .doOnCompleted {
cancelProgressNotification() cancelProgressNotification()
if (downloadNew && hasDownloads) { if (downloadNew && hasDownloads) {
@ -406,13 +388,43 @@ class LibraryUpdateService(
} }
} }
if (failedUpdates.isNotEmpty()) {
Timber.e("Failed updating: ${failedUpdates.map { it.title }}")
}
cancelProgressNotification() cancelProgressNotification()
} }
private suspend fun updateMangaChapters(manga: LibraryManga, progess: Int, shouldDownload: Boolean):
Boolean {
try {
var hasDownloads = false
if (job?.isCancelled == true) {
throw java.lang.Exception("Job was cancelled")
}
showProgressNotification(manga, progess, mangaToUpdate.size)
val source = sourceManager.get(manga.source) as? HttpSource ?: return false
val fetchedChapters = withContext(Dispatchers.IO) {
source.fetchChapterList(manga).toBlocking().single()
} ?: emptyList()
if (fetchedChapters.isNotEmpty()) {
val newChapters = syncChaptersWithSource(db, fetchedChapters, manga, source)
if (newChapters.first.isNotEmpty()) {
if (shouldDownload) {
downloadChapters(manga, newChapters.first.sortedBy { it.chapter_number })
hasDownloads = true
}
newUpdates[manga] =
newChapters.first.sortedBy { it.chapter_number }.toTypedArray()
}
if (newChapters.first.size + newChapters.second.size > 0) listener?.onUpdateManga(
manga
)
}
return hasDownloads
}
catch (e: Exception) {
Timber.e("Failed updating: ${manga.title}: $e")
return false
}
}
fun downloadChapters(manga: Manga, chapters: List<Chapter>) { fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
// we need to get the chapters from the db so we have chapter ids // we need to get the chapters from the db so we have chapter ids
val mangaChapters = db.getChapters(manga).executeAsBlocking() val mangaChapters = db.getChapters(manga).executeAsBlocking()
@ -525,11 +537,11 @@ class LibraryUpdateService(
* *
* @param updates a list of manga with new updates. * @param updates a list of manga with new updates.
*/ */
private fun showResultNotification(updates: List<Pair<Manga, Array<Chapter>>>) { private fun showResultNotification(updates: Map<LibraryManga, Array<Chapter>>) {
val notifications = ArrayList<Pair<Notification, Int>>() val notifications = ArrayList<Pair<Notification, Int>>()
updates.forEach { updates.forEach {
val manga = it.first val manga = it.key
val chapters = it.second val chapters = it.value
val chapterNames = chapters.map { chapter -> chapter.name } val chapterNames = chapters.map { chapter -> chapter.name }
notifications.add(Pair(notification(Notifications.CHANNEL_NEW_CHAPTERS) { notifications.add(Pair(notification(Notifications.CHANNEL_NEW_CHAPTERS) {
setSmallIcon(R.drawable.ic_tachi) setSmallIcon(R.drawable.ic_tachi)
@ -578,12 +590,12 @@ class LibraryUpdateService(
setContentText(resources.getQuantityString(R.plurals setContentText(resources.getQuantityString(R.plurals
.notification_new_chapters_text, .notification_new_chapters_text,
updates.size, updates.size)) updates.size, updates.size))
setStyle(NotificationCompat.BigTextStyle().bigText(updates.joinToString("\n") { setStyle(NotificationCompat.BigTextStyle().bigText(updates.keys.joinToString("\n") {
it.first.currentTitle().chop(45) it.currentTitle().chop(45)
})) }))
} }
else { else {
setContentText(updates.first().first.currentTitle().chop(45)) setContentText(updates.keys.first().currentTitle().chop(45))
} }
priority = NotificationCompat.PRIORITY_HIGH priority = NotificationCompat.PRIORITY_HIGH
setGroup(Notifications.GROUP_NEW_CHAPTERS) setGroup(Notifications.GROUP_NEW_CHAPTERS)