Show notification with error log on update failures

(cherry picked from commit fc4e290c49367a9ebd43bdb713788faa16ded265)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt
This commit is contained in:
Eugene Cheung 2020-05-13 22:28:15 -04:00 committed by Jobobby04
parent aded163e0a
commit 4dc2143160
4 changed files with 77 additions and 9 deletions

View File

@ -6,6 +6,7 @@ import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.bumptech.glide.Glide
@ -80,6 +81,39 @@ class LibraryUpdateNotifier(private val context: Context) {
)
}
/**
* Shows notification containing update entries that failed with action to open full log.
*
* @param errors List of entry titles that failed to update.
* @param uri Uri for error log file containing all titles that failed.
*/
fun showUpdateErrorNotification(errors: List<String>, uri: Uri) {
if (errors.isEmpty()) {
return
}
context.notificationManager.notify(
Notifications.ID_LIBRARY_ERROR,
context.notificationBuilder(Notifications.CHANNEL_LIBRARY) {
setContentTitle(context.resources.getQuantityString(R.plurals.notification_update_error, errors.size, errors.size))
setStyle(
NotificationCompat.BigTextStyle().bigText(
errors.joinToString("\n") {
it.chop(NOTIF_TITLE_MAX_LEN)
}
)
)
setSmallIcon(R.drawable.ic_tachi)
addAction(
R.drawable.nnf_ic_file_folder,
context.getString(R.string.action_open_log),
NotificationReceiver.openErrorLogPendingActivity(context, uri)
)
}
.build()
)
}
/**
* Shows the notification containing the result of the update done by the service.
*

View File

@ -23,9 +23,11 @@ import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.prepUpdateCover
import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.acquireWakeLock
import eu.kanade.tachiyomi.util.system.isServiceRunning
import exh.LIBRARY_UPDATE_EXCLUDED_SOURCES
import java.io.File
import java.util.ArrayList
import java.util.concurrent.atomic.AtomicInteger
import rx.Observable
@ -254,7 +256,7 @@ class LibraryUpdateService(
// List containing new updates
val newUpdates = ArrayList<Pair<LibraryManga, Array<Chapter>>>()
// List containing failed updates
val failedUpdates = ArrayList<Manga>()
val failedUpdates = ArrayList<Pair<Manga, String?>>()
// List containing categories that get included in downloads.
val categoriesToDownload = preferences.downloadNewCategories().get().map(String::toInt)
// Boolean to determine if user wants to automatically download new chapters.
@ -266,7 +268,7 @@ class LibraryUpdateService(
return Observable.from(mangaToUpdate)
// Notify manga that will update.
.doOnNext { notifier.showProgressNotification(it, count.andIncrement, mangaToUpdate.size) }
// Update the chapters of the manga.
// Update the chapters of the manga
.concatMap { manga ->
if (manga.source in LIBRARY_UPDATE_EXCLUDED_SOURCES) {
// Ignore EXH manga, updating chapters for every manga will get you banned
@ -275,7 +277,7 @@ class LibraryUpdateService(
updateManga(manga)
// If there's any error, return empty update and continue.
.onErrorReturn {
failedUpdates.add(manga)
failedUpdates.add(Pair(manga, it.message))
Pair(emptyList(), emptyList())
}
// Filter out mangas without new chapters (or failed).
@ -295,7 +297,10 @@ class LibraryUpdateService(
.map {
Pair(
manga,
(it.first.sortedByDescending { ch -> ch.source_order }.toTypedArray())
(
it.first.sortedByDescending { ch -> ch.source_order }
.toTypedArray()
)
)
}
}
@ -306,6 +311,8 @@ class LibraryUpdateService(
}
// Notify result of the overall update.
.doOnCompleted {
notifier.cancelProgressNotification()
if (newUpdates.isNotEmpty()) {
notifier.showUpdateNotifications(newUpdates)
if (downloadNew && hasDownloads) {
@ -314,10 +321,12 @@ class LibraryUpdateService(
}
if (failedUpdates.isNotEmpty()) {
Timber.e("Failed updating: ${failedUpdates.map { it.title }}")
val errorFile = writeErrorFile(failedUpdates)
notifier.showUpdateErrorNotification(
failedUpdates.map { it.first.title },
errorFile.getUriCompat(this)
)
}
notifier.cancelProgressNotification()
}
.map { manga -> manga.first }
}
@ -420,4 +429,25 @@ class LibraryUpdateService(
notifier.cancelProgressNotification()
}
}
/**
* Writes basic file of update errors to cache dir.
*/
private fun writeErrorFile(errors: List<Pair<Manga, String?>>): File {
try {
if (errors.isNotEmpty()) {
val destFile = File(externalCacheDir, "tachiyomi_update_errors.txt")
destFile.bufferedWriter().use { out ->
errors.forEach { (manga, error) ->
out.write("${manga.title}: $error\n")
}
}
return destFile
}
} catch (e: Exception) {
// Empty
}
return File("")
}
}

View File

@ -25,7 +25,7 @@ object Notifications {
*/
const val CHANNEL_LIBRARY = "library_channel"
const val ID_LIBRARY_PROGRESS = -101
const val ID_OLD_LIBRARY_RESULT = -101
const val ID_LIBRARY_ERROR = -102
/**
* Notification channel and ids used by the downloader.
@ -45,7 +45,7 @@ object Notifications {
* Notification channel and ids used by the library updater.
*/
const val CHANNEL_UPDATES_TO_EXTS = "updates_ext_channel"
const val ID_UPDATES_TO_EXTS = -501
const val ID_UPDATES_TO_EXTS = -401
/**
* Notification channel and ids used by the backup/restore system.

View File

@ -579,6 +579,10 @@
<item quantity="one">Chapters %1$s and 1 more</item>
<item quantity="other">Chapters %1$s and %2$d more</item>
</plurals>
<plurals name="notification_update_error">
<item quantity="one">1 update failed</item>
<item quantity="other">%1$d updates failed</item>
</plurals>
<string name="notification_cover_update_failed">Failed to update cover</string>
<string name="notification_first_add_to_library">Please add the manga to your library before doing this</string>
<string name="notification_not_connected_to_ac_title">Sync canceled</string>