package com.github.libretube import android.app.DownloadManager import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.app.Service import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.graphics.Color import android.net.Uri import android.os.Build import android.os.Environment import android.os.Environment.DIRECTORY_DOWNLOADS import android.os.IBinder import android.util.Log import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import com.arthenica.ffmpegkit.FFmpegKit import java.io.File var IS_DOWNLOAD_RUNNING = false class DownloadService : Service() { val TAG = "DownloadService" private var downloadId: Long = -1 private lateinit var videoId: String private lateinit var videoUrl: String private lateinit var audioUrl: String private lateinit var extension: String private var duration: Int = 0 // private lateinit var command: String private lateinit var audioDir: File private lateinit var videoDir: File lateinit var service: NotificationManager lateinit var notification: NotificationCompat.Builder override fun onCreate() { super.onCreate() IS_DOWNLOAD_RUNNING = true } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { videoId = intent?.getStringExtra("videoId")!! videoUrl = intent.getStringExtra("videoUrl")!! audioUrl = intent.getStringExtra("audioUrl")!! extension = intent.getStringExtra("extension")!! // command = intent.getStringExtra("command")!! duration = intent.getIntExtra("duration", 1) service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val channelId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val chan = NotificationChannel( "service", "DownloadService", NotificationManager.IMPORTANCE_NONE ) chan.lightColor = Color.BLUE chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE service.createNotificationChannel(chan) "service" } else { // If earlier version channel ID is not used // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) "" } var pendingIntent: PendingIntent? = null pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE) } else { PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT) } // Creating a notification and setting its various attributes notification = NotificationCompat.Builder(this@DownloadService, channelId) .setSmallIcon(R.drawable.ic_download) .setContentTitle("LibreTube") .setContentText("Downloading") .setPriority(NotificationCompat.PRIORITY_LOW) .setOngoing(true) .setOnlyAlertOnce(true) .setProgress(100, 0, true) .setContentIntent(pendingIntent) .setAutoCancel(true) startForeground(1, notification.build()) downloadManager() return super.onStartCommand(intent, flags, startId) } override fun onBind(intent: Intent?): IBinder? { TODO("Not yet implemented") } private fun downloadManager() { val path = applicationContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) val folder_main = ".tmp" val f = File(path, folder_main) if (!f.exists()) { f.mkdirs() Log.e(TAG, "Directory make") } else { f.deleteRecursively() f.mkdirs() Log.e(TAG, "Directory already have") } audioDir = File(f, "$videoId-audio") videoDir = File(f, "$videoId-video") try { Log.e(TAG, "Directory make") registerReceiver( onDownloadComplete, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) ) val request: DownloadManager.Request = DownloadManager.Request(Uri.parse(videoUrl)) .setTitle("Video") // Title of the Download Notification .setDescription("Downloading") // Description of the Download Notification .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE) // Visibility of the download Notification .setDestinationUri(Uri.fromFile(videoDir)) .setAllowedOverMetered(true) // Set if download is allowed on Mobile network .setAllowedOverRoaming(true) // val downloadManager: DownloadManager = applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager downloadId = downloadManager.enqueue(request) if (audioUrl == "") { downloadId = 0L } } catch (e: IllegalArgumentException) { Log.e(TAG, "download error $e") try { downloadId = 0L val request: DownloadManager.Request = DownloadManager.Request(Uri.parse(audioUrl)) .setTitle("Audio") // Title of the Download Notification .setDescription("Downloading") // Description of the Download Notification .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE) // Visibility of the download Notification .setDestinationUri(Uri.fromFile(audioDir)) .setAllowedOverMetered(true) // Set if download is allowed on Mobile network .setAllowedOverRoaming(true) // val downloadManager: DownloadManager = applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager downloadManager.enqueue(request) } catch (e: Exception) { Log.e(TAG, "audio download error $e") stopService(Intent(this, DownloadService::class.java)) } } } private val onDownloadComplete: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { // Fetching the download id received with the broadcast val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) // Checking if the received broadcast is for our enqueued download by matching download id if (downloadId == id) { downloadId = 0L try { val request: DownloadManager.Request = DownloadManager.Request(Uri.parse(audioUrl)) .setTitle("Audio") // Title of the Download Notification .setDescription("Downloading") // Description of the Download Notification .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE) // Visibility of the download Notification .setDestinationUri(Uri.fromFile(audioDir)) .setAllowedOverMetered(true) // Set if download is allowed on Mobile network .setAllowedOverRoaming(true) // val downloadManager: DownloadManager = applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager downloadManager.enqueue(request) } catch (e: Exception) { } } else if (downloadId == 0L) { val libreTube = File( Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS), "LibreTube" ) if (!libreTube.exists()) { libreTube.mkdirs() Log.e(TAG, "libreTube Directory make") } else { Log.e(TAG, "libreTube Directory already have") } var command: String = when { videoUrl == "" -> { "-y -i $audioDir -c copy $libreTube/$videoId-audio$extension" } audioUrl == "" -> { "-y -i $videoDir -c copy $libreTube/$videoId-video$extension" } else -> { "-y -i $videoDir -i $audioDir -c copy $libreTube/${videoId}$extension" } } notification.setContentTitle("Muxing") FFmpegKit.executeAsync( command, { session -> val state = session.state val returnCode = session.returnCode // CALLED WHEN SESSION IS EXECUTED Log.d( TAG, String.format( "FFmpeg process exited with state %s and rc %s.%s", state, returnCode, session.failStackTrace ) ) val path = applicationContext.getExternalFilesDir(DIRECTORY_DOWNLOADS) val folder_main = ".tmp" val f = File(path, folder_main) f.deleteRecursively() if (returnCode.toString() != "0") { var builder = NotificationCompat.Builder(this@DownloadService, "failed") .setSmallIcon(R.drawable.ic_download) .setContentTitle(resources.getString(R.string.downloadfailed)) .setContentText("failure") .setPriority(NotificationCompat.PRIORITY_HIGH) createNotificationChannel() with(NotificationManagerCompat.from(this@DownloadService)) { // notificationId is a unique int for each notification that you must define notify(69, builder.build()) } } stopForeground(true) stopService(Intent(this@DownloadService, DownloadService::class.java)) }, { // CALLED WHEN SESSION PRINTS LOGS Log.e(TAG, it.message.toString()) } ) { // CALLED WHEN SESSION GENERATES STATISTICS Log.e(TAG + "stat", it.time.toString()) /*val progress = it.time/(10*duration!!) if (progress<1){ notification .setProgress(progressMax, progress.toInt(), false) service.notify(1,notification.build()) }*/ } } } } private fun createNotificationChannel() { // Create the NotificationChannel, but only on API 26+ because // the NotificationChannel class is new and not in the support library if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val name = "failed" val descriptionText = "Download Failed" val importance = NotificationManager.IMPORTANCE_DEFAULT val channel = NotificationChannel("failed", name, importance).apply { description = descriptionText } // Register the channel with the system val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.createNotificationChannel(channel) } } override fun onDestroy() { try { unregisterReceiver(onDownloadComplete) } catch (e: Exception) { } IS_DOWNLOAD_RUNNING = false Log.d(TAG, "dl finished!") super.onDestroy() } }