Skip to content

Commit

Permalink
fix(notifications): Revert parallelize downloads
Browse files Browse the repository at this point in the history
  • Loading branch information
quickdesh committed Jul 25, 2023
1 parent 4ffae67 commit 0c0bf51
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 86 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.data.download.anime

import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.Context
import android.graphics.BitmapFactory
Expand All @@ -12,8 +11,8 @@ import eu.kanade.tachiyomi.data.notification.NotificationHandler
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.system.cancelNotification
import eu.kanade.tachiyomi.util.system.notificationBuilder
import eu.kanade.tachiyomi.util.system.notificationManager
import eu.kanade.tachiyomi.util.system.notify
import uy.kohesive.injekt.injectLazy
import java.util.regex.Pattern
Expand Down Expand Up @@ -46,16 +45,6 @@ internal class AnimeDownloadNotifier(private val context: Context) {
*/
private var isDownloading = false

/**
* Updated when paused
*/
var paused = false

/**
* Map to store notification IDs for each download
*/
private val notificationIdMap: MutableMap<Long, Int> = mutableMapOf()

/**
* Shows a notification from this builder.
*
Expand All @@ -69,30 +58,29 @@ internal class AnimeDownloadNotifier(private val context: Context) {
* Dismiss the downloader's notification. Downloader error notifications use a different id, so
* those can only be dismissed by the user.
*/
fun dismissProgress(download: AnimeDownload) {
val notificationId = notificationIdMap[download.episode.id] ?: return
context.cancelNotification(notificationId)
notificationIdMap.remove(download.episode.id)
fun dismissProgress() {
context.notificationManager.cancel(Notifications.ID_DOWNLOAD_EPISODE_PROGRESS)
}

/**
* Called when download progress changes.
*
* @param download download object containing download information.
*/
@SuppressLint("RestrictedApi", "StringFormatInvalid")
fun onProgressChange(download: AnimeDownload) {
val notificationId = notificationIdMap.getOrPut(download.episode.id) {
download.episode.id.hashCode()
}

with(progressNotificationBuilder) {
if (!isDownloading) {
setSmallIcon(android.R.drawable.stat_sys_download)
clearActions()
// Open download manager when clicked
setContentIntent(NotificationHandler.openAnimeDownloadManagerPendingActivity(context))
isDownloading = true
// Pause action
addAction(
R.drawable.ic_pause_24dp,
context.getString(R.string.action_pause),
NotificationReceiver.pauseAnimeDownloadsPendingBroadcast(context),
)
}

val downloadingProgressText = if (download.totalProgress == 0) {
Expand All @@ -118,28 +106,14 @@ internal class AnimeDownloadNotifier(private val context: Context) {
}
setOngoing(true)

show(notificationId)
}

// Add pause action if not already added
val pauseActionIntent = NotificationReceiver.pauseAnimeDownloadsPendingBroadcast(context)
val pauseActionAdded = progressNotificationBuilder.mActions.any { it.actionIntent == pauseActionIntent }
if (!paused && !pauseActionAdded) {
progressNotificationBuilder.addAction(
R.drawable.ic_pause_24dp,
context.getString(R.string.action_pause),
pauseActionIntent,
)
paused = true
show(Notifications.ID_DOWNLOAD_EPISODE_PROGRESS)
}
}

/**
* Show notification when download is paused.
*/
fun onPaused(download: AnimeDownload) {
val notificationId = notificationIdMap[download.episode.id] ?: return

fun onPaused() {
with(progressNotificationBuilder) {
setContentTitle(context.getString(R.string.download_paused))
setContentText(context.getString(R.string.download_notifier_download_paused_episodes))
Expand All @@ -162,23 +136,21 @@ internal class AnimeDownloadNotifier(private val context: Context) {
NotificationReceiver.clearAnimeDownloadsPendingBroadcast(context),
)

show(notificationId)
show(Notifications.ID_DOWNLOAD_EPISODE_PROGRESS)
}

// Reset initial values
isDownloading = false
paused = false
}

/**
* Resets the state once downloads are completed.
*/
fun onComplete(download: AnimeDownload) {
dismissProgress(download)
fun onComplete() {
dismissProgress()

// Reset states to default
isDownloading = false
paused = false
}

/**
Expand All @@ -198,7 +170,7 @@ internal class AnimeDownloadNotifier(private val context: Context) {
timeout?.let { setTimeoutAfter(it) }
contentIntent?.let { setContentIntent(it) }

show(Notifications.ID_DOWNLOAD_CHAPTER_ERROR)
show(Notifications.ID_DOWNLOAD_EPISODE_ERROR)
}

// Reset download information
Expand All @@ -212,11 +184,7 @@ internal class AnimeDownloadNotifier(private val context: Context) {
* @param error string containing error information.
* @param episode string containing episode title.
*/
fun onError(download: AnimeDownload, error: String? = null, episode: String? = null, animeTitle: String? = null) {
val notificationId = notificationIdMap.getOrPut(download.episode.id) {
download.episode.id.hashCode()
}

fun onError(error: String? = null, episode: String? = null, animeTitle: String? = null) {
// Create notification
with(errorNotificationBuilder) {
setContentTitle(
Expand All @@ -228,7 +196,7 @@ internal class AnimeDownloadNotifier(private val context: Context) {
setContentIntent(NotificationHandler.openAnimeDownloadManagerPendingActivity(context))
setProgress(0, 0, false)

show(notificationId)
show(Notifications.ID_DOWNLOAD_EPISODE_ERROR)
}

// Reset download information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import android.app.Notification
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.os.PowerManager
import androidx.annotation.StringRes
Expand Down Expand Up @@ -90,14 +89,9 @@ class AnimeDownloadService : Service() {

override fun onCreate() {
scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
startForeground(Notifications.ID_DOWNLOAD_EPISODE_PROGRESS, getPlaceholderNotification())
wakeLock = acquireWakeLock(javaClass.name)
_isRunning.value = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForeground(1, getPlaceholderNotification())
} else {
@Suppress("DEPRECATION")
startForeground(1, Notification())
}
listenNetworkChanges()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,20 +160,14 @@ class AnimeDownloader(
.forEach { it.status = AnimeDownload.State.ERROR }

if (reason != null) {
queueState.value.forEach {
notifier.onWarning(reason)
return
}
notifier.onWarning(reason)
return
}

if (isPaused && queueState.value.isNotEmpty()) {
queueState.value.forEach {
notifier.onPaused(it)
}
notifier.onPaused()
} else {
queueState.value.forEach {
notifier.onComplete(it)
}
notifier.onComplete()
}

isPaused = false
Expand Down Expand Up @@ -201,10 +195,8 @@ class AnimeDownloader(
fun clearQueue() {
destroySubscription()

queueState.value.forEach {
notifier.dismissProgress(it)
}
_clearQueue()
notifier.dismissProgress()
}

/**
Expand All @@ -214,8 +206,8 @@ class AnimeDownloader(
// Unsubscribe the previous subscription if it exists
destroySubscription()

subscription = downloadsRelay
.flatMapIterable { it }
subscription = downloadsRelay.flatMapIterable { it }
// Concurrently download from 3 different sources
.groupBy { it.source }
.flatMap(
{ bySource ->
Expand All @@ -228,17 +220,15 @@ class AnimeDownloader(
downloadPreferences.numberOfDownloads().get(),
)
},
downloadPreferences.numberOfDownloads().get(), // Set the maximum number of concurrent downloads here
3,
)
.subscribe(
{ completedDownload ->
completeAnimeDownload(completedDownload)
},
{ error ->
logcat(LogPriority.ERROR, error)
queueState.value.forEach {
notifier.onError(it, error.message, it.episode.name, it.anime.title)
}
notifier.onError(error.message)
stop()
},
)
Expand Down Expand Up @@ -299,7 +289,7 @@ class AnimeDownloader(

// Start downloader if needed
if (autoStart && wasEmpty) {
val queuedDownloads = queueState.value.filter { it: AnimeDownload -> it.source !is UnmeteredSource }.count()
val queuedDownloads = queueState.value.count { it: AnimeDownload -> it.source !is UnmeteredSource }
val maxDownloadsFromSource = queueState.value
.groupBy { it.source }
.filterKeys { it !is UnmeteredSource }
Expand Down Expand Up @@ -334,7 +324,7 @@ class AnimeDownloader(
val availSpace = DiskUtil.getAvailableStorageSpace(animeDir)
if (availSpace != -1L && availSpace < MIN_DISK_SPACE) {
download.status = AnimeDownload.State.ERROR
notifier.onError(download, context.getString(R.string.download_insufficient_space), download.episode.name, download.anime.title)
notifier.onError(context.getString(R.string.download_insufficient_space), download.episode.name, download.anime.title)
return@defer Observable.just(download)
}

Expand Down Expand Up @@ -399,15 +389,12 @@ class AnimeDownloader(
// Do after download completes
.doOnNext {
ensureSuccessfulAnimeDownload(download, animeDir, tmpDir, episodeDirname)

queueState.value.forEach {
if (download.status == AnimeDownload.State.DOWNLOADED) notifier.dismissProgress(it)
}
if (download.status == AnimeDownload.State.DOWNLOADED) notifier.dismissProgress()
}
// If the video list threw, it will resume here
.onErrorReturn { error ->
download.status = AnimeDownload.State.ERROR
notifier.onError(download, error.message, download.episode.name, download.anime.title)
notifier.onError(error.message, download.episode.name, download.anime.title)
download
}
}
Expand Down Expand Up @@ -465,7 +452,7 @@ class AnimeDownloader(
.onErrorReturn {
video.progress = 0
video.status = Video.State.ERROR
notifier.onError(download, it.message, download.episode.name, download.anime.title)
notifier.onError(it.message, download.episode.name, download.anime.title)
video
}
}
Expand Down Expand Up @@ -845,8 +832,8 @@ class AnimeDownloader(
companion object {
const val TMP_DIR_SUFFIX = "_tmp"
const val WARNING_NOTIF_TIMEOUT_MS = 30_000L
const val EPISODES_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 15
private const val DOWNLOADS_QUEUED_WARNING_THRESHOLD = 30
const val EPISODES_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 10
private const val DOWNLOADS_QUEUED_WARNING_THRESHOLD = 20
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ object Notifications {
private const val GROUP_DOWNLOADER = "group_downloader"
const val CHANNEL_DOWNLOADER_PROGRESS = "downloader_progress_channel"
const val ID_DOWNLOAD_CHAPTER_PROGRESS = -201
const val ID_DOWNLOAD_EPISODE_PROGRESS = -205
const val ID_DOWNLOAD_EPISODE_PROGRESS = -203
const val CHANNEL_DOWNLOADER_ERROR = "downloader_error_channel"
const val ID_DOWNLOAD_CHAPTER_ERROR = -202
const val ID_DOWNLOAD_EPISODE_ERROR = -204

/**
* Notification channel and ids used by the library updater.
Expand Down

0 comments on commit 0c0bf51

Please sign in to comment.