FIXES
1.The videos are not visible on the home screen, but they are visible on the same server in libretube. 2.Open download card late on YouTube. 3.When you enter the end time or a higher value there and confirm, the application is closed and the error.. 4.The home page player and cut player do not open. When the cut player opens, the video often stops 5.The cutting player does not do its work exactly.
This commit is contained in:
parent
8a42b3f515
commit
444f0cc582
18 changed files with 185 additions and 74 deletions
|
|
@ -10,7 +10,7 @@ def properties = new Properties()
|
|||
def versionMajor = 1
|
||||
def versionMinor = 6
|
||||
def versionPatch = 3
|
||||
def versionBuild = 15 // bump for dogfood builds, public betas, etc.
|
||||
def versionBuild = 17 // bump for dogfood builds, public betas, etc.
|
||||
def versionExt = ""
|
||||
|
||||
if (versionBuild > 0){
|
||||
|
|
|
|||
|
|
@ -52,7 +52,10 @@ import kotlinx.coroutines.runBlocking
|
|||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextInt
|
||||
|
||||
|
||||
class DownloadViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
|
@ -149,7 +152,13 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
}
|
||||
|
||||
suspend fun updateDownload(item: DownloadItem){
|
||||
repository.update(item)
|
||||
if (sharedPreferences.getBoolean("incognito", false)){
|
||||
if (item.status == DownloadRepository.Status.Cancelled.toString() || item.status == DownloadRepository.Status.Error.toString()){
|
||||
repository.delete(item)
|
||||
}
|
||||
}else{
|
||||
repository.update(item)
|
||||
}
|
||||
}
|
||||
|
||||
fun getItemByID(id: Long) : DownloadItem {
|
||||
|
|
@ -485,6 +494,8 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
if (it.status != DownloadRepository.Status.Paused.toString()) it.status = DownloadRepository.Status.Queued.toString()
|
||||
if (activeAndQueuedDownloads.firstOrNull{d ->
|
||||
d.id = 0
|
||||
d.logID = null
|
||||
d.customFileNameTemplate = it.customFileNameTemplate
|
||||
d.status = DownloadRepository.Status.Queued.toString()
|
||||
d.toString() == it.toString()
|
||||
} != null) {
|
||||
|
|
@ -506,6 +517,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
Toast.makeText(context, context.getString(R.string.download_already_exists), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
val workManager = WorkManager.getInstance(context)
|
||||
|
||||
queuedItems.forEach {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
var delay = if (it.downloadStartTime != 0L){
|
||||
|
|
@ -518,19 +532,20 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
|
||||
val workRequest = OneTimeWorkRequestBuilder<DownloadWorker>()
|
||||
.setInputData(Data.Builder().putLong("id", it.id).build())
|
||||
.addTag(it.id.toString())
|
||||
.addTag("download")
|
||||
.setConstraints(workConstraints.build())
|
||||
.setInitialDelay(delay, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
WorkManager.getInstance(context).beginUniqueWork(
|
||||
it.id.toString(),
|
||||
ExistingWorkPolicy.KEEP,
|
||||
workManager.enqueueUniqueWork(
|
||||
Random.nextInt(1000000000).toString(),
|
||||
ExistingWorkPolicy.REPLACE,
|
||||
workRequest
|
||||
).enqueue()
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val isCurrentNetworkMetered = (context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).isActiveNetworkMetered
|
||||
if (!allowMeteredNetworks && isCurrentNetworkMetered){
|
||||
Looper.prepare().run {
|
||||
|
|
|
|||
|
|
@ -17,15 +17,17 @@ class CancelDownloadNotificationReceiver : BroadcastReceiver() {
|
|||
val message = intent.getStringExtra("cancel")
|
||||
val id = intent.getIntExtra("workID", 0)
|
||||
if (message != null) {
|
||||
val notificationUtil = NotificationUtil(c)
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
runCatching {
|
||||
val notificationUtil = NotificationUtil(c)
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
|
||||
val dbManager = DBManager.getInstance(c)
|
||||
CoroutineScope(Dispatchers.IO).launch{
|
||||
val item = dbManager.downloadDao.getDownloadById(id.toLong())
|
||||
item.status = DownloadRepository.Status.Cancelled.toString()
|
||||
dbManager.downloadDao.update(item)
|
||||
val dbManager = DBManager.getInstance(c)
|
||||
CoroutineScope(Dispatchers.IO).launch{
|
||||
val item = dbManager.downloadDao.getDownloadById(id.toLong())
|
||||
item.status = DownloadRepository.Status.Cancelled.toString()
|
||||
dbManager.downloadDao.update(item)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,13 @@ class PauseDownloadNotificationReceiver : BroadcastReceiver() {
|
|||
override fun onReceive(c: Context, intent: Intent) {
|
||||
val id = intent.getIntExtra("workID", 0)
|
||||
if (id != 0) {
|
||||
val title = intent.getStringExtra("title")
|
||||
val notificationUtil = NotificationUtil(c)
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
notificationUtil.createResumeDownload(id, title, NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||
runCatching {
|
||||
val title = intent.getStringExtra("title")
|
||||
val notificationUtil = NotificationUtil(c)
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
notificationUtil.createResumeDownload(id, title, NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import android.content.Context
|
|||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
|
|
@ -26,10 +27,14 @@ import com.deniscerri.ytdlnis.util.UiUtil
|
|||
import com.google.android.material.bottomappbar.BottomAppBar
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.neo.highlight.core.Highlight
|
||||
import com.neo.highlight.util.listener.HighlightTextWatcher
|
||||
import com.neo.highlight.util.scheme.ColorScheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
class AddExtraCommandsDialog(private val item: DownloadItem, private val callback: ExtraCommandsListener) : BottomSheetDialogFragment() {
|
||||
|
|
@ -81,11 +86,32 @@ class AddExtraCommandsDialog(private val item: DownloadItem, private val callbac
|
|||
val text = view.findViewById<EditText>(R.id.command)
|
||||
val templates = view.findViewById<Button>(R.id.commands)
|
||||
val shortcuts = view.findViewById<Button>(R.id.shortcuts)
|
||||
val currentCommand = infoUtil.buildYoutubeDLRequest(item).buildCommand().joinToString(" ")
|
||||
view.findViewById<TextView>(R.id.currentText)?.text = currentCommand
|
||||
val currentCommand = infoUtil.parseYTDLRequestString(infoUtil.buildYoutubeDLRequest(item))
|
||||
val currentText = view.findViewById<TextView>(R.id.currentText)
|
||||
currentText?.text = currentCommand
|
||||
|
||||
|
||||
//init syntax highlighter
|
||||
val highlight = Highlight()
|
||||
val highlightWatcher = HighlightTextWatcher()
|
||||
|
||||
val schemes = listOf(
|
||||
ColorScheme(Pattern.compile("([\"'])(?:\\\\1|.)*?\\1"), Color.parseColor("#FC8500")),
|
||||
ColorScheme(Pattern.compile("yt-dlp"), Color.parseColor("#00FF00")),
|
||||
ColorScheme(Pattern.compile("(https?://(?:www\\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|www\\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|https?://(?:www\\.|(?!www))[a-zA-Z0-9]+\\.[^\\s]{2,}|www\\.[a-zA-Z0-9]+\\.[^\\s]{2,})"), Color.parseColor("#b5942f")),
|
||||
ColorScheme(Pattern.compile("\\d+(\\.\\d)?%"), Color.parseColor("#43a564"))
|
||||
)
|
||||
|
||||
highlight.addScheme(
|
||||
*schemes.map { it }.toTypedArray()
|
||||
)
|
||||
highlightWatcher.addScheme(
|
||||
*schemes.map { it }.toTypedArray()
|
||||
)
|
||||
highlight.setSpan(currentText)
|
||||
currentText.addTextChangedListener(highlightWatcher)
|
||||
|
||||
text?.setText(item.extraCommands)
|
||||
|
||||
val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
text!!.postDelayed({
|
||||
text.setSelection(text.length())
|
||||
|
|
|
|||
|
|
@ -8,28 +8,21 @@ import android.graphics.Color
|
|||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Range
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.children
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.media3.common.AudioAttributes
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.MediaItem.fromUri
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.datasource.DefaultDataSource
|
||||
import androidx.media3.datasource.cronet.CronetDataSource
|
||||
import androidx.media3.exoplayer.DefaultLoadControl
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||
import androidx.media3.exoplayer.source.MediaSource
|
||||
import androidx.media3.exoplayer.source.MergingMediaSource
|
||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||
import androidx.media3.ui.PlayerView
|
||||
import com.deniscerri.ytdlnis.App
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.ChapterItem
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
|
|
@ -54,14 +47,12 @@ import kotlinx.coroutines.flow.flow
|
|||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.chromium.net.CronetEngine
|
||||
import java.lang.reflect.Type
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
||||
class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls : String?, private var chapters: List<ChapterItem>?, private val listener: VideoCutListener) : BottomSheetDialogFragment() {
|
||||
class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls : String?, private var chapters: List<ChapterItem>?, private val listener: VideoCutListener) : BottomSheetDialogFragment() {
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
private lateinit var player: ExoPlayer
|
||||
|
|
@ -279,7 +270,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls
|
|||
toTextInput.editText!!.setTextAndRecalculateWidth(endTimestampString)
|
||||
|
||||
|
||||
okBtn.isEnabled = !(values[0] == 0F && values[1] == 100F)
|
||||
okBtn.isEnabled = values[0] != 0F && values[1] != 100F
|
||||
|
||||
try {
|
||||
player.seekTo((startTimestamp * 1000).toLong())
|
||||
|
|
@ -294,26 +285,29 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls
|
|||
if ((event!!.action == KeyEvent.ACTION_DOWN) &&
|
||||
(keyCode == KeyEvent.KEYCODE_ENTER)) {
|
||||
|
||||
val startTimestamp = (rangeSlider.valueFrom.toInt() * timeSeconds) / 100
|
||||
var startTimestamp = (rangeSlider.valueFrom.toInt() * timeSeconds) / 100
|
||||
val endTimestamp = (rangeSlider.valueTo.toInt() * timeSeconds) / 100
|
||||
|
||||
fromTextInput.editText!!.clearFocus()
|
||||
val seconds = convertStringToTimestamp(fromTextInput.editText!!.text.toString())
|
||||
var seconds = convertStringToTimestamp(fromTextInput.editText!!.text.toString())
|
||||
val endSeconds = convertStringToTimestamp(toTextInput.editText!!.text.toString())
|
||||
|
||||
val startValue = (seconds.toFloat() / endTimestamp) * 100
|
||||
var startValue = (seconds.toFloat() / endTimestamp) * 100
|
||||
val endValue = (endSeconds.toFloat() / endTimestamp) * 100
|
||||
|
||||
if (seconds == 0) {
|
||||
fromTextInput.editText!!.setTextAndRecalculateWidth(infoUtil.formatIntegerDuration(startTimestamp, Locale.US))
|
||||
}else if (startValue > 100){
|
||||
startTimestamp = 0
|
||||
seconds = 0
|
||||
fromTextInput.editText!!.setTextAndRecalculateWidth(infoUtil.formatIntegerDuration(startTimestamp, Locale.US))
|
||||
startValue = 0F
|
||||
}
|
||||
|
||||
rangeSlider.setValues(startValue, endValue)
|
||||
okBtn.isEnabled = !(startValue == 0F && endValue == 100F)
|
||||
okBtn.isEnabled = startValue != 0F && endValue != 100F
|
||||
try {
|
||||
player.seekTo((((startValue * timeSeconds) / 100) * 1000).toLong())
|
||||
player.seekTo(seconds.toLong() * 1000)
|
||||
player.play()
|
||||
}catch (ignored: Exception) {}
|
||||
|
||||
|
|
@ -331,14 +325,19 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls
|
|||
(keyCode == KeyEvent.KEYCODE_ENTER)) {
|
||||
|
||||
val values = rangeSlider.values
|
||||
val endTimestamp = (rangeSlider.valueTo.toInt() * timeSeconds) / 100
|
||||
var endTimestamp = (rangeSlider.valueTo.toInt() * timeSeconds) / 100
|
||||
|
||||
toTextInput.editText!!.clearFocus()
|
||||
val startSeconds = convertStringToTimestamp(fromTextInput.editText!!.text.toString())
|
||||
val seconds = convertStringToTimestamp(toTextInput.editText!!.text.toString())
|
||||
|
||||
val startValue = (startSeconds.toFloat() / endTimestamp) * 100
|
||||
val endValue = (seconds.toFloat() / endTimestamp) * 100
|
||||
var endValue = (seconds.toFloat() / endTimestamp) * 100
|
||||
if (endValue > 100F){
|
||||
endTimestamp = timeSeconds
|
||||
toTextInput.editText!!.setTextAndRecalculateWidth(infoUtil.formatIntegerDuration(endTimestamp, Locale.US))
|
||||
endValue = 100F
|
||||
}
|
||||
|
||||
if (seconds == 0) {
|
||||
toTextInput.editText!!.setTextAndRecalculateWidth(infoUtil.formatIntegerDuration(endTimestamp, Locale.US))
|
||||
|
|
@ -347,9 +346,9 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls
|
|||
}
|
||||
|
||||
rangeSlider.setValues(startValue, endValue)
|
||||
okBtn.isEnabled = !(startValue == 0F && endValue == 100F)
|
||||
okBtn.isEnabled = startValue != 0F && endValue != 100F
|
||||
try {
|
||||
player.seekTo((((startValue * timeSeconds) / 100) * 1000).toLong())
|
||||
player.seekTo(startSeconds.toLong() * 1000)
|
||||
player.play()
|
||||
}catch (ignored: Exception) {}
|
||||
|
||||
|
|
@ -543,10 +542,8 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls
|
|||
|
||||
private fun videoProgress(player: ExoPlayer?) = flow {
|
||||
while (true) {
|
||||
runCatching {
|
||||
emit((player!!.currentPosition / 1000).toInt())
|
||||
delay(1000)
|
||||
}
|
||||
emit((player!!.currentPosition / 1000).toInt())
|
||||
delay(1000)
|
||||
}
|
||||
}.flowOn(Dispatchers.Main)
|
||||
|
||||
|
|
@ -587,4 +584,4 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls
|
|||
|
||||
interface VideoCutListener{
|
||||
fun onChangeCut(list: List<String>)
|
||||
}
|
||||
}
|
||||
|
|
@ -182,7 +182,11 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
}
|
||||
items.forEachIndexed { index, i ->
|
||||
i.allFormats.clear()
|
||||
if (formatCollection.isNotEmpty() && formatCollection[index].isNotEmpty()) i.allFormats.addAll(formatCollection[index])
|
||||
if (formatCollection.size == items.size && formatCollection[index].isNotEmpty()) {
|
||||
runCatching {
|
||||
i.allFormats.addAll(formatCollection[index])
|
||||
}
|
||||
}
|
||||
i.format = selectedFormats[index].format
|
||||
if (i.type == DownloadViewModel.Type.video) selectedFormats[index].audioFormats?.map { it.format_id }?.let { i.videoPreferences.audioFormatIDs.addAll(it) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
|
||||
private lateinit var activeDownloads: ActiveDownloadMinifiedAdapter
|
||||
private lateinit var queuedDownloads: GenericDownloadAdapter
|
||||
private var activeCount: Int = 0
|
||||
|
||||
private lateinit var queuedItems : List<DownloadItem>
|
||||
private lateinit var activeItems : List<DownloadItem>
|
||||
|
|
@ -197,6 +198,10 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
queuedDownloads.submitList(it)
|
||||
}
|
||||
|
||||
downloadViewModel.activeDownloadsCount.observe(viewLifecycleOwner){
|
||||
activeCount = it
|
||||
}
|
||||
|
||||
|
||||
bottomSheetLink.text = item.url
|
||||
bottomSheetLink.setOnClickListener{
|
||||
|
|
@ -448,7 +453,7 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
Toast.makeText(context, getString(R.string.download_rescheduled_to) + " " + it.time, Toast.LENGTH_LONG).show()
|
||||
downloadViewModel.deleteDownload(item)
|
||||
item.downloadStartTime = it.timeInMillis
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(item.id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelAllWorkByTag(item.id.toString())
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(listOf(item))
|
||||
}
|
||||
|
|
@ -512,7 +517,7 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
bottomSheet.dismiss()
|
||||
downloadViewModel.deleteDownload(item)
|
||||
item.downloadStartTime = 0
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(item.id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelAllWorkByTag(item.id.toString())
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(listOf(item))
|
||||
}
|
||||
|
|
@ -534,6 +539,21 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
}
|
||||
|
||||
override fun onCancelClick(itemID: Long) {
|
||||
lifecycleScope.launch {
|
||||
if (activeCount == 1){
|
||||
val queue = withContext(Dispatchers.IO){
|
||||
val list = downloadViewModel.getQueued().toMutableList()
|
||||
list.map { it.status = DownloadRepository.Status.Queued.toString() }
|
||||
list
|
||||
}
|
||||
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(queue)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cancelActiveDownload(itemID)
|
||||
}
|
||||
override fun onPauseClick(itemID: Long, action: ActiveDownloadAdapter.ActiveDownloadAction, position: Int) {
|
||||
|
|
@ -557,8 +577,16 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
}
|
||||
activeDownloads.notifyItemChanged(position)
|
||||
|
||||
val queue = if (activeCount > 1) listOf(item)
|
||||
else withContext(Dispatchers.IO){
|
||||
val list = downloadViewModel.getQueued().toMutableList()
|
||||
list.map { it.status = DownloadRepository.Status.Queued.toString() }
|
||||
list.add(0, item)
|
||||
list
|
||||
}
|
||||
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(listOf(item))
|
||||
downloadViewModel.queueDownloads(queue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -574,14 +602,14 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
|
||||
private fun cancelItem(id: Int){
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelAllWorkByTag(id.toString())
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
}
|
||||
|
||||
private fun cancelActiveDownload(itemID: Long){
|
||||
val id = itemID.toInt()
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelAllWorkByTag(id.toString())
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
|
||||
activeItems.find { it.id == itemID }?.let {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
private lateinit var notificationUtil: NotificationUtil
|
||||
private lateinit var list: List<DownloadItem>
|
||||
private lateinit var pauseResume: MaterialButton
|
||||
private lateinit var workManager: WorkManager
|
||||
|
||||
|
||||
override fun onCreateView(
|
||||
|
|
@ -53,6 +54,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
notificationUtil = NotificationUtil(requireContext())
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
list = listOf()
|
||||
workManager = WorkManager.getInstance(requireContext())
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +89,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
}
|
||||
|
||||
queued.forEach {
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(it.id.toString())
|
||||
workManager.cancelAllWorkByTag(it.id.toString())
|
||||
}
|
||||
|
||||
list.forEach {
|
||||
|
|
@ -136,7 +138,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
|
||||
it.forEach{item ->
|
||||
WorkManager.getInstance(requireContext())
|
||||
.getWorkInfosForUniqueWorkLiveData(item.id.toString())
|
||||
.getWorkInfosByTagLiveData(item.id.toString())
|
||||
.observe(viewLifecycleOwner){ list ->
|
||||
list.forEach {work ->
|
||||
if (work == null) return@observe
|
||||
|
|
@ -162,6 +164,21 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
}
|
||||
|
||||
override fun onCancelClick(itemID: Long) {
|
||||
lifecycleScope.launch {
|
||||
if (list.size == 1){
|
||||
val queue = withContext(Dispatchers.IO){
|
||||
val list = downloadViewModel.getQueued().toMutableList()
|
||||
list.map { it.status = DownloadRepository.Status.Queued.toString() }
|
||||
list
|
||||
}
|
||||
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(queue)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cancelDownload(itemID)
|
||||
}
|
||||
|
||||
|
|
@ -216,7 +233,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
|
||||
private fun cancelItem(id: Int){
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelAllWorkByTag(id.toString())
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
Toast.makeText(context, getString(R.string.download_rescheduled_to) + " " + it.time, Toast.LENGTH_LONG).show()
|
||||
downloadViewModel.deleteDownload(item)
|
||||
item.downloadStartTime = it.timeInMillis
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(item.id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelAllWorkByTag(item.id.toString())
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(listOf(item))
|
||||
}
|
||||
|
|
@ -231,7 +231,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
bottomSheet.dismiss()
|
||||
downloadViewModel.deleteDownload(item)
|
||||
item.downloadStartTime = 0
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(item.id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelAllWorkByTag(item.id.toString())
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(listOf(item))
|
||||
}
|
||||
|
|
@ -321,7 +321,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
for (obj in selectedObjects!!){
|
||||
val id = obj.id.toInt()
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelAllWorkByTag(id.toString())
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
downloadViewModel.deleteDownload(obj)
|
||||
}
|
||||
|
|
@ -333,7 +333,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
}
|
||||
R.id.download -> {
|
||||
for (obj in selectedObjects!!){
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(obj.id.toInt().toString())
|
||||
WorkManager.getInstance(requireContext()).cancelAllWorkByTag(obj.id.toInt().toString())
|
||||
}
|
||||
selectedObjects!!.forEach { it.downloadStartTime = 0L }
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ class TerminalActivity : BaseActivity() {
|
|||
|
||||
private fun cancelDownload() {
|
||||
YoutubeDL.getInstance().destroyProcessById(downloadID.toString())
|
||||
WorkManager.getInstance(this).cancelUniqueWork(downloadID.toString())
|
||||
WorkManager.getInstance(this).cancelAllWorkByTag(downloadID.toString())
|
||||
notificationUtil.cancelDownloadNotification(downloadID)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1139,9 +1139,9 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
formatArgument = if (downloadItem.videoPreferences.audioFormatIDs.isNotEmpty() && ! downloadItem.videoPreferences.removeAudio){
|
||||
val audioIds = downloadItem.videoPreferences.audioFormatIDs.joinToString("+")
|
||||
"$videoFormatID+$audioIds/best/$videoFormatID"
|
||||
"$videoFormatID+$audioIds/$videoFormatID/best"
|
||||
}else{
|
||||
"$videoFormatID+bestaudio/best/$videoFormatID"
|
||||
"$videoFormatID+bestaudio/$videoFormatID/best"
|
||||
}
|
||||
}
|
||||
Log.e(DownloadWorker.TAG, formatArgument)
|
||||
|
|
@ -1200,6 +1200,18 @@ class InfoUtil(private val context: Context) {
|
|||
return request
|
||||
}
|
||||
|
||||
|
||||
fun parseYTDLRequestString(request : YoutubeDLRequest) : String {
|
||||
val arr = request.buildCommand().toMutableList()
|
||||
for (i in arr.indices) {
|
||||
if (!arr[i].startsWith("-")) {
|
||||
arr[i] = "\"${arr[i]}\""
|
||||
}
|
||||
}
|
||||
|
||||
return java.lang.String.join(" ", arr).replace("\"\"", "\" \"")
|
||||
}
|
||||
|
||||
private val pipedURL = sharedPreferences.getString("piped_instance", defaultPipedURL)?.ifEmpty { defaultPipedURL }?.removeSuffix("/")
|
||||
|
||||
class PlaylistTuple internal constructor(
|
||||
|
|
|
|||
|
|
@ -342,6 +342,12 @@ class NotificationUtil(var context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
fun showYTDLUpdateNotification() : Notification{
|
||||
val notificationBuilder = getBuilder(DOWNLOAD_MISC_CHANNEL_ID)
|
||||
notificationBuilder.setContentTitle("Updating YT-DLP...")
|
||||
return notificationBuilder.build()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DOWNLOAD_SERVICE_CHANNEL_ID = "1"
|
||||
const val COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID = "2"
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class DownloadWorker(
|
|||
) : Worker(context, workerParams) {
|
||||
override fun doWork(): Result {
|
||||
itemId = inputData.getLong("id", 0)
|
||||
if (itemId == 0L || isStopped) return Result.failure()
|
||||
if (itemId == 0L || isStopped) return Result.success()
|
||||
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val infoUtil = InfoUtil(context)
|
||||
|
|
@ -56,10 +56,10 @@ class DownloadWorker(
|
|||
downloadItem = repository.getItemByID(itemId)
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
return Result.failure()
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
if (downloadItem.status != DownloadRepository.Status.Queued.toString() && downloadItem.status != DownloadRepository.Status.Paused.toString()) return Result.failure()
|
||||
if (downloadItem.status != DownloadRepository.Status.Queued.toString() && downloadItem.status != DownloadRepository.Status.Paused.toString()) return Result.success()
|
||||
|
||||
val pendingIntent = NavDeepLinkBuilder(context)
|
||||
.setGraph(R.navigation.nav_graph)
|
||||
|
|
@ -101,7 +101,7 @@ class DownloadWorker(
|
|||
"URL: ${downloadItem.url}\n" +
|
||||
"Type: ${downloadItem.type}\n" +
|
||||
"Format: ${downloadItem.format}\n\n" +
|
||||
"Command: ${java.lang.String.join(" ", request.buildCommand())}\n\n",
|
||||
"Command: ${infoUtil.parseYTDLRequestString(request)} ${downloadItem.extraCommands}\n\n",
|
||||
downloadItem.format,
|
||||
downloadItem.type,
|
||||
System.currentTimeMillis(),
|
||||
|
|
@ -194,7 +194,7 @@ class DownloadWorker(
|
|||
|
||||
}.onFailure {
|
||||
if (it is YoutubeDL.CanceledException) {
|
||||
return Result.failure(
|
||||
return Result.success(
|
||||
Data.Builder().putString("output", "Download has been cancelled!").build()
|
||||
)
|
||||
}else{
|
||||
|
|
@ -225,7 +225,7 @@ class DownloadWorker(
|
|||
NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID
|
||||
)
|
||||
|
||||
return Result.failure(
|
||||
return Result.success(
|
||||
Data.Builder().putString("output", it.toString()).build()
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ class UpdateYTDLWorker(
|
|||
workerParams: WorkerParameters
|
||||
) : CoroutineWorker(context, workerParams) {
|
||||
override suspend fun doWork(): Result {
|
||||
val notification = NotificationUtil(context).showYTDLUpdateNotification()
|
||||
val foregroundInfo = ForegroundInfo(System.currentTimeMillis().toInt(), notification)
|
||||
setForeground(foregroundInfo)
|
||||
UpdateUtil(context).updateYoutubeDL()
|
||||
return Result.success()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@
|
|||
app:icon="@drawable/exomedia_ic_play_arrow_white"
|
||||
android:layout_width="wrap_content"
|
||||
android:indeterminate="true"
|
||||
android:translationZ="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/frame_layout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
@ -67,7 +66,6 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
android:translationZ="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/frame_layout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:textIsSelectable="true"
|
||||
android:id="@+id/currentText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ buildscript {
|
|||
// supports java 1.6
|
||||
commonsCompressVer = '1.12'
|
||||
youtubedlAndroidVer = "23b26d55f8"
|
||||
workVer = "2.8.1"
|
||||
workVer = "2.7.0"
|
||||
composeVer = '1.4.2'
|
||||
kotlinVer = "1.7.21"
|
||||
coroutineVer = "1.6.4"
|
||||
|
|
|
|||
Loading…
Reference in a new issue