Merge pull request #394 from Bnyro/downloads

Downloads Refactor
This commit is contained in:
Bnyro 2022-06-06 16:53:59 +02:00 committed by GitHub
commit ced24dcda1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 193 additions and 200 deletions

View File

@ -68,7 +68,7 @@ class BackgroundMode {
*/ */
private fun initializePlayerNotification(c: Context) { private fun initializePlayerNotification(c: Context) {
playerNotification = PlayerNotificationManager playerNotification = PlayerNotificationManager
.Builder(c, NOTIFICATION_ID, "background_mode").build() .Builder(c, 1, "background_mode").build()
playerNotification.setPlayer(player) playerNotification.setPlayer(player)
playerNotification.setUsePreviousAction(false) playerNotification.setUsePreviousAction(false)
playerNotification.setUseNextAction(false) playerNotification.setUseNextAction(false)

View File

@ -1,16 +1,12 @@
package com.github.libretube package com.github.libretube
import android.app.DownloadManager import android.app.DownloadManager
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.app.Service import android.app.Service
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.graphics.Color
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Environment import android.os.Environment
@ -33,11 +29,12 @@ class DownloadService : Service() {
private lateinit var extension: String private lateinit var extension: String
private var duration: Int = 0 private var duration: Int = 0
// private lateinit var command: String
private lateinit var audioDir: File private lateinit var audioDir: File
private lateinit var videoDir: File private lateinit var videoDir: File
lateinit var service: NotificationManager private lateinit var notification: NotificationCompat.Builder
lateinit var notification: NotificationCompat.Builder private lateinit var downloadType: String
private lateinit var libretubeDir: File
private lateinit var tempDir: File
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
IS_DOWNLOAD_RUNNING = true IS_DOWNLOAD_RUNNING = true
@ -48,44 +45,17 @@ class DownloadService : Service() {
videoUrl = intent.getStringExtra("videoUrl")!! videoUrl = intent.getStringExtra("videoUrl")!!
audioUrl = intent.getStringExtra("audioUrl")!! audioUrl = intent.getStringExtra("audioUrl")!!
extension = intent.getStringExtra("extension")!! extension = intent.getStringExtra("extension")!!
// command = intent.getStringExtra("command")!!
duration = intent.getIntExtra("duration", 1) duration = intent.getIntExtra("duration", 1)
service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager downloadType = if (audioUrl != "" && videoUrl != "") "mux"
val channelId = else if (audioUrl != "") "audio"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { else if (videoUrl != "") "video"
val chan = NotificationChannel( else "none"
"service", if (downloadType != "none") {
"DownloadService", NotificationManager.IMPORTANCE_NONE downloadNotification(intent)
)
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() downloadManager()
} else {
onDestroy()
}
return super.onStartCommand(intent, flags, startId) return super.onStartCommand(intent, flags, startId)
} }
@ -95,58 +65,51 @@ class DownloadService : Service() {
} }
private fun downloadManager() { private fun downloadManager() {
val path = applicationContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
val folder_main = ".tmp" // create folder for temporary files
val f = File(path, folder_main) tempDir = File(
if (!f.exists()) { applicationContext.getExternalFilesDir(DIRECTORY_DOWNLOADS),
f.mkdirs() ".tmp"
)
if (!tempDir.exists()) {
tempDir.mkdirs()
Log.e(TAG, "Directory make") Log.e(TAG, "Directory make")
} else { } else {
f.deleteRecursively() tempDir.deleteRecursively()
f.mkdirs() tempDir.mkdirs()
Log.e(TAG, "Directory already have") Log.e(TAG, "Directory already have")
} }
audioDir = File(f, "$videoId-audio")
videoDir = File(f, "$videoId-video") // create LibreTube folder in Downloads
libretubeDir = File(
Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS),
"LibreTube"
)
if (!libretubeDir.exists()) libretubeDir.mkdirs()
// start download
try { try {
Log.e(TAG, "Directory make")
registerReceiver( registerReceiver(
onDownloadComplete, onDownloadComplete,
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
) )
val request: DownloadManager.Request = when (downloadType) {
DownloadManager.Request(Uri.parse(videoUrl)) "mux" -> {
.setTitle("Video") // Title of the Download Notification audioDir = File(tempDir, "$videoId-audio")
.setDescription("Downloading") // Description of the Download Notification videoDir = File(tempDir, "$videoId-video")
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE) // Visibility of the download Notification downloadId = downloadManagerRequest("Video", "Downloading", videoUrl, videoDir)
.setDestinationUri(Uri.fromFile(videoDir)) }
.setAllowedOverMetered(true) // Set if download is allowed on Mobile network "video" -> {
.setAllowedOverRoaming(true) // videoDir = File(libretubeDir, "$videoId-video")
val downloadManager: DownloadManager = downloadId = downloadManagerRequest("Video", "Downloading", videoUrl, videoDir)
applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager }
downloadId = downloadManager.enqueue(request) "audio" -> {
if (audioUrl == "") { audioDir = File(libretubeDir, "$videoId-audio")
downloadId = 0L downloadId = downloadManagerRequest("Audio", "Downloading", audioUrl, audioDir)
}
} }
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
Log.e(TAG, "download error $e") 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))
}
} }
} }
@ -156,42 +119,86 @@ class DownloadService : Service() {
val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
// Checking if the received broadcast is for our enqueued download by matching download id // Checking if the received broadcast is for our enqueued download by matching download id
if (downloadId == id) { if (downloadId == id) {
downloadId = 0L if (downloadType == "mux") {
try { downloadManagerRequest("Audio", "Downloading", audioUrl, audioDir)
} else {
downloadSucceededNotification()
onDestroy()
}
} else {
muxDownloadedMedia()
}
}
}
private fun downloadManagerRequest(
title: String,
descriptionText: String,
url: String,
fileDir: File
): Long {
val request: DownloadManager.Request = val request: DownloadManager.Request =
DownloadManager.Request(Uri.parse(audioUrl)) DownloadManager.Request(Uri.parse(url))
.setTitle("Audio") // Title of the Download Notification .setTitle(title) // Title of the Download Notification
.setDescription("Downloading") // Description of the Download Notification .setDescription(descriptionText) // Description of the Download Notification
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE) // Visibility of the download Notification .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE) // Visibility of the download Notification
.setDestinationUri(Uri.fromFile(audioDir)) .setDestinationUri(Uri.fromFile(fileDir))
.setAllowedOverMetered(true) // Set if download is allowed on Mobile network .setAllowedOverMetered(true) // Set if download is allowed on Mobile network
.setAllowedOverRoaming(true) // .setAllowedOverRoaming(true) //
val downloadManager: DownloadManager = val downloadManager: DownloadManager =
applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
downloadManager.enqueue(request) return downloadManager.enqueue(request)
} catch (e: Exception) {
} }
} else if (downloadId == 0L) {
val libreTube = File( private fun downloadNotification(intent: Intent) {
Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS), "LibreTube" var pendingIntent: PendingIntent? = null
) pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (!libreTube.exists()) { PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE)
libreTube.mkdirs()
Log.e(TAG, "libreTube Directory make")
} else { } else {
Log.e(TAG, "libreTube Directory already have") PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT)
} }
var command: String = when { // Creating a notification and setting its various attributes
videoUrl == "" -> { notification =
"-y -i $audioDir -c copy $libreTube/$videoId-audio$extension" NotificationCompat.Builder(this@DownloadService, "download_service")
.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(2, notification.build())
} }
audioUrl == "" -> {
"-y -i $videoDir -c copy $libreTube/$videoId-video$extension" private fun downloadFailedNotification() {
} val builder = NotificationCompat.Builder(this@DownloadService, "download_service")
else -> { .setSmallIcon(R.drawable.ic_download)
"-y -i $videoDir -i $audioDir -c copy $libreTube/${videoId}$extension" .setContentTitle(resources.getString(R.string.downloadfailed))
.setContentText("failure")
.setPriority(NotificationCompat.PRIORITY_HIGH)
with(NotificationManagerCompat.from(this@DownloadService)) {
// notificationId is a unique int for each notification that you must define
notify(3, builder.build())
} }
} }
private fun downloadSucceededNotification() {
Log.i(TAG, "Download succeeded")
val builder = NotificationCompat.Builder(this@DownloadService, "download_service")
.setSmallIcon(R.drawable.ic_download)
.setContentTitle(resources.getString(R.string.success))
.setContentText("success")
.setPriority(NotificationCompat.PRIORITY_HIGH)
with(NotificationManagerCompat.from(this@DownloadService)) {
// notificationId is a unique int for each notification that you must define
notify(4, builder.build())
}
}
private fun muxDownloadedMedia() {
val command = "-y -i $videoDir -i $audioDir -c copy $libretubeDir/${videoId}$extension"
notification.setContentTitle("Muxing") notification.setContentTitle("Muxing")
FFmpegKit.executeAsync( FFmpegKit.executeAsync(
command, command,
@ -208,25 +215,10 @@ class DownloadService : Service() {
session.failStackTrace session.failStackTrace
) )
) )
val path = tempDir.deleteRecursively()
applicationContext.getExternalFilesDir(DIRECTORY_DOWNLOADS) if (returnCode.toString() != "0") downloadFailedNotification()
val folder_main = ".tmp" else downloadSucceededNotification()
val f = File(path, folder_main) onDestroy()
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 // CALLED WHEN SESSION PRINTS LOGS
Log.e(TAG, it.message.toString()) Log.e(TAG, it.message.toString())
@ -242,33 +234,16 @@ class DownloadService : Service() {
}*/ }*/
} }
} }
}
}
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() { override fun onDestroy() {
try { try {
unregisterReceiver(onDownloadComplete) unregisterReceiver(onDownloadComplete)
} catch (e: Exception) { } catch (e: Exception) { }
}
IS_DOWNLOAD_RUNNING = false IS_DOWNLOAD_RUNNING = false
Log.d(TAG, "dl finished!") Log.d(TAG, "dl finished!")
stopForeground(true)
stopService(Intent(this@DownloadService, DownloadService::class.java))
super.onDestroy() super.onDestroy()
} }
} }

View File

@ -5,8 +5,6 @@ import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.os.Build import android.os.Build
const val NOTIFICATION_ID = 1
class MyApp : Application() { class MyApp : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -15,19 +13,37 @@ class MyApp : Application() {
} }
/** /**
* Initializes the required [NotificationChannel] for the app. * Initializes the required [NotificationChannel]s for the app.
*/ */
private fun initializeNotificationChannels() { private fun initializeNotificationChannels() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { createNotificationChannel(
// Create the NotificationChannel "download_service",
val name = "Background Mode" "Download Service",
val descriptionText = "Shows a notification with buttons to control the audio player" "DownloadService",
val importance = NotificationManager.IMPORTANCE_LOW NotificationManager.IMPORTANCE_NONE
val mChannel = NotificationChannel("background_mode", name, importance) )
mChannel.description = descriptionText createNotificationChannel(
"background_mode",
"Background Mode",
"Shows a notification with buttons to control the audio player",
NotificationManager.IMPORTANCE_LOW
)
}
private fun createNotificationChannel(
id: String,
name: String,
descriptionText: String,
importance: Int
) {
// 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 channel = NotificationChannel(id, name, importance)
channel.description = descriptionText
// Register the channel in the system
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(mChannel) notificationManager.createNotificationChannel(channel)
} }
} }

View File

@ -35,7 +35,7 @@ class DownloadDialog : DialogFragment() {
var audioUrl = arrayListOf<String>() var audioUrl = arrayListOf<String>()
var selectedVideo = 0 var selectedVideo = 0
var selectedAudio = 0 var selectedAudio = 0
var extension = ".mkv" var extension = ".mp4"
var duration = 0 var duration = 0
private lateinit var videoId: String private lateinit var videoId: String
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

View File

@ -42,7 +42,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.github.libretube.IS_DOWNLOAD_RUNNING import com.github.libretube.IS_DOWNLOAD_RUNNING
import com.github.libretube.MainActivity import com.github.libretube.MainActivity
import com.github.libretube.NOTIFICATION_ID
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.SponsorBlockSettings import com.github.libretube.SponsorBlockSettings
import com.github.libretube.adapters.CommentsAdapter import com.github.libretube.adapters.CommentsAdapter
@ -339,7 +338,7 @@ class PlayerFragment : Fragment() {
val notificationManager = context?.getSystemService( val notificationManager = context?.getSystemService(
Context.NOTIFICATION_SERVICE Context.NOTIFICATION_SERVICE
) as NotificationManager ) as NotificationManager
notificationManager.cancel(NOTIFICATION_ID) notificationManager.cancel(1)
exoPlayer.release() exoPlayer.release()
} catch (e: Exception) { } catch (e: Exception) {
} }
@ -812,7 +811,7 @@ class PlayerFragment : Fragment() {
mediaSessionConnector.setPlayer(exoPlayer) mediaSessionConnector.setPlayer(exoPlayer)
playerNotification = PlayerNotificationManager playerNotification = PlayerNotificationManager
.Builder(c, NOTIFICATION_ID, "background_mode") .Builder(c, 1, "background_mode")
.build() .build()
playerNotification.apply { playerNotification.apply {

View File

@ -30,18 +30,21 @@
android:id="@+id/radioGp" android:id="@+id/radioGp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="8dp"> android:orientation="horizontal"
android:layout_margin="8dp"
android:visibility="gone" >
<RadioButton <RadioButton
android:id="@+id/mkv" android:id="@+id/mkv"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text=".mkv" android:text=".mkv"
android:layout_marginRight="16dp"
android:checked="true" /> android:checked="true" />
<RadioButton <RadioButton
android:id="@+id/mp4" android:id="@+id/mp4"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text=".mp4" /> android:text=".mp4" />
</RadioGroup> </RadioGroup>