mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	download not working
This commit is contained in:
		
							parent
							
								
									9da1ce6032
								
							
						
					
					
						commit
						602cd065ce
					
				
					 5 changed files with 168 additions and 210 deletions
				
			
		|  | @ -147,11 +147,11 @@ class EpisodeAdapter( | |||
|                         clickCallback.invoke(EpisodeClickEvent(ACTION_CHROME_CAST_EPISODE, card)) | ||||
|                     } else { | ||||
|                         // clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card)) | ||||
|                         clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card)) | ||||
|                         clickCallback.invoke(EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, card)) | ||||
|                     } | ||||
|                 } else { | ||||
|                     // clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card)) | ||||
|                     clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card)) | ||||
|                     clickCallback.invoke(EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, card)) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  |  | |||
|  | @ -341,10 +341,19 @@ class ResultFragment : Fragment() { | |||
|                     if (tempUrl != null) { | ||||
|                         viewModel.loadEpisode(episodeClick.data, true) { data -> | ||||
|                             if (data is Resource.Success) { | ||||
|                                 val meta = VideoDownloadManager.DownloadEpisodeMetadata( | ||||
|                                     episodeClick.data.id, | ||||
|                                     currentHeaderName ?: return@loadEpisode, | ||||
|                                     apiName ?: return@loadEpisode, | ||||
|                                     episodeClick.data.poster, | ||||
|                                     episodeClick.data.name, | ||||
|                                     episodeClick.data.season, | ||||
|                                     episodeClick.data.episode | ||||
|                                 ) | ||||
|                                 VideoDownloadManager.DownloadEpisode( | ||||
|                                     requireContext(), | ||||
|                                     tempUrl, | ||||
|                                     episodeClick.data, | ||||
|                                     meta, | ||||
|                                     data.value.links | ||||
|                                 ) | ||||
|                             } | ||||
|  |  | |||
|  | @ -6,31 +6,23 @@ import android.app.PendingIntent | |||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.graphics.Bitmap | ||||
| import android.net.Uri | ||||
| import android.os.Build | ||||
| import android.os.Environment | ||||
| import androidx.annotation.DrawableRes | ||||
| import androidx.core.app.NotificationCompat | ||||
| import androidx.core.app.NotificationManagerCompat | ||||
| import androidx.core.net.toUri | ||||
| import com.anggrayudi.storage.extension.closeStream | ||||
| import com.anggrayudi.storage.file.DocumentFileCompat | ||||
| import com.anggrayudi.storage.file.openOutputStream | ||||
| import com.bumptech.glide.Glide | ||||
| import com.google.android.exoplayer2.database.ExoDatabaseProvider | ||||
| import com.google.android.exoplayer2.offline.DownloadManager | ||||
| import com.google.android.exoplayer2.offline.DownloadRequest | ||||
| import com.google.android.exoplayer2.offline.DownloadService | ||||
| import com.google.android.exoplayer2.offline.DownloadService.sendAddDownload | ||||
| import com.google.android.exoplayer2.offline.StreamKey | ||||
| import com.google.android.exoplayer2.scheduler.Requirements | ||||
| import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory | ||||
| import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor | ||||
| import com.google.android.exoplayer2.upstream.cache.SimpleCache | ||||
| import com.lagradost.cloudstream3.MainActivity | ||||
| import com.lagradost.cloudstream3.R | ||||
| import com.lagradost.cloudstream3.UIHelper.colorFromAttribute | ||||
| import com.lagradost.cloudstream3.USER_AGENT | ||||
| import com.lagradost.cloudstream3.ui.result.ResultEpisode | ||||
| import java.io.File | ||||
| import java.util.concurrent.Executor | ||||
| import java.io.BufferedInputStream | ||||
| import java.io.InputStream | ||||
| import java.net.URL | ||||
| import java.net.URLConnection | ||||
| 
 | ||||
| 
 | ||||
| const val CHANNEL_ID = "cloudstream3.general" | ||||
|  | @ -38,6 +30,11 @@ const val CHANNEL_NAME = "Downloads" | |||
| const val CHANNEL_DESCRIPT = "The download notification channel" | ||||
| 
 | ||||
| object VideoDownloadManager { | ||||
|     var maxConcurrentDownloads = 3 | ||||
| 
 | ||||
|     private const val USER_AGENT = | ||||
|         "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" | ||||
| 
 | ||||
|     @DrawableRes | ||||
|     const val imgDone = R.drawable.rddone | ||||
| 
 | ||||
|  | @ -76,6 +73,16 @@ object VideoDownloadManager { | |||
|         Stop, | ||||
|     } | ||||
| 
 | ||||
|     data class DownloadEpisodeMetadata( | ||||
|         val id: Int, | ||||
|         val mainName: String, | ||||
|         val sourceApiName: String?, | ||||
|         val poster: String?, | ||||
|         val name: String?, | ||||
|         val season: Int?, | ||||
|         val episode: Int? | ||||
|     ) | ||||
| 
 | ||||
|     private var hasCreatedNotChanel = false | ||||
|     private fun Context.createNotificationChannel() { | ||||
|         hasCreatedNotChanel = true | ||||
|  | @ -111,29 +118,22 @@ object VideoDownloadManager { | |||
|         return null | ||||
|     } | ||||
| 
 | ||||
|     fun createNotification( | ||||
|     private fun createNotification( | ||||
|         context: Context, | ||||
|         text: String, | ||||
|         source: String, | ||||
|         ep: ResultEpisode, | ||||
|         source: String?, | ||||
|         linkName: String?, | ||||
|         ep: DownloadEpisodeMetadata, | ||||
|         state: DownloadType, | ||||
|         progress: Long, | ||||
|         total: Long, | ||||
|     ) { | ||||
|         val intent = Intent(context, MainActivity::class.java).apply { | ||||
|             data = source.toUri() | ||||
|             flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK | ||||
|         } | ||||
| 
 | ||||
|         val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, 0) | ||||
|         val builder = NotificationCompat.Builder(context, CHANNEL_ID) | ||||
|             .setAutoCancel(true) | ||||
|             .setColorized(true) | ||||
|             .setAutoCancel(true) | ||||
|             .setOnlyAlertOnce(true) | ||||
|             .setPriority(NotificationCompat.PRIORITY_DEFAULT) | ||||
|             .setColor(context.colorFromAttribute(R.attr.colorPrimary)) | ||||
|             .setContentText(text) | ||||
|             .setContentTitle(ep.mainName) | ||||
|             .setSmallIcon( | ||||
|                 when (state) { | ||||
|                     DownloadType.IsDone -> imgDone | ||||
|  | @ -143,19 +143,72 @@ object VideoDownloadManager { | |||
|                     DownloadType.IsStopped -> imgStopped | ||||
|                 } | ||||
|             ) | ||||
|             .setContentIntent(pendingIntent) | ||||
| 
 | ||||
|         if (ep.sourceApiName != null) { | ||||
|             builder.setSubText(ep.sourceApiName) | ||||
|         } | ||||
| 
 | ||||
|         if (source != null) { | ||||
|             val intent = Intent(context, MainActivity::class.java).apply { | ||||
|                 data = source.toUri() | ||||
|                 flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK | ||||
|             } | ||||
|             val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, 0) | ||||
|             builder.setContentIntent(pendingIntent) | ||||
|         } | ||||
| 
 | ||||
|         if (state == DownloadType.IsDownloading || state == DownloadType.IsPaused) { | ||||
|             builder.setProgress(total.toInt(), progress.toInt(), false) | ||||
|         } | ||||
| 
 | ||||
|         val rowTwoExtra = if (ep.name != null) " - ${ep.name}\n" else "" | ||||
|         val rowTwo = if (ep.season != null && ep.episode != null) { | ||||
|             "S${ep.season}:E${ep.episode}" + rowTwoExtra | ||||
|         } else if (ep.episode != null) { | ||||
|             "Episode ${ep.episode}" + rowTwoExtra | ||||
|         } else { | ||||
|             (ep.name ?: "") + "" | ||||
|         } | ||||
| 
 | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||
|             if (ep.poster != null) { | ||||
|                 val poster = context.getImageBitmapFromUrl(ep.poster) | ||||
|                 if (poster != null) | ||||
|                     builder.setLargeIcon(poster) | ||||
|             } | ||||
| 
 | ||||
|             val progressPercentage = progress * 100 / total | ||||
|             val progressMbString = "%.1f".format(progress / 1000000f) | ||||
|             val totalMbString = "%.1f".format(total / 1000000f) | ||||
| 
 | ||||
|             val bigText = | ||||
|                 if (state == DownloadType.IsDownloading || state == DownloadType.IsPaused) { | ||||
|                     (if (linkName == null) "" else "$linkName\n") + "$rowTwo\n$progressPercentage % ($progressMbString MB/$totalMbString MB)" | ||||
|                 } else if (state == DownloadType.IsFailed) { | ||||
|                     "Download Failed - $rowTwo" | ||||
|                 } else if (state == DownloadType.IsDone) { | ||||
|                     "Download Done - $rowTwo" | ||||
|                 } else { | ||||
|                     "Download Stopped - $rowTwo" | ||||
|                 } | ||||
| 
 | ||||
|             val bodyStyle = NotificationCompat.BigTextStyle() | ||||
|             bodyStyle.bigText(bigText) | ||||
|             builder.setStyle(bodyStyle) | ||||
|         } else { | ||||
|             val txt = if (state == DownloadType.IsDownloading || state == DownloadType.IsPaused) { | ||||
|                 rowTwo | ||||
|             } else if (state == DownloadType.IsFailed) { | ||||
|                 "Download Failed - $rowTwo" | ||||
|             } else if (state == DownloadType.IsDone) { | ||||
|                 "Download Done - $rowTwo" | ||||
|             } else { | ||||
|                 "Download Stopped - $rowTwo" | ||||
|             } | ||||
| 
 | ||||
|             builder.setContentText(txt) | ||||
|         } | ||||
| 
 | ||||
|         if ((state == DownloadType.IsDownloading || state == DownloadType.IsPaused) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||
|             val actionTypes: MutableList<DownloadActionType> = ArrayList() | ||||
|             // INIT | ||||
|  | @ -171,9 +224,9 @@ object VideoDownloadManager { | |||
| 
 | ||||
|             // ADD ACTIONS | ||||
|             for ((index, i) in actionTypes.withIndex()) { | ||||
|                 val _resultIntent = Intent(context, DownloadService::class.java) | ||||
|                 val actionResultIntent = Intent(context, DownloadService::class.java) | ||||
| 
 | ||||
|                 _resultIntent.putExtra( | ||||
|                 actionResultIntent.putExtra( | ||||
|                     "type", when (i) { | ||||
|                         DownloadActionType.Resume -> "resume" | ||||
|                         DownloadActionType.Pause -> "pause" | ||||
|  | @ -181,11 +234,11 @@ object VideoDownloadManager { | |||
|                     } | ||||
|                 ) | ||||
| 
 | ||||
|                 _resultIntent.putExtra("id", ep.id) | ||||
|                 actionResultIntent.putExtra("id", ep.id) | ||||
| 
 | ||||
|                 val pending: PendingIntent = PendingIntent.getService( | ||||
|                     context, 4337 + index + ep.id, | ||||
|                     _resultIntent, | ||||
|                     actionResultIntent, | ||||
|                     PendingIntent.FLAG_UPDATE_CURRENT | ||||
|                 ) | ||||
| 
 | ||||
|  | @ -215,96 +268,86 @@ object VideoDownloadManager { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     //https://exoplayer.dev/downloading-media.html | ||||
|     fun DownloadSingleEpisode(context: Context, source: String, ep: ResultEpisode, link: ExtractorLink) { | ||||
|         val url = link.url | ||||
|         val headers = mapOf("User-Agent" to USER_AGENT, "Referer" to link.referer) | ||||
|     fun DownloadSingleEpisode( | ||||
|         context: Context, | ||||
|         source: String?, | ||||
|         ep: DownloadEpisodeMetadata, | ||||
|         link: ExtractorLink | ||||
|     ): Boolean { | ||||
|         val name = (ep.name ?: "Episode ${ep.episode}") | ||||
|         val path = "Downloads/Anime/$name.mp4" | ||||
|         val dFile = DocumentFileCompat.fromSimplePath(context, basePath = path) ?: return false | ||||
| 
 | ||||
|         // Note: This should be a singleton in your app. | ||||
|         val databaseProvider = ExoDatabaseProvider(context) | ||||
|         val resume = false | ||||
| 
 | ||||
|         val downloadDirectory = File(Environment.getExternalStorageDirectory().path + "/Download/" + (ep.name ?: "Episode ${ep.episode}")) // File(context.cacheDir, "video_${ep.id}") | ||||
|         if (!resume && dFile.exists()) { | ||||
|             if (!dFile.delete()) { | ||||
|                 return false | ||||
|             } | ||||
|         } | ||||
|         if (!dFile.exists()) { | ||||
|             dFile.createFile("video/mp4", name) | ||||
|         } | ||||
| 
 | ||||
|         // A download cache should not evict media, so should use a NoopCacheEvictor. | ||||
|         val downloadCache = SimpleCache( | ||||
|             downloadDirectory, | ||||
|             NoOpCacheEvictor(), | ||||
|             databaseProvider) | ||||
|         // OPEN FILE | ||||
|         val fileStream = dFile.openOutputStream(context, resume) ?: return false | ||||
| 
 | ||||
|         // Create a factory for reading the data from the network. | ||||
|         val dataSourceFactory = DefaultHttpDataSourceFactory() | ||||
|         // CONNECT | ||||
|         val connection: URLConnection = URL(link.url).openConnection() | ||||
| 
 | ||||
|         // Choose an executor for downloading data. Using Runnable::run will cause each download task to | ||||
|         // download data on its own thread. Passing an executor that uses multiple threads will speed up | ||||
|         // download tasks that can be split into smaller parts for parallel execution. Applications that | ||||
|         // already have an executor for background downloads may wish to reuse their existing executor. | ||||
|         val downloadExecutor = Executor { obj: Runnable -> obj.run() } | ||||
|         // SET CONNECTION SETTINGS | ||||
|         connection.connectTimeout = 10000 | ||||
|         connection.setRequestProperty("Accept-Encoding", "identity") | ||||
|         connection.setRequestProperty("User-Agent", USER_AGENT) | ||||
|         if (link.referer.isNotEmpty()) connection.setRequestProperty("Referer", link.referer) | ||||
|         if (resume) connection.setRequestProperty("Range", "bytes=${dFile.length()}-") | ||||
|         val resumeLength = (if (resume) dFile.length() else 0) | ||||
| 
 | ||||
|         // ON CONNECTION | ||||
|         connection.connect() | ||||
|         val contentLength = connection.contentLength | ||||
|         if (contentLength < 5000000) return false // less than 5mb | ||||
|         val bytesTotal = contentLength + resumeLength | ||||
| 
 | ||||
|         // Create the download manager. | ||||
|         val downloadManager = DownloadManager( | ||||
|             context, | ||||
|             databaseProvider, | ||||
|             downloadCache, | ||||
|             dataSourceFactory, | ||||
|             downloadExecutor) | ||||
|         // READ DATA FROM CONNECTION | ||||
|         val connectionInputStream: InputStream = BufferedInputStream(connection.inputStream) | ||||
|         val buffer = ByteArray(1024) | ||||
|         var count: Int | ||||
|         var bytesDownloaded = resumeLength | ||||
| 
 | ||||
|         val requirements = Requirements(Requirements.NETWORK) | ||||
|         // Optionally, setters can be called to configure the download manager. | ||||
|         downloadManager.requirements = requirements | ||||
|         downloadManager.maxParallelDownloads = 3 | ||||
|         val builder = DownloadRequest.Builder(ep.id.toString(), link.url.toUri()) | ||||
|         fun updateNotification(type : DownloadType) { | ||||
|             createNotification( | ||||
|                 context, | ||||
|                 source, | ||||
|                 link.name, | ||||
|                 ep, | ||||
|                 type, | ||||
|                 bytesDownloaded, | ||||
|                 bytesTotal | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|         val downloadRequest: DownloadRequest = builder.build() | ||||
|         while (true) { | ||||
|             count = connectionInputStream.read(buffer) | ||||
|             if (count < 0) break | ||||
|             bytesDownloaded += count | ||||
| 
 | ||||
|         DownloadService.sendAddDownload( | ||||
|             context, | ||||
|             VideoDownloadService::class.java, | ||||
|             downloadRequest, | ||||
|             /* foreground= */ true) | ||||
| /* | ||||
|         val disposable = url.download(header = headers) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribeBy( | ||||
|                 onNext = { progress -> | ||||
|                     createNotification( | ||||
|                         context, | ||||
|                         "Downloading ${progress.downloadSizeStr()}/${progress.totalSizeStr()}", | ||||
|                         source, | ||||
|                         ep, | ||||
|                         DownloadType.IsDownloading, | ||||
|                         progress.downloadSize, | ||||
|                         progress.totalSize | ||||
|                     ) | ||||
|                 }, | ||||
|                 onComplete = { | ||||
|                     createNotification( | ||||
|                         context, | ||||
|                         "Download Done", | ||||
|                         source, | ||||
|                         ep, | ||||
|                         DownloadType.IsDone, | ||||
|                         0, 0 | ||||
|                     ) | ||||
|                 }, | ||||
|                 onError = { | ||||
|                     createNotification( | ||||
|                         context, | ||||
|                         "Download Failed", | ||||
|                         source, | ||||
|                         ep, | ||||
|                         DownloadType.IsFailed, | ||||
|                         0, 0 | ||||
|                     ) | ||||
|                 } | ||||
|             )*/ | ||||
|             updateNotification(DownloadType.IsDownloading) | ||||
|             fileStream.write(buffer, 0, count) | ||||
|         } | ||||
| 
 | ||||
|         // DOWNLOAD EXITED CORRECTLY | ||||
|         updateNotification(DownloadType.IsDone) | ||||
|         fileStream.closeStream() | ||||
|         connectionInputStream.closeStream() | ||||
| 
 | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     public fun DownloadEpisode(context: Context, source: String, ep: ResultEpisode, links: List<ExtractorLink>) { | ||||
|     public fun DownloadEpisode(context: Context, source: String, ep: DownloadEpisodeMetadata, links: List<ExtractorLink>) { | ||||
|         val validLinks = links.filter { !it.isM3u8 } | ||||
|         if (validLinks.isNotEmpty()) { | ||||
|             DownloadSingleEpisode(context, source, ep, validLinks.first()) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -1,97 +0,0 @@ | |||
| package com.lagradost.cloudstream3.utils | ||||
| 
 | ||||
| import android.app.IntentService | ||||
| import android.app.Notification | ||||
| import android.app.PendingIntent | ||||
| import android.content.Intent | ||||
| import androidx.core.app.NotificationCompat | ||||
| import androidx.core.app.NotificationManagerCompat | ||||
| import androidx.core.net.toUri | ||||
| import com.google.android.exoplayer2.offline.Download | ||||
| import com.google.android.exoplayer2.offline.DownloadManager | ||||
| import com.google.android.exoplayer2.offline.DownloadService | ||||
| import com.google.android.exoplayer2.scheduler.PlatformScheduler | ||||
| import com.google.android.exoplayer2.scheduler.Scheduler | ||||
| import com.lagradost.cloudstream3.MainActivity | ||||
| import com.lagradost.cloudstream3.R | ||||
| import com.lagradost.cloudstream3.UIHelper.colorFromAttribute | ||||
| import java.lang.Exception | ||||
| 
 | ||||
| private const val JOB_ID = 1 | ||||
| private const val FOREGROUND_NOTIFICATION_ID = 1 | ||||
| 
 | ||||
| class VideoDownloadService : DownloadService( | ||||
|     FOREGROUND_NOTIFICATION_ID, | ||||
|     DEFAULT_FOREGROUND_NOTIFICATION_UPDATE_INTERVAL, | ||||
|     CHANNEL_ID, | ||||
|     R.string.exo_download_notification_channel_name,  /* channelDescriptionResourceId= */ | ||||
|     0) { | ||||
|     override fun getDownloadManager(): DownloadManager { | ||||
|         val ctx = this | ||||
|         return ExoPlayerHelper.downloadManager.apply { | ||||
|             requirements = DownloadManager.DEFAULT_REQUIREMENTS | ||||
|             maxParallelDownloads = 3 | ||||
|             addListener( | ||||
|                 object : DownloadManager.Listener { | ||||
| 
 | ||||
|                     override fun onDownloadChanged( | ||||
|                         downloadManager: DownloadManager, | ||||
|                         download: Download, | ||||
|                         finalException: Exception?, | ||||
|                     ) { | ||||
|                         val intent = Intent(ctx, MainActivity::class.java).apply { | ||||
|                             flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK | ||||
|                         } | ||||
| 
 | ||||
|                         val pendingIntent: PendingIntent = PendingIntent.getActivity(ctx, 0, intent, 0) | ||||
|                         val builder = NotificationCompat.Builder(ctx, CHANNEL_ID) | ||||
|                             .setAutoCancel(true) | ||||
|                             .setColorized(true) | ||||
|                             .setAutoCancel(true) | ||||
|                             .setOnlyAlertOnce(true) | ||||
|                             .setPriority(NotificationCompat.PRIORITY_DEFAULT) | ||||
|                             .setColor(colorFromAttribute(R.attr.colorPrimary)) | ||||
|                             .setContentText("${download.bytesDownloaded} / ${download.contentLength}") | ||||
|                             .setSmallIcon( | ||||
|                                 VideoDownloadManager.imgDownloading | ||||
|                             ) | ||||
|                             .setProgress((download.bytesDownloaded / 1000).toInt(), | ||||
|                                 (download.contentLength / 1000).toInt(), | ||||
|                                 false) // in case the size is over 2gb / 1000 | ||||
|                             .setContentIntent(pendingIntent) | ||||
|                         builder.build() | ||||
|                         with(NotificationManagerCompat.from(ctx)) { | ||||
|                             // notificationId is a unique int for each notification that you must define | ||||
|                             notify(download.request.id.hashCode(), builder.build()) | ||||
|                         } | ||||
|                         super.onDownloadChanged(downloadManager, download, finalException) | ||||
|                     } | ||||
|                 } | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun getScheduler(): Scheduler = | ||||
|         PlatformScheduler(this, JOB_ID) | ||||
| 
 | ||||
|     override fun getForegroundNotification(downloads: MutableList<Download>): Notification { | ||||
|         val intent = Intent(this, MainActivity::class.java).apply { | ||||
|             flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK | ||||
|         } | ||||
| 
 | ||||
|         val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, 0) | ||||
|         val builder = NotificationCompat.Builder(this, CHANNEL_ID) | ||||
|             .setAutoCancel(true) | ||||
|             .setColorized(true) | ||||
|             .setAutoCancel(true) | ||||
|             .setOnlyAlertOnce(true) | ||||
|             .setPriority(NotificationCompat.PRIORITY_DEFAULT) | ||||
|             .setColor(colorFromAttribute(R.attr.colorPrimary)) | ||||
|             .setContentText("Downloading ${downloads.size} item${if (downloads.size == 1) "" else "s"}") | ||||
|             .setSmallIcon( | ||||
|                 VideoDownloadManager.imgDownloading | ||||
|             ) | ||||
|             .setContentIntent(pendingIntent) | ||||
|         return builder.build() | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue