fixes
This commit is contained in:
parent
3b40ba7e02
commit
76394309fd
4 changed files with 82 additions and 91 deletions
|
|
@ -1062,8 +1062,10 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
|
||||
result.message = repository.startDownloadWorker(queued, context).getOrElse { "" }
|
||||
|
||||
val ids = queued.filter { it.needsDataUpdating() }.map { it.id }
|
||||
continueUpdatingDataInBackground(ids)
|
||||
val idsToUpdateDataInBackground = queued.filter { it.needsDataUpdating() && it.downloadStartTime > 0 }.map { it.id }
|
||||
if (idsToUpdateDataInBackground.isNotEmpty()) {
|
||||
continueUpdatingDataInBackground(idsToUpdateDataInBackground)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1201,18 +1203,16 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
}
|
||||
|
||||
private fun continueUpdatingDataInBackground(ids: List<Long>){
|
||||
val id = System.currentTimeMillis().toInt()
|
||||
val workRequest = OneTimeWorkRequestBuilder<UpdateMultipleDownloadsDataWorker>()
|
||||
.setInputData(
|
||||
Data.Builder()
|
||||
.putLongArray("ids", ids.toLongArray())
|
||||
.putInt("id", id)
|
||||
.build())
|
||||
.addTag("updateData")
|
||||
.build()
|
||||
val context = App.instance
|
||||
WorkManager.getInstance(context).enqueueUniqueWork(
|
||||
id.toString(),
|
||||
System.currentTimeMillis().toString(),
|
||||
ExistingWorkPolicy.REPLACE,
|
||||
workRequest
|
||||
)
|
||||
|
|
|
|||
|
|
@ -626,7 +626,7 @@ class NotificationUtil(var context: Context) {
|
|||
return notificationBuilder
|
||||
.setContentTitle(resources.getString(R.string.updating_download_data))
|
||||
.setOngoing(true)
|
||||
.setCategory(Notification.CATEGORY_PROGRESS)
|
||||
.setCategory(Notification.CATEGORY_MESSAGE)
|
||||
.setSmallIcon(R.drawable.ic_launcher_foreground_large)
|
||||
.setLargeIcon(
|
||||
BitmapFactory.decodeResource(
|
||||
|
|
@ -637,7 +637,6 @@ class NotificationUtil(var context: Context) {
|
|||
.setContentText("")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setProgress(PROGRESS_MAX, PROGRESS_CURR, false)
|
||||
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
|
||||
.clearActions()
|
||||
.build()
|
||||
|
|
|
|||
|
|
@ -43,17 +43,12 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.CoroutineStart
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.takeWhile
|
||||
import kotlinx.coroutines.flow.transformLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
|
|
@ -80,6 +75,8 @@ class DownloadWorker(private val context: Context,workerParams: WorkerParameters
|
|||
private lateinit var eventBus: EventBus
|
||||
|
||||
private lateinit var queueState : Flow<List<DownloadItem>>
|
||||
lateinit var observeJob : Job
|
||||
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
|
|
@ -107,11 +104,6 @@ class DownloadWorker(private val context: Context,workerParams: WorkerParameters
|
|||
)
|
||||
}
|
||||
|
||||
private fun cancelSelf() {
|
||||
workManager.cancelWorkById(this@DownloadWorker.id)
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
override suspend fun doWork(): Result {
|
||||
//init
|
||||
|
|
@ -157,75 +149,75 @@ class DownloadWorker(private val context: Context,workerParams: WorkerParameters
|
|||
|
||||
val downloadJobs = mutableMapOf<Long, Job>()
|
||||
|
||||
queueState.collectLatest { queue ->
|
||||
val runningCount = queue.asSequence()
|
||||
.filter { it.status == DownloadRepository.Status.Active.toString() }
|
||||
.count()
|
||||
observeJob = CoroutineScope(SupervisorJob()).launch {
|
||||
queueState.collectLatest { queue ->
|
||||
val runningCount = queue.asSequence()
|
||||
.filter { it.status == DownloadRepository.Status.Active.toString() }
|
||||
.count()
|
||||
|
||||
val queueItems = queue.asSequence()
|
||||
.filter { it.status != DownloadRepository.Status.Active.toString() }
|
||||
val queueItems = queue.asSequence()
|
||||
.filter { it.status != DownloadRepository.Status.Active.toString() }
|
||||
|
||||
val queueCount = queueItems.count()
|
||||
if (queueCount == 0 && runningCount == 0) {
|
||||
cancelSelf()
|
||||
return@collectLatest
|
||||
}
|
||||
|
||||
val useScheduler = sharedPreferences.getBoolean("use_scheduler", false)
|
||||
if (useScheduler){
|
||||
if (queueItems.none{ it.downloadStartTime > 0L } && runningCount == 0 && !alarmScheduler.isDuringTheScheduledTime()) {
|
||||
cancelSelf()
|
||||
val queueCount = queueItems.count()
|
||||
if (queueCount == 0 && runningCount == 0) {
|
||||
observeJob.cancel()
|
||||
return@collectLatest
|
||||
}
|
||||
}
|
||||
|
||||
val concurrentDownloads = sharedPreferences.getInt("concurrent_downloads", 1) - runningCount
|
||||
if (concurrentDownloads > 0) {
|
||||
//free spots are open
|
||||
if (priorityItemIDs.isNotEmpty()) {
|
||||
if (!continueAfterPriorityIds && queueItems.none { priorityItemIDs.contains(it.id) }) {
|
||||
//dont queue any more items if only required priority items
|
||||
cancelSelf()
|
||||
val useScheduler = sharedPreferences.getBoolean("use_scheduler", false)
|
||||
if (useScheduler){
|
||||
if (queueItems.none{ it.downloadStartTime > 0L } && runningCount == 0 && !alarmScheduler.isDuringTheScheduledTime()) {
|
||||
observeJob.cancel()
|
||||
return@collectLatest
|
||||
}
|
||||
}
|
||||
|
||||
// Use supervisorScope to cancel child jobs when the downloader job is cancelled
|
||||
supervisorScope {
|
||||
val queuedDownloads = queueItems
|
||||
.toList()
|
||||
.take(concurrentDownloads)
|
||||
|
||||
val queuedIDs = queuedDownloads.map { it.id }
|
||||
val downloadJobsToStop = downloadJobs.filter { it.key !in queuedIDs }
|
||||
downloadJobsToStop.forEach { (download, job) ->
|
||||
job.cancel()
|
||||
downloadJobs.remove(download)
|
||||
val concurrentDownloads = sharedPreferences.getInt("concurrent_downloads", 1) - runningCount
|
||||
if (concurrentDownloads > 0) {
|
||||
//free spots are open
|
||||
if (priorityItemIDs.isNotEmpty()) {
|
||||
if (!continueAfterPriorityIds && queueItems.none { priorityItemIDs.contains(it.id) }) {
|
||||
//dont queue any more items if only required priority items
|
||||
observeJob.cancel()
|
||||
return@collectLatest
|
||||
}
|
||||
}
|
||||
|
||||
val downloadsToStart = queuedDownloads.filter { it.id !in downloadJobs }
|
||||
downloadsToStart.forEach { download ->
|
||||
downloadJobs[download.id] = launchDownloadJob(download)
|
||||
// Use supervisorScope to cancel child jobs when the downloader job is cancelled
|
||||
supervisorScope {
|
||||
val queuedDownloads = queueItems
|
||||
.toList()
|
||||
.take(concurrentDownloads)
|
||||
|
||||
val queuedIDs = queuedDownloads.map { it.id }
|
||||
val downloadJobsToStop = downloadJobs.filter { it.key !in queuedIDs }
|
||||
downloadJobsToStop.forEach { (download, job) ->
|
||||
job.cancel()
|
||||
downloadJobs.remove(download)
|
||||
}
|
||||
|
||||
val downloadsToStart = queuedDownloads.filter { it.id !in downloadJobs }
|
||||
downloadsToStart.forEach { downloadItem ->
|
||||
val notification = notificationUtil.createDownloadServiceNotification(openDownloadQueue, downloadItem.title.ifEmpty { downloadItem.url })
|
||||
notificationUtil.notify(downloadItem.id.toInt(), notification)
|
||||
downloadJobs[downloadItem.id] = launchDownloadJob(downloadItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
while (observeJob.isActive) {
|
||||
//keep alive
|
||||
}
|
||||
|
||||
return Result.Success()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
private fun launchIO(block: suspend CoroutineScope.() -> Unit): Job =
|
||||
GlobalScope.launch(Dispatchers.IO, CoroutineStart.DEFAULT, block)
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private fun launchDownloadJob(downloadItem: DownloadItem) = launchIO {
|
||||
val notification = notificationUtil.createDownloadServiceNotification(openDownloadQueue, downloadItem.title.ifEmpty { downloadItem.url })
|
||||
notificationUtil.notify(downloadItem.id.toInt(), notification)
|
||||
|
||||
private fun launchDownloadJob(downloadItem: DownloadItem) = CoroutineScope(Dispatchers.IO).launch {
|
||||
val writtenPath = downloadItem.format.format_note.contains("-P ")
|
||||
val noCache = writtenPath || (!sharedPreferences.getBoolean("cache_downloads", true) && File(FileUtil.formatPath(downloadItem.downloadPath)).canWrite())
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package com.deniscerri.ytdl.work
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||
import android.os.Build
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
|
|
@ -14,37 +16,37 @@ import com.deniscerri.ytdl.util.NotificationUtil
|
|||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
|
||||
class UpdateMultipleDownloadsDataWorker(
|
||||
private val context: Context,
|
||||
workerParams: WorkerParameters
|
||||
) : Worker(context, workerParams) {
|
||||
override fun doWork(): Result {
|
||||
class UpdateMultipleDownloadsDataWorker(private val context: Context,workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) {
|
||||
|
||||
override suspend fun getForegroundInfo(): ForegroundInfo {
|
||||
val workNotif = NotificationUtil(App.instance).createDataUpdateNotification()
|
||||
|
||||
return ForegroundInfo(
|
||||
2000000000,
|
||||
workNotif,
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||
} else {
|
||||
0
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val dbManager = DBManager.getInstance(context)
|
||||
val dao = dbManager.downloadDao
|
||||
val resDao = dbManager.resultDao
|
||||
val commandTemplateDao = dbManager.commandTemplateDao
|
||||
val resultRepo = ResultRepository(resDao,commandTemplateDao, context)
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val ids = inputData.getLongArray("ids")!!.toMutableList()
|
||||
val workID = inputData.getInt("id", 0)
|
||||
if (workID == 0) return Result.failure()
|
||||
|
||||
val notification = notificationUtil.createDataUpdateNotification()
|
||||
|
||||
if (Build.VERSION.SDK_INT > 33) {
|
||||
setForegroundAsync(ForegroundInfo(workID, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC))
|
||||
}else{
|
||||
setForegroundAsync(ForegroundInfo(workID, notification))
|
||||
}
|
||||
|
||||
var count = 0
|
||||
|
||||
return try{
|
||||
setForegroundSafely()
|
||||
try{
|
||||
ids.forEach {
|
||||
if (!isStopped){
|
||||
val d = dao.getDownloadById(it)
|
||||
if (d.title.isNotBlank() && d.author.isNotBlank() && d.thumb.isNotBlank()) {
|
||||
count++
|
||||
return@forEach
|
||||
}
|
||||
|
||||
|
|
@ -59,20 +61,18 @@ class UpdateMultipleDownloadsDataWorker(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
count++
|
||||
notificationUtil.updateDataUpdateNotification(workID, UpdateMultipleDownloadsDataWorker::class.java.name, count, ids.size)
|
||||
}else{
|
||||
throw Exception()
|
||||
}
|
||||
}
|
||||
|
||||
Result.success()
|
||||
|
||||
}catch (e: Exception){
|
||||
notificationUtil.cancelDownloadNotification(workID)
|
||||
ids.clear()
|
||||
Result.failure()
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue