From 0bb9d9d8fb4bcfd6a904791222d2fd9e320eed66 Mon Sep 17 00:00:00 2001 From: deniscerri <64997243+deniscerri@users.noreply.github.com> Date: Sat, 22 Feb 2025 17:44:20 +0100 Subject: [PATCH] Fixed quotes breaking command, removed format sorting by default, moved to advanced settings --- .../database/viewmodel/DownloadViewModel.kt | 17 ++- .../ui/adapter/YoutubePlayerClientAdapter.kt | 34 ++++- .../settings/ProcessingSettingsFragment.kt | 120 +--------------- .../advanced/AdvancedSettingsFragment.kt | 133 ++++++++++++++++++ .../ytdl/ui/more/terminal/TerminalFragment.kt | 4 +- .../java/com/deniscerri/ytdl/util/UiUtil.kt | 2 + .../ytdl/util/extractors/YTDLPUtil.kt | 119 +++++++++------- .../res/drawable/baseline_arrow_upward_24.xml | 5 + .../main/res/layout/player_client_item.xml | 40 ++++-- app/src/main/res/layout/textview_chip.xml | 19 +++ app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/advanced_preferences.xml | 24 +++- .../main/res/xml/processing_preferences.xml | 9 -- build.gradle | 2 +- 14 files changed, 326 insertions(+), 203 deletions(-) create mode 100644 app/src/main/res/drawable/baseline_arrow_upward_24.xml create mode 100644 app/src/main/res/layout/textview_chip.xml diff --git a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt index eb66050a..5c06d216 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt @@ -532,12 +532,19 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel fun getFormat(formats: List, type: Type, url: String? = null) : Format { + val sortFormats = sharedPreferences.getBoolean("use_format_sorting", false) + when(type) { Type.audio -> { return cloneFormat ( try { val theFormats = formats.filter { it.vcodec.isBlank() || it.vcodec == "none" } - FormatUtil(application).sortAudioFormats(theFormats).first() + + if (sortFormats) { + FormatUtil(application).sortAudioFormats(theFormats).first() + }else { + theFormats.first() + } }catch (e: Exception){ formatUtil.getGenericAudioFormats(resources).first() } @@ -551,9 +558,11 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel formatUtil.getGenericVideoFormats(resources).sortedByDescending { it.filesize } } - val sorted = FormatUtil(application).sortVideoFormats(theFormats) - println(sorted.map { it.vcodec }) - sorted.first() + if (sortFormats) { + FormatUtil(application).sortVideoFormats(theFormats).first() + }else { + theFormats.first() + } }catch (e: Exception){ formatUtil.getGenericVideoFormats(resources).first() } diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/YoutubePlayerClientAdapter.kt b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/YoutubePlayerClientAdapter.kt index 6e52c6e6..ea71aa0f 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/YoutubePlayerClientAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/YoutubePlayerClientAdapter.kt @@ -5,6 +5,7 @@ import android.app.Activity import android.content.SharedPreferences import android.content.res.ColorStateList import android.graphics.Color +import android.text.TextUtils import android.util.TypedValue import android.view.LayoutInflater import android.view.MotionEvent @@ -23,6 +24,8 @@ import com.deniscerri.ytdl.database.models.CommandTemplate import com.deniscerri.ytdl.database.models.YoutubePlayerClientItem import com.deniscerri.ytdl.util.Extensions.popup import com.google.android.material.card.MaterialCardView +import com.google.android.material.chip.Chip +import com.google.android.material.chip.ChipGroup import com.google.android.material.materialswitch.MaterialSwitch class YoutubePlayerClientAdapter(onItemClickListener: OnItemClickListener, activity: Activity, private var itemTouchHelper: ItemTouchHelper) : ListAdapter(AsyncDifferConfig.Builder( @@ -61,21 +64,38 @@ class YoutubePlayerClientAdapter(onItemClickListener: OnItemClickListener, activ val title = card.findViewById(R.id.title) title.text = item.playerClient - val content = card.findViewById(R.id.content) - content.isVisible = item.poTokens.isNotEmpty() - if (item.poTokens.isNotEmpty()) { - val text = item.poTokens.joinToString("\n") { "PO Token (${it.context}): ${it.token}" } - content.text = text + val content = card.findViewById(R.id.content) + val chips = mutableListOf() + item.poTokens.forEach { + val tmp = activity.layoutInflater.inflate(R.layout.textview_chip, content, false) as TextView + tmp.maxWidth = 500 + tmp.maxLines = 1 + tmp.ellipsize = TextUtils.TruncateAt.END + val text = "PO Token (${it.context}): ${it.token}" + tmp.text = text + chips.add(tmp) + } + + for (chip in chips.reversed()) { + content.addView(chip, 0) } if (item.urlRegex.isNotEmpty()) { - val text = content.text.toString() + "\nURL Regex: " + item.urlRegex.joinToString(", ") - content.text = text + val text = "URL Regex: " + item.urlRegex.joinToString(", ") + content.findViewById(R.id.urlRegex).apply { + isVisible = true + setText(text) + } } + title.alpha = if (item.enabled) 1f else 0.3f + content.alpha = if (item.enabled) 1f else 0.3f + val switch = card.findViewById(R.id.materialSwitch) switch.isChecked = item.enabled switch.setOnClickListener { + title.alpha = if (switch.isChecked) 1f else 0.3f + content.alpha = if (switch.isChecked) 1f else 0.3f onItemClickListener.onStatusToggle(item, switch.isChecked, position) } diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt index 40287cb0..7de3f414 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt @@ -30,8 +30,7 @@ class ProcessingSettingsFragment : BaseSettingsFragment() { val preferredFormatID : EditTextPreference? = findPreference("format_id") val preferredFormatIDAudio : EditTextPreference? = findPreference("format_id_audio") val subtitleLanguages : Preference? = findPreference("subs_lang") - val formatImportanceAudio: Preference? = findPreference("format_importance_audio") - val formatImportanceVideo: Preference? = findPreference("format_importance_video") + preferredFormatID?.title = "${getString(R.string.preferred_format_id)} [${getString(R.string.video)}]" preferredFormatID?.dialogTitle = "${getString(R.string.file_name_template)} [${getString(R.string.video)}]" @@ -50,50 +49,6 @@ class ProcessingSettingsFragment : BaseSettingsFragment() { } - formatImportanceAudio?.apply { - title = "${getString(R.string.format_importance)} [${getString(R.string.audio)}]" - val items = requireContext().getStringArray(R.array.format_importance_audio) - val itemValues = requireContext().getStringArray(R.array.format_importance_audio_values).toSet() - val prefVideo = prefs.getString("format_importance_audio", itemValues.joinToString(","))!! - summary = prefVideo.split(",").mapIndexed { index, s -> "${index + 1}. ${items[itemValues.indexOf(s)]}" }.joinToString("\n") - - setOnPreferenceClickListener { - val pref = prefs.getString("format_importance_audio", itemValues.joinToString(","))!! - val prefArr = pref.split(",") - val itms = itemValues.sortedBy { prefArr.indexOf(it) }.map { - Pair(it, items[itemValues.indexOf(it)]) - }.toMutableList() - - showFormatImportanceDialog(title.toString(), itms) { new -> - editor.putString("format_importance_audio", new.joinToString(",") { it.first }).apply() - formatImportanceAudio.summary = new.map { it.second }.mapIndexed { index, s -> "${index + 1}. $s" }.joinToString("\n") - } - true - } - } - - formatImportanceVideo?.apply { - title = "${getString(R.string.format_importance)} [${getString(R.string.video)}]" - val items = requireContext().getStringArray(R.array.format_importance_video) - val itemValues = requireContext().getStringArray(R.array.format_importance_video_values).toSet() - val prefVideo = prefs.getString("format_importance_video", itemValues.joinToString(","))!! - summary = prefVideo.split(",").mapIndexed { index, s -> "${index + 1}. ${items[itemValues.indexOf(s)]}" }.joinToString("\n") - - setOnPreferenceClickListener { - val pref = prefs.getString("format_importance_video", itemValues.joinToString(","))!! - val prefArr = pref.split(",") - val itms = itemValues.sortedBy { prefArr.indexOf(it) }.map { - Pair(it, items[itemValues.indexOf(it)]) - }.toMutableList() - - showFormatImportanceDialog(title.toString(), itms) {new -> - editor.putString("format_importance_video", new.joinToString(",") { it.first }).apply() - formatImportanceVideo.summary = new.map { it.second }.mapIndexed { index, s -> "${index + 1}. $s" }.joinToString("\n") - } - true - } - } - findPreference("format_id")?.apply { val s = getString(R.string.preferred_format_id_summary) summary = if (text.isNullOrBlank()) { @@ -128,77 +83,4 @@ class ProcessingSettingsFragment : BaseSettingsFragment() { } } } - - - private fun showFormatImportanceDialog(t: String, items: MutableList>, onChange: (items: List>) -> Unit){ - val builder = MaterialAlertDialogBuilder(requireContext()) - builder.setTitle(t) - val adapter = SortableTextItemAdapter(items) - val itemTouchCallback = object : ItemTouchHelper.Callback() { - override fun getMovementFlags( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder - ): Int { - val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN - return makeMovementFlags(dragFlags, 0) - } - - override fun onMove( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean { - val itemToMove = adapter.items[viewHolder.absoluteAdapterPosition] - adapter.items.remove(itemToMove) - adapter.items.add(target.absoluteAdapterPosition, itemToMove) - - adapter.notifyItemMoved( - viewHolder.absoluteAdapterPosition, - target.absoluteAdapterPosition - ) - return true - } - - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - // do nothing - } - } - - val linear = LinearLayout(requireActivity()) - linear.orientation = LinearLayout.VERTICAL - - val note = TextView(requireActivity()) - note.text = getString(R.string.format_importance_note) - note.textSize = 16f - note.setTypeface(note.typeface, Typeface.BOLD) - note.setPadding(20,20,20,20) - linear.addView(note) - - val recycler = RecyclerView(requireContext()) - recycler.layoutManager = LinearLayoutManager(requireContext()) - recycler.adapter = adapter - - linear.addView(recycler) - - val itemTouchHelper = ItemTouchHelper(itemTouchCallback) - itemTouchHelper.attachToRecyclerView(recycler) - - - builder.setView(linear) - builder.setPositiveButton( - getString(android.R.string.ok) - ) { _: DialogInterface?, _: Int -> - onChange(adapter.items) - } - - // handle the negative button of the alert dialog - builder.setNegativeButton( - getString(R.string.cancel) - ) { _: DialogInterface?, _: Int -> } - - val dialog = builder.create() - dialog.show() - } - - } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/AdvancedSettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/AdvancedSettingsFragment.kt index 812401bb..363f747d 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/AdvancedSettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/AdvancedSettingsFragment.kt @@ -1,13 +1,23 @@ package com.deniscerri.ytdl.ui.more.settings.advanced import android.annotation.SuppressLint +import android.content.DialogInterface +import android.graphics.Typeface import android.os.Bundle +import android.widget.LinearLayout +import android.widget.TextView import androidx.navigation.fragment.findNavController import androidx.preference.Preference import androidx.preference.PreferenceManager +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.afollestad.materialdialogs.utils.MDUtil.getStringArray import com.deniscerri.ytdl.R +import com.deniscerri.ytdl.ui.adapter.SortableTextItemAdapter import com.deniscerri.ytdl.ui.more.settings.BaseSettingsFragment import com.deniscerri.ytdl.util.UiUtil +import com.google.android.material.dialog.MaterialAlertDialogBuilder class AdvancedSettingsFragment : BaseSettingsFragment() { @@ -15,9 +25,132 @@ class AdvancedSettingsFragment : BaseSettingsFragment() { @SuppressLint("RestrictedApi") override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.advanced_preferences, rootKey) + val prefs = PreferenceManager.getDefaultSharedPreferences(requireActivity()) + val editor = prefs.edit() + findPreference("yt_player_client")?.setOnPreferenceClickListener { findNavController().navigate(R.id.youtubePlayerClientFragment) false } + + val formatImportanceAudio: Preference? = findPreference("format_importance_audio") + val formatImportanceVideo: Preference? = findPreference("format_importance_video") + + formatImportanceAudio?.apply { + title = "${getString(R.string.format_importance)} [${getString(R.string.audio)}]" + val items = requireContext().getStringArray(R.array.format_importance_audio) + val itemValues = requireContext().getStringArray(R.array.format_importance_audio_values).toSet() + val prefVideo = prefs.getString("format_importance_audio", itemValues.joinToString(","))!! + summary = prefVideo.split(",").mapIndexed { index, s -> "${index + 1}. ${items[itemValues.indexOf(s)]}" }.joinToString("\n") + + setOnPreferenceClickListener { + val pref = prefs.getString("format_importance_audio", itemValues.joinToString(","))!! + val prefArr = pref.split(",") + val itms = itemValues.sortedBy { prefArr.indexOf(it) }.map { + Pair(it, items[itemValues.indexOf(it)]) + }.toMutableList() + + showFormatImportanceDialog(title.toString(), itms) { new -> + editor.putString("format_importance_audio", new.joinToString(",") { it.first }).apply() + formatImportanceAudio.summary = new.map { it.second }.mapIndexed { index, s -> "${index + 1}. $s" }.joinToString("\n") + } + true + } + } + + formatImportanceVideo?.apply { + title = "${getString(R.string.format_importance)} [${getString(R.string.video)}]" + val items = requireContext().getStringArray(R.array.format_importance_video) + val itemValues = requireContext().getStringArray(R.array.format_importance_video_values).toSet() + val prefVideo = prefs.getString("format_importance_video", itemValues.joinToString(","))!! + summary = prefVideo.split(",").mapIndexed { index, s -> "${index + 1}. ${items[itemValues.indexOf(s)]}" }.joinToString("\n") + + setOnPreferenceClickListener { + val pref = prefs.getString("format_importance_video", itemValues.joinToString(","))!! + val prefArr = pref.split(",") + val itms = itemValues.sortedBy { prefArr.indexOf(it) }.map { + Pair(it, items[itemValues.indexOf(it)]) + }.toMutableList() + + showFormatImportanceDialog(title.toString(), itms) {new -> + editor.putString("format_importance_video", new.joinToString(",") { it.first }).apply() + formatImportanceVideo.summary = new.map { it.second }.mapIndexed { index, s -> "${index + 1}. $s" }.joinToString("\n") + } + true + } + } + + } + + + + private fun showFormatImportanceDialog(t: String, items: MutableList>, onChange: (items: List>) -> Unit){ + val builder = MaterialAlertDialogBuilder(requireContext()) + builder.setTitle(t) + val adapter = SortableTextItemAdapter(items) + val itemTouchCallback = object : ItemTouchHelper.Callback() { + override fun getMovementFlags( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder + ): Int { + val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN + return makeMovementFlags(dragFlags, 0) + } + + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean { + val itemToMove = adapter.items[viewHolder.absoluteAdapterPosition] + adapter.items.remove(itemToMove) + adapter.items.add(target.absoluteAdapterPosition, itemToMove) + + adapter.notifyItemMoved( + viewHolder.absoluteAdapterPosition, + target.absoluteAdapterPosition + ) + return true + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + // do nothing + } + } + + val linear = LinearLayout(requireActivity()) + linear.orientation = LinearLayout.VERTICAL + + val note = TextView(requireActivity()) + note.text = getString(R.string.format_importance_note) + note.textSize = 16f + note.setTypeface(note.typeface, Typeface.BOLD) + note.setPadding(20,20,20,20) + linear.addView(note) + + val recycler = RecyclerView(requireContext()) + recycler.layoutManager = LinearLayoutManager(requireContext()) + recycler.adapter = adapter + + linear.addView(recycler) + + val itemTouchHelper = ItemTouchHelper(itemTouchCallback) + itemTouchHelper.attachToRecyclerView(recycler) + + + builder.setView(linear) + builder.setPositiveButton( + getString(android.R.string.ok) + ) { _: DialogInterface?, _: Int -> + onChange(adapter.items) + } + + // handle the negative button of the alert dialog + builder.setNegativeButton( + getString(R.string.cancel) + ) { _: DialogInterface?, _: Int -> } + + val dialog = builder.create() + dialog.show() } } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/terminal/TerminalFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/terminal/TerminalFragment.kt index da74a7a0..47156635 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/terminal/TerminalFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/terminal/TerminalFragment.kt @@ -364,8 +364,8 @@ class TerminalFragment : Fragment() { .observe(viewLifecycleOwner, workerObserver) } - private val workerObserver = object: Observer> { - override fun onChanged(value: MutableList) { + private val workerObserver = object: Observer> { + override fun onChanged(value: List) { value.forEach { work -> if (listOf(WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED).contains(work.state)) { requireActivity().runOnUiThread { diff --git a/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt index 3627aa41..8c769f2b 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt @@ -1500,6 +1500,7 @@ object UiUtil { val cut = view.findViewById(R.id.cut) if (items.size > 1 || items.first().url.isEmpty()) cut.isVisible = false else{ + cut.setOnClickListener(null) val invalidDuration = items[0].duration == "-1" if(items[0].duration.isNotEmpty() && !invalidDuration){ val downloadItem = items[0] @@ -1664,6 +1665,7 @@ object UiUtil { val cut = view.findViewById(R.id.cut) if (items.size > 1 || items.first().url.isEmpty()) cut.isVisible = false else{ + cut.setOnClickListener(null) val downloadItem = items[0] val invalidDuration = downloadItem.duration == "-1" if (downloadItem.duration.isNotEmpty() && !invalidDuration){ diff --git a/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt index eac59b79..bae87df9 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt @@ -823,40 +823,49 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co } request.addOption("-x") - val formatSorting = mutableListOf("hasaud") - val formatImportance = formatUtil.getAudioFormatImportance() - for(order in formatImportance) { - when(order) { - "file_size" -> { - formatSorting.add("size") - } - "language" -> { - if (preferredLanguage.isNotBlank()) { - formatSorting.add("lang:${preferredLanguage}") + val formatSorting = mutableListOf() + if (sharedPreferences.getBoolean("use_format_sorting", false)) { + formatSorting.add("hasaud") + val formatImportance = formatUtil.getAudioFormatImportance() + for(order in formatImportance) { + when(order) { + "file_size" -> { + formatSorting.add("size") } - } - "codec" -> { - if (aCodecPref.isNotBlank()){ - formatSorting.add("acodec:$aCodecPref") + "language" -> { + if (preferredLanguage.isNotBlank()) { + formatSorting.add("lang:${preferredLanguage}") + } } - } - "container" -> { - if(ext.isNotBlank()){ - if(!ext.matches("(webm)|(Default)|(${context.getString(R.string.defaultValue)})".toRegex()) && supportedContainers.contains(ext)){ - request.addOption("--audio-format", ext) - formatSorting.add("aext:$ext") + "codec" -> { + if (aCodecPref.isNotBlank()){ + formatSorting.add("acodec:$aCodecPref") + } + } + "container" -> { + if(ext.isNotBlank()){ + if(!ext.matches("(webm)|(Default)|(${context.getString(R.string.defaultValue)})".toRegex()) && supportedContainers.contains(ext)){ + request.addOption("--audio-format", ext) + formatSorting.add("aext:$ext") + } } } } } + + if (downloadItem.format.format_id == context.resources.getString(R.string.worst_quality) || downloadItem.format.format_id == "wa" || downloadItem.format.format_id == "worst") { + if(formatSorting.contains("size")) { + formatSorting.remove("size") + } + formatSorting.addAll(0,listOf("+br", "+res", "+fps")) + } + }else if (preferredLanguage.isNotBlank()) { + formatSorting.add("lang:${preferredLanguage}") } - - if (downloadItem.format.format_id == context.resources.getString(R.string.worst_quality) || downloadItem.format.format_id == "wa" || downloadItem.format.format_id == "worst") { - if(formatSorting.contains("size")) { - formatSorting.remove("size") - } - formatSorting.addAll(0,listOf("+br", "+res", "+fps")) + if (sharedPreferences.getBoolean("prefer_smaller_formats", false) && !formatSorting.contains("+size")) { + formatSorting.remove("size") + formatSorting.add(0, "+size") } if (abrSort.isNotBlank()){ @@ -867,7 +876,6 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co request.addOption("-S", formatSorting.joinToString(",")) } - request.addOption("-P", downDir.absolutePath) @@ -1119,38 +1127,41 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co val formatImportance = formatUtil.getVideoFormatImportance() val formatSorting = mutableListOf() - for(order in formatImportance) { - when(order) { - "no_audio" -> { - formatSorting.add("+hasaud") - } - "codec" -> { - if (vCodecPref.isNotBlank()) formatSorting.add("vcodec:$vCodecPref") - if (aCodecPref.isNotBlank()) formatSorting.add("acodec:$aCodecPref") - } - "resolution" -> { - if (hasGenericResulutionFormat.isNotBlank()) { - formatSorting.add("res:${hasGenericResulutionFormat}") + if (sharedPreferences.getBoolean("use_format_sorting", false)) { + for(order in formatImportance) { + when(order) { + "no_audio" -> { + formatSorting.add("+hasaud") + } + "codec" -> { + if (vCodecPref.isNotBlank()) formatSorting.add("vcodec:$vCodecPref") + if (aCodecPref.isNotBlank()) formatSorting.add("acodec:$aCodecPref") + } + "resolution" -> { + if (hasGenericResulutionFormat.isNotBlank()) { + formatSorting.add("res:${hasGenericResulutionFormat}") + } + } + "container" -> { + if (cont.isNotBlank()) formatSorting.add("vext:$cont") + if (acont.isNotBlank()) formatSorting.add("aext:$acont") } } - "container" -> { - if (cont.isNotBlank()) formatSorting.add("vext:$cont") - if (acont.isNotBlank()) formatSorting.add("aext:$acont") + } + + if (downloadItem.format.format_id == context.resources.getString(R.string.worst_quality) || downloadItem.format.format_id == "worst") { + formatSorting.addAll(0, listOf("+br","+res","+fps")) + }else { + if (sharedPreferences.getBoolean("prefer_smaller_formats", false)) { + formatSorting.add(0, "+size") } } } - if (downloadItem.format.format_id == context.resources.getString(R.string.worst_quality) || downloadItem.format.format_id == "worst") { - formatSorting.addAll(0, listOf("+br","+res","+fps")) - }else { - if (sharedPreferences.getBoolean("prefer_smaller_formats", false)) { - formatSorting.add(0, "+size") - }else { - formatSorting.add(0, "size") - } + if (sharedPreferences.getBoolean("prefer_smaller_formats", false) && !formatSorting.contains("+br")) { + formatSorting.add(0, "+size") } - if (abrSort.isNotBlank()) { formatSorting.add("abr~${abrSort}") } @@ -1324,7 +1335,11 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co this.add(elements.first().toString()) if (elements.size > 1) { for (el in elements.drop(1)) { - this.add(""""$el"""") + val arg = el.toString() + .replace("\\", "\\\\") + .replace("\"", "\\\"") + + this.add("\"$arg\"") } } } diff --git a/app/src/main/res/drawable/baseline_arrow_upward_24.xml b/app/src/main/res/drawable/baseline_arrow_upward_24.xml new file mode 100644 index 00000000..d2eef1f7 --- /dev/null +++ b/app/src/main/res/drawable/baseline_arrow_upward_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/player_client_item.xml b/app/src/main/res/layout/player_client_item.xml index 95c4eaff..de13f7c8 100644 --- a/app/src/main/res/layout/player_client_item.xml +++ b/app/src/main/res/layout/player_client_item.xml @@ -49,17 +49,41 @@ app:layout_constraintStart_toEndOf="@id/drag_view" app:layout_constraintTop_toTopOf="parent" /> - + app:layout_constraintTop_toBottomOf="@+id/title" + app:layout_constraintHorizontal_bias="0.0" + android:id="@+id/content" + app:chipSpacing="0dp" + android:layout_width="0dp" + android:layout_height="wrap_content"> + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b17bed64..26a3a7df 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -464,4 +464,5 @@ Cache Folder Changing the Cache Folder might cause unexpected issues. If the app cannot write to the configured path, it will resort to the default internal cache directory Icon could change and Application will close + Use Format Importance Ordering \ No newline at end of file diff --git a/app/src/main/res/xml/advanced_preferences.xml b/app/src/main/res/xml/advanced_preferences.xml index b7628edb..c07ae774 100644 --- a/app/src/main/res/xml/advanced_preferences.xml +++ b/app/src/main/res/xml/advanced_preferences.xml @@ -34,7 +34,29 @@ android:title="@string/data_fetching_extra_command" /> - + + + + + + + + + + - - - diff --git a/build.gradle b/build.gradle index c5347b4b..52e7b442 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ buildscript { youtubedlAndroidVerNoPyCrypto = "97bee6c0e8" youtubedlAndroidVerMine = "8831745ea3" oldytdlAndroidVer = "0.14.0" - workVer = "2.9.1" + workVer = "2.10.0" composeVer = '1.4.2' kotlinVer = "1.7.21" coroutineVer = '1.7.3'