download dialog

This commit is contained in:
rimthekid 2022-03-04 19:57:10 +04:00
parent 7159eb0472
commit f8a0c949f9
7 changed files with 269 additions and 80 deletions

View File

@ -25,13 +25,13 @@
"filters": [ "filters": [
{ {
"filterType": "ABI", "filterType": "ABI",
"value": "x86" "value": "armeabi-v7a"
} }
], ],
"attributes": [], "attributes": [],
"versionCode": 4, "versionCode": 4,
"versionName": "0.2.2", "versionName": "0.2.2",
"outputFile": "app-x86-release.apk" "outputFile": "app-armeabi-v7a-release.apk"
}, },
{ {
"type": "ONE_OF_MANY", "type": "ONE_OF_MANY",
@ -51,13 +51,13 @@
"filters": [ "filters": [
{ {
"filterType": "ABI", "filterType": "ABI",
"value": "armeabi-v7a" "value": "x86"
} }
], ],
"attributes": [], "attributes": [],
"versionCode": 4, "versionCode": 4,
"versionName": "0.2.2", "versionName": "0.2.2",
"outputFile": "app-armeabi-v7a-release.apk" "outputFile": "app-x86-release.apk"
} }
], ],
"elementType": "File" "elementType": "File"

View File

@ -0,0 +1,96 @@
package com.github.libretube
import android.app.Dialog
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
class DownloadDialog : DialogFragment() {
private val TAG = "DownloadDialog"
var vidName = arrayListOf<String>()
var vidUrl = arrayListOf<String>()
var audioName = arrayListOf<String>()
var audioUrl = arrayListOf<String>()
var selectedVideo = 0
var selectedAudio = 0
var extension = ".mkv"
var duration = 0
private lateinit var videoId: String
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return activity?.let {
vidName = arguments?.getStringArrayList("videoName") as ArrayList<String>
vidUrl = arguments?.getStringArrayList("videoUrl") as ArrayList<String>
audioName = arguments?.getStringArrayList("audioName") as ArrayList<String>
audioUrl = arguments?.getStringArrayList("audioUrl") as ArrayList<String>
duration = arguments?.getInt("duration")!!
videoId = arguments?.getString("videoId")!!
val builder = AlertDialog.Builder(it)
// Get the layout inflater
val inflater = requireActivity().layoutInflater
var view: View = inflater.inflate(R.layout.dialog_download, null)
val videoSpinner = view.findViewById<Spinner>(R.id.video_spinner)
val videoArrayAdapter =ArrayAdapter<String>(requireContext(),android.R.layout.simple_spinner_item,vidName)
videoArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
videoSpinner.adapter=videoArrayAdapter
videoSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>,
view: View,
position: Int,
id: Long
) {
selectedVideo = position
Log.d(TAG,selectedVideo.toString())
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
val audioSpinner = view.findViewById<Spinner>(R.id.audio_spinner)
val audioArrayAdapter = ArrayAdapter<String>(requireContext(),android.R.layout.simple_spinner_item,audioName)
audioArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
audioSpinner.adapter = audioArrayAdapter
audioSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>,
view: View,
position: Int,
id: Long
) {
selectedAudio = position
Log.d(TAG,selectedAudio.toString())
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
val radioGroup = view.findViewById<RadioGroup>(R.id.radioGp)
radioGroup.setOnCheckedChangeListener { group, checkedId ->
val radio: RadioButton = view.findViewById(checkedId)
extension = radio.text.toString()
Log.d(TAG,extension)
}
view.findViewById<Button>(R.id.download).setOnClickListener {
val intent = Intent(context,DownloadService::class.java)
intent.putExtra("videoId",videoId)
intent.putExtra("videoUrl",vidUrl[selectedVideo])
intent.putExtra("audioUrl",audioUrl[selectedAudio])
intent.putExtra("duration",duration)
intent.putExtra("extension",extension)
//intent.putExtra("command","-y -i ${response.videoStreams[which].url} -i ${response.audioStreams!![0].url} -c copy ${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/${videoId}.mkv")
context?.startService(intent)
dismiss()
}
builder.setView(view)
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
override fun onDestroy() {
vidName.clear()
vidUrl.clear()
audioUrl.clear()
audioName.clear()
super.onDestroy()
}
}

View File

@ -12,25 +12,35 @@ import android.os.Environment
import android.os.IBinder import android.os.IBinder
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.arthenica.ffmpegkit.FFmpegKit import com.arthenica.ffmpegkit.FFmpegKit
import java.io.File import java.io.File
import java.lang.Exception
var IS_DOWNLOAD_RUNNING = false
class DownloadService : Service(){ class DownloadService : Service(){
val TAG = "DownloadService" val TAG = "DownloadService"
private var downloadId: Long =0
private var downloadId: Long =-1
private lateinit var videoId: String private lateinit var videoId: String
private lateinit var videoUrl: String private lateinit var videoUrl: String
private lateinit var audioUrl: String private lateinit var audioUrl: String
private lateinit var extension: String
private var duration: Int = 0 private var duration: Int = 0
//private lateinit var command: String //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
override fun onCreate() {
super.onCreate()
IS_DOWNLOAD_RUNNING = true
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
videoId = intent?.getStringExtra("videoId")!! videoId = intent?.getStringExtra("videoId")!!
videoUrl = intent.getStringExtra("videoUrl")!! videoUrl = intent.getStringExtra("videoUrl")!!
audioUrl = intent.getStringExtra("audioUrl")!! audioUrl = intent.getStringExtra("audioUrl")!!
extension = intent.getStringExtra("extension")!!
//command = intent.getStringExtra("command")!! //command = intent.getStringExtra("command")!!
duration = intent.getIntExtra("duration",1) duration = intent.getIntExtra("duration",1)
downloadManager() downloadManager()
@ -49,12 +59,15 @@ class DownloadService : Service(){
f.mkdirs() f.mkdirs()
Log.e(TAG, "Directory make") Log.e(TAG, "Directory make")
} else { } else {
f.deleteRecursively()
f.mkdirs()
Log.e(TAG, "Directory already have") Log.e(TAG, "Directory already have")
} }
audioDir = File(f, "$videoId-audio") audioDir = File(f, "$videoId-audio")
videoDir = File(f, "$videoId-video") videoDir = File(f, "$videoId-video")
try { try {
Log.e(TAG, "Directory make") Log.e(TAG, "Directory make")
registerReceiver(onDownloadComplete, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
val request: DownloadManager.Request = val request: DownloadManager.Request =
DownloadManager.Request(Uri.parse(videoUrl)) DownloadManager.Request(Uri.parse(videoUrl))
.setTitle("Video") // Title of the Download Notification .setTitle("Video") // Title of the Download Notification
@ -66,22 +79,11 @@ class DownloadService : Service(){
val downloadManager: DownloadManager = val downloadManager: DownloadManager =
applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
downloadId = downloadManager.enqueue(request) downloadId = downloadManager.enqueue(request)
if(audioUrl=="") downloadId = 0L
registerReceiver(onDownloadComplete, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
Log.e(TAG, "download error $e") Log.e(TAG, "download error $e")
} try{
} downloadId = 0L
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) {
Toast.makeText(this@DownloadService, "Download Completed", Toast.LENGTH_SHORT)
.show()
downloadId=0
val request: DownloadManager.Request = val request: DownloadManager.Request =
DownloadManager.Request(Uri.parse(audioUrl)) DownloadManager.Request(Uri.parse(audioUrl))
.setTitle("Audio") // Title of the Download Notification .setTitle("Audio") // Title of the Download Notification
@ -94,8 +96,35 @@ class DownloadService : Service(){
applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager
downloadManager.enqueue(request) 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){ }else if (downloadId == 0L){
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager /*val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channelId = val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val chan = NotificationChannel("service", val chan = NotificationChannel("service",
@ -109,11 +138,10 @@ class DownloadService : Service(){
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
"" ""
} }
//Toast.makeText(this,command, Toast.LENGTH_SHORT).show()
val pendingIntent: PendingIntent = PendingIntent.getActivity( val pendingIntent: PendingIntent = PendingIntent.getActivity(
this@DownloadService, 0, intent, 0) this@DownloadService, 0, intent, 0)*/
//Sets the maximum progress as 100 //Sets the maximum progress as 100
val progressMax = 100 /*val progressMax = 100
//Creating a notification and setting its various attributes //Creating a notification and setting its various attributes
val notification = val notification =
NotificationCompat.Builder(this@DownloadService, channelId) NotificationCompat.Builder(this@DownloadService, channelId)
@ -125,9 +153,26 @@ class DownloadService : Service(){
.setOnlyAlertOnce(true) .setOnlyAlertOnce(true)
.setProgress(progressMax, 0, true) .setProgress(progressMax, 0, true)
.setContentIntent(pendingIntent) .setContentIntent(pendingIntent)
.setAutoCancel(true) .setAutoCancel(true)*/
val libreTube = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),"LibreTube")
FFmpegKit.executeAsync("-y -i $videoDir -i $audioDir -c copy ${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/${videoId}.mkv", 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"
}
}
FFmpegKit.executeAsync(command,
{ session -> { session ->
val state = session.state val state = session.state
val returnCode = session.returnCode val returnCode = session.returnCode
@ -146,27 +191,33 @@ class DownloadService : Service(){
val f = File(path, folder_main) val f = File(path, folder_main)
f.deleteRecursively() f.deleteRecursively()
stopForeground(true) stopForeground(true)
//Toast.makeText(this@DownloadService, R.string.dlcomplete, Toast.LENGTH_LONG).show()
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())
}) { }) {
// CALLED WHEN SESSION GENERATES STATISTICS // CALLED WHEN SESSION GENERATES STATISTICS
Log.e(TAG+"stat",it.time.toString()) Log.e(TAG+"stat",it.time.toString())
val progress = it.time/(10*duration!!) /*val progress = it.time/(10*duration!!)
if (progress<1){ if (progress<1){
notification notification
.setProgress(progressMax, progress.toInt(), false) .setProgress(progressMax, progress.toInt(), false)
service.notify(1,notification.build()) service.notify(1,notification.build())
} }*/
} }
startForeground(1,notification.build()) //startForeground(1,notification.build())
} }
} }
} }
override fun onDestroy() { override fun onDestroy() {
unregisterReceiver(onDownloadComplete) try {
unregisterReceiver(onDownloadComplete)
}catch (e: Exception){}
IS_DOWNLOAD_RUNNING = false
Log.d(TAG,"dl finished!")
super.onDestroy() super.onDestroy()
} }

View File

@ -6,7 +6,6 @@ import android.app.Activity
import android.app.ActivityManager import android.app.ActivityManager
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
@ -366,8 +365,10 @@ class PlayerFragment : Fragment() {
} }
//check if livestream //check if livestream
if (response.duration!!>0){ if (response.duration!!>0){
//download clicked //download clicked
relDownloadVideo.setOnClickListener { relDownloadVideo.setOnClickListener {
if(!IS_DOWNLOAD_RUNNING){
val mainActivity = activity as MainActivity val mainActivity = activity as MainActivity
Log.e(TAG,"download button clicked!") Log.e(TAG,"download button clicked!")
if (SDK_INT >= Build.VERSION_CODES.R) { if (SDK_INT >= Build.VERSION_CODES.R) {
@ -399,45 +400,39 @@ class PlayerFragment : Fragment() {
) )
} }
} }
val builderr: AlertDialog.Builder? = activity?.let { var vidName = arrayListOf<String>()
AlertDialog.Builder(it) vidName.add("No video")
var vidUrl = arrayListOf<String>()
vidUrl.add("")
for (vid in response.videoStreams!!){
val name = vid.quality +" "+ vid.format
vidName.add(name)
vidUrl.add(vid.url!!)
}
var audioName = arrayListOf<String>()
audioName.add("No audio")
var audioUrl = arrayListOf<String>()
audioUrl.add("")
for (audio in response.audioStreams!!){
val name = audio.quality +" "+ audio.format
audioName.add(name)
audioUrl.add(audio.url!!)
}
val newFragment = DownloadDialog()
var bundle = Bundle()
bundle.putStringArrayList("videoName",vidName)
bundle.putStringArrayList("videoUrl",vidUrl)
bundle.putStringArrayList("audioName",audioName)
bundle.putStringArrayList("audioUrl",audioUrl)
bundle.putString("videoId",videoId)
bundle.putInt("duration",response.duration)
newFragment.arguments = bundle
newFragment.show(childFragmentManager, "Download")
}else{
Toast.makeText(context, R.string.dlisinprogress, Toast.LENGTH_SHORT)
.show()
}
} }
var videos = videosNameArray.drop(1).toTypedArray()
builderr!!.setTitle(R.string.choose_quality_dialog)
.setItems(videos,
DialogInterface.OnClickListener { _, which ->
val intent = Intent(context,DownloadService::class.java)
intent.putExtra("videoId",videoId)
intent.putExtra("videoUrl",response.videoStreams[which].url)
intent.putExtra("audioUrl",response.audioStreams!![0].url)
intent.putExtra("duration",response.duration)
//intent.putExtra("command","-y -i ${response.videoStreams[which].url} -i ${response.audioStreams!![0].url} -c copy ${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/${videoId}.mkv")
context?.startService(intent)
/*FFmpegKit.executeAsync("-y -i ${response.videoStreams[which].url} -i ${response.audioStreams!![0].url} -c copy ${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/${videoId}.mkv",
{ 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
)
)
}, {
// CALLED WHEN SESSION PRINTS LOGS
Log.e(TAG,it.message.toString())
}) {
// CALLED WHEN SESSION GENERATES STATISTICS
Log.e(TAG,it.time.toString())
}*/
})
val dialog: AlertDialog? = builderr?.create()
dialog?.show()
}
}else{ }else{
Toast.makeText(context,R.string.cannotDownload, Toast.LENGTH_SHORT).show() Toast.makeText(context,R.string.cannotDownload, Toast.LENGTH_SHORT).show()
} }
@ -449,15 +444,6 @@ class PlayerFragment : Fragment() {
} }
/* private fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager?
for (service in manager!!.getRunningServices(Int.MAX_VALUE)) {
if (serviceClass.name == service.service.className) {
return true
}
}
return false
}*/
private fun isSubscribed(button: MaterialButton, channel_id: String){ private fun isSubscribed(button: MaterialButton, channel_id: String){
@SuppressLint("ResourceAsColor") @SuppressLint("ResourceAsColor")
fun run() { fun run() {

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageView
android:src="@drawable/ic_libretube_foreground"
android:layout_width="match_parent"
android:layout_height="64dp"
android:scaleType="center"
android:background="#CD5757"
android:contentDescription="@string/app_name" />
<Spinner
android:id="@+id/video_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
/>
<Spinner
android:id="@+id/audio_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"/>
<RadioGroup
android:id="@+id/radioGp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<RadioButton
android:id="@+id/mkv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=".mkv"
android:checked="true"/>
<RadioButton
android:id="@+id/mp4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=".mp4"/>
</RadioGroup>
<Button
android:id="@+id/download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/download"
android:padding="8dp"
android:layout_margin="8dp"
android:layout_gravity="center"/>
</LinearLayout>

View File

@ -104,7 +104,8 @@
android:id="@+id/relPlayer_download" android:id="@+id/relPlayer_download"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1"> android:layout_weight="1"
android:background="?android:attr/selectableItemBackground">
<ImageView <ImageView
android:id="@+id/player_download" android:id="@+id/player_download"

View File

@ -24,4 +24,6 @@
<string name="please_login">Please Login or Register from the settings to show your Subscriptions!</string> <string name="please_login">Please Login or Register from the settings to show your Subscriptions!</string>
<string name="subscribeIsEmpty">Subscribe to some channels first!</string> <string name="subscribeIsEmpty">Subscribe to some channels first!</string>
<string name="cannotDownload">Can\'t Download this stream!</string> <string name="cannotDownload">Can\'t Download this stream!</string>
<string name="dlcomplete">Download is completed!</string>
<string name="dlisinprogress">Another Download is already in progress please wait till it\'s finished!</string>
</resources> </resources>