mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Account for skipped entries when showing large updates warning
Closes #6159
This commit is contained in:
		@@ -186,7 +186,40 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
 | 
			
		||||
                .distinctBy { it.manga.id }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val restrictions = libraryPreferences.autoUpdateMangaRestrictions().get()
 | 
			
		||||
        val skippedUpdates = mutableListOf<Pair<Manga, String?>>()
 | 
			
		||||
        val fetchWindow = fetchInterval.getWindow(ZonedDateTime.now())
 | 
			
		||||
 | 
			
		||||
        mangaToUpdate = listToUpdate
 | 
			
		||||
            .filter {
 | 
			
		||||
                when {
 | 
			
		||||
                    it.manga.updateStrategy != UpdateStrategy.ALWAYS_UPDATE -> {
 | 
			
		||||
                        skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_always_update))
 | 
			
		||||
                        false
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    MANGA_NON_COMPLETED in restrictions && it.manga.status.toInt() == SManga.COMPLETED -> {
 | 
			
		||||
                        skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_completed))
 | 
			
		||||
                        false
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    MANGA_HAS_UNREAD in restrictions && it.unreadCount != 0L -> {
 | 
			
		||||
                        skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_caught_up))
 | 
			
		||||
                        false
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    MANGA_NON_READ in restrictions && it.totalChapters > 0L && !it.hasStarted -> {
 | 
			
		||||
                        skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_started))
 | 
			
		||||
                        false
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    MANGA_OUTSIDE_RELEASE_PERIOD in restrictions && it.manga.nextUpdate > fetchWindow.second -> {
 | 
			
		||||
                        skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_in_release_period))
 | 
			
		||||
                        false
 | 
			
		||||
                    }
 | 
			
		||||
                    else -> true
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .sortedBy { it.manga.title }
 | 
			
		||||
 | 
			
		||||
        // Warn when excessively checking a single source
 | 
			
		||||
@@ -197,6 +230,17 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
 | 
			
		||||
        if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD) {
 | 
			
		||||
            notifier.showQueueSizeWarningNotification()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (skippedUpdates.isNotEmpty()) {
 | 
			
		||||
            // TODO: surface skipped reasons to user?
 | 
			
		||||
            logcat {
 | 
			
		||||
                skippedUpdates
 | 
			
		||||
                    .groupBy { it.second }
 | 
			
		||||
                    .map { (reason, entries) -> "$reason: [${entries.map { it.first.title }.sorted().joinToString()}]" }
 | 
			
		||||
                    .joinToString()
 | 
			
		||||
            }
 | 
			
		||||
            notifier.showUpdateSkippedNotification(skippedUpdates.size)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -212,10 +256,8 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
 | 
			
		||||
        val progressCount = AtomicInteger(0)
 | 
			
		||||
        val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>()
 | 
			
		||||
        val newUpdates = CopyOnWriteArrayList<Pair<Manga, Array<Chapter>>>()
 | 
			
		||||
        val skippedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>()
 | 
			
		||||
        val failedUpdates = CopyOnWriteArrayList<Pair<Manga, String?>>()
 | 
			
		||||
        val hasDownloads = AtomicBoolean(false)
 | 
			
		||||
        val restrictions = libraryPreferences.autoUpdateMangaRestrictions().get()
 | 
			
		||||
        val fetchWindow = fetchInterval.getWindow(ZonedDateTime.now())
 | 
			
		||||
 | 
			
		||||
        coroutineScope {
 | 
			
		||||
@@ -237,49 +279,30 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
 | 
			
		||||
                                    progressCount,
 | 
			
		||||
                                    manga,
 | 
			
		||||
                                ) {
 | 
			
		||||
                                    when {
 | 
			
		||||
                                        manga.updateStrategy != UpdateStrategy.ALWAYS_UPDATE ->
 | 
			
		||||
                                            skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_always_update))
 | 
			
		||||
                                    try {
 | 
			
		||||
                                        val newChapters = updateManga(manga, fetchWindow)
 | 
			
		||||
                                            .sortedByDescending { it.sourceOrder }
 | 
			
		||||
 | 
			
		||||
                                        MANGA_NON_COMPLETED in restrictions && manga.status.toInt() == SManga.COMPLETED ->
 | 
			
		||||
                                            skippedUpdates.add(manga to context.getString(R.string.skipped_reason_completed))
 | 
			
		||||
 | 
			
		||||
                                        MANGA_HAS_UNREAD in restrictions && libraryManga.unreadCount != 0L ->
 | 
			
		||||
                                            skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_caught_up))
 | 
			
		||||
 | 
			
		||||
                                        MANGA_NON_READ in restrictions && libraryManga.totalChapters > 0L && !libraryManga.hasStarted ->
 | 
			
		||||
                                            skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_started))
 | 
			
		||||
 | 
			
		||||
                                        MANGA_OUTSIDE_RELEASE_PERIOD in restrictions && manga.nextUpdate > fetchWindow.second ->
 | 
			
		||||
                                            skippedUpdates.add(manga to context.getString(R.string.skipped_reason_not_in_release_period))
 | 
			
		||||
 | 
			
		||||
                                        else -> {
 | 
			
		||||
                                            try {
 | 
			
		||||
                                                val newChapters = updateManga(manga, fetchWindow)
 | 
			
		||||
                                                    .sortedByDescending { it.sourceOrder }
 | 
			
		||||
 | 
			
		||||
                                                if (newChapters.isNotEmpty()) {
 | 
			
		||||
                                                    val categoryIds = getCategories.await(manga.id).map { it.id }
 | 
			
		||||
                                                    if (manga.shouldDownloadNewChapters(categoryIds, downloadPreferences)) {
 | 
			
		||||
                                                        downloadChapters(manga, newChapters)
 | 
			
		||||
                                                        hasDownloads.set(true)
 | 
			
		||||
                                                    }
 | 
			
		||||
 | 
			
		||||
                                                    libraryPreferences.newUpdatesCount().getAndSet { it + newChapters.size }
 | 
			
		||||
 | 
			
		||||
                                                    // Convert to the manga that contains new chapters
 | 
			
		||||
                                                    newUpdates.add(manga to newChapters.toTypedArray())
 | 
			
		||||
                                                }
 | 
			
		||||
                                            } catch (e: Throwable) {
 | 
			
		||||
                                                val errorMessage = when (e) {
 | 
			
		||||
                                                    is NoChaptersException -> context.getString(R.string.no_chapters_error)
 | 
			
		||||
                                                    // failedUpdates will already have the source, don't need to copy it into the message
 | 
			
		||||
                                                    is SourceNotInstalledException -> context.getString(R.string.loader_not_implemented_error)
 | 
			
		||||
                                                    else -> e.message
 | 
			
		||||
                                                }
 | 
			
		||||
                                                failedUpdates.add(manga to errorMessage)
 | 
			
		||||
                                        if (newChapters.isNotEmpty()) {
 | 
			
		||||
                                            val categoryIds = getCategories.await(manga.id).map { it.id }
 | 
			
		||||
                                            if (manga.shouldDownloadNewChapters(categoryIds, downloadPreferences)) {
 | 
			
		||||
                                                downloadChapters(manga, newChapters)
 | 
			
		||||
                                                hasDownloads.set(true)
 | 
			
		||||
                                            }
 | 
			
		||||
 | 
			
		||||
                                            libraryPreferences.newUpdatesCount().getAndSet { it + newChapters.size }
 | 
			
		||||
 | 
			
		||||
                                            // Convert to the manga that contains new chapters
 | 
			
		||||
                                            newUpdates.add(manga to newChapters.toTypedArray())
 | 
			
		||||
                                        }
 | 
			
		||||
                                    } catch (e: Throwable) {
 | 
			
		||||
                                        val errorMessage = when (e) {
 | 
			
		||||
                                            is NoChaptersException -> context.getString(R.string.no_chapters_error)
 | 
			
		||||
                                            // failedUpdates will already have the source, don't need to copy it into the message
 | 
			
		||||
                                            is SourceNotInstalledException -> context.getString(R.string.loader_not_implemented_error)
 | 
			
		||||
                                            else -> e.message
 | 
			
		||||
                                        }
 | 
			
		||||
                                        failedUpdates.add(manga to errorMessage)
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                                    if (libraryPreferences.autoUpdateTrackers().get()) {
 | 
			
		||||
@@ -309,16 +332,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
 | 
			
		||||
                errorFile.getUriCompat(context),
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        if (skippedUpdates.isNotEmpty()) {
 | 
			
		||||
            // TODO: surface skipped reasons to user
 | 
			
		||||
            logcat {
 | 
			
		||||
                skippedUpdates
 | 
			
		||||
                    .groupBy { it.second }
 | 
			
		||||
                    .map { (reason, entries) -> "$reason: [${entries.map { it.first.title }.sorted().joinToString()}]" }
 | 
			
		||||
                    .joinToString()
 | 
			
		||||
            }
 | 
			
		||||
            notifier.showUpdateSkippedNotification(skippedUpdates.size)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
 | 
			
		||||
@@ -428,29 +441,27 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
 | 
			
		||||
        completed: AtomicInteger,
 | 
			
		||||
        manga: Manga,
 | 
			
		||||
        block: suspend () -> Unit,
 | 
			
		||||
    ) {
 | 
			
		||||
        coroutineScope {
 | 
			
		||||
            ensureActive()
 | 
			
		||||
    ) = coroutineScope {
 | 
			
		||||
        ensureActive()
 | 
			
		||||
 | 
			
		||||
            updatingManga.add(manga)
 | 
			
		||||
            notifier.showProgressNotification(
 | 
			
		||||
                updatingManga,
 | 
			
		||||
                completed.get(),
 | 
			
		||||
                mangaToUpdate.size,
 | 
			
		||||
            )
 | 
			
		||||
        updatingManga.add(manga)
 | 
			
		||||
        notifier.showProgressNotification(
 | 
			
		||||
            updatingManga,
 | 
			
		||||
            completed.get(),
 | 
			
		||||
            mangaToUpdate.size,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
            block()
 | 
			
		||||
        block()
 | 
			
		||||
 | 
			
		||||
            ensureActive()
 | 
			
		||||
        ensureActive()
 | 
			
		||||
 | 
			
		||||
            updatingManga.remove(manga)
 | 
			
		||||
            completed.getAndIncrement()
 | 
			
		||||
            notifier.showProgressNotification(
 | 
			
		||||
                updatingManga,
 | 
			
		||||
                completed.get(),
 | 
			
		||||
                mangaToUpdate.size,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        updatingManga.remove(manga)
 | 
			
		||||
        completed.getAndIncrement()
 | 
			
		||||
        notifier.showProgressNotification(
 | 
			
		||||
            updatingManga,
 | 
			
		||||
            completed.get(),
 | 
			
		||||
            mangaToUpdate.size,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -30,10 +30,14 @@ import tachiyomi.core.util.lang.launchUI
 | 
			
		||||
import tachiyomi.domain.chapter.model.Chapter
 | 
			
		||||
import tachiyomi.domain.manga.model.Manga
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.text.NumberFormat
 | 
			
		||||
 | 
			
		||||
class LibraryUpdateNotifier(private val context: Context) {
 | 
			
		||||
 | 
			
		||||
    private val preferences: SecurityPreferences by injectLazy()
 | 
			
		||||
    private val percentFormatter = NumberFormat.getPercentInstance().apply {
 | 
			
		||||
        maximumFractionDigits = 0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Pending intent of action that cancels the library update
 | 
			
		||||
@@ -78,7 +82,7 @@ class LibraryUpdateNotifier(private val context: Context) {
 | 
			
		||||
        } else {
 | 
			
		||||
            val updatingText = manga.joinToString("\n") { it.title.chop(40) }
 | 
			
		||||
            progressNotificationBuilder
 | 
			
		||||
                .setContentTitle(context.getString(R.string.notification_updating, current, total))
 | 
			
		||||
                .setContentTitle(context.getString(R.string.notification_updating_progress, percentFormatter.format(current.toFloat() / total)))
 | 
			
		||||
                .setStyle(NotificationCompat.BigTextStyle().bigText(updatingText))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user