From cacc871815c75f984598d2f63a2cf8c854a19841 Mon Sep 17 00:00:00 2001 From: deniscerri <64997243+deniscerri@users.noreply.github.com> Date: Sat, 16 Aug 2025 21:13:55 +0200 Subject: [PATCH] add gif video container & add compatibility mode for recode video --- .../ytdl/database/models/VideoPreferences.kt | 3 +- .../DownloadMultipleBottomSheetDialog.kt | 19 ++++ .../ui/downloadcard/DownloadVideoFragment.kt | 25 +++++- .../java/com/deniscerri/ytdl/util/UiUtil.kt | 40 +++++++-- .../ytdl/util/extractors/YTDLPUtil.kt | 15 ++-- app/src/main/res/layout/adjust_video.xml | 18 ++-- .../video_download_preferences_dialog.xml | 86 +++++++++++++++++++ app/src/main/res/values/arrays.xml | 2 + app/src/main/res/values/strings.xml | 2 + 9 files changed, 185 insertions(+), 25 deletions(-) create mode 100644 app/src/main/res/layout/video_download_preferences_dialog.xml diff --git a/app/src/main/java/com/deniscerri/ytdl/database/models/VideoPreferences.kt b/app/src/main/java/com/deniscerri/ytdl/database/models/VideoPreferences.kt index f612bf54..655c7016 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/models/VideoPreferences.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/models/VideoPreferences.kt @@ -17,5 +17,6 @@ data class VideoPreferences ( var alsoDownloadAsAudio: Boolean = false, var recodeVideo: Boolean = false, var liveFromStart: Boolean = false, - var waitForVideoMinutes: Int = 0 + var waitForVideoMinutes: Int = 0, + var compatibilityMode: Boolean = false ) : Parcelable diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt index d791dfbe..f89f1c0a 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt @@ -674,6 +674,15 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure items.forEach { it.videoPreferences.recodeVideo = checked } CoroutineScope(Dispatchers.IO).launch { items.forEach { downloadViewModel.updateDownload(it) } } }, + compatibilityModeClicked = { checked -> + items.forEach { + it.videoPreferences.compatibilityMode = checked + if(checked) { + it.container = "mkv" + } + } + CoroutineScope(Dispatchers.IO).launch { items.forEach { downloadViewModel.updateDownload(it) } } + }, alsoDownloadAsAudioClicked = {}, extraCommandsClicked = { val callback = object : ExtraCommandsListener { @@ -815,6 +824,16 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure withContext(Dispatchers.IO){ downloadViewModel.updateProcessingContainer(listAdapter.getCheckedItemsOrNull(), container.toString()) } + if (container == "gif") { + val items = withContext(Dispatchers.IO){ + downloadViewModel.getProcessingDownloads(listAdapter.getCheckedItemsOrNull()) + } + items.forEach { + it.videoPreferences.removeAudio = true + it.videoPreferences.recodeVideo = true + } + CoroutineScope(Dispatchers.IO).launch { items.forEach { downloadViewModel.updateDownload(it) } } + } } setContainerText(container.toString()) true diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadVideoFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadVideoFragment.kt index 12e33574..764d9589 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadVideoFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadVideoFragment.kt @@ -307,7 +307,7 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private true } - container?.isEnabled = true + container?.isEnabled = !downloadItem.videoPreferences.compatibilityMode containerAutoCompleteTextView?.setAdapter( ArrayAdapter( requireContext(), @@ -318,6 +318,9 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private if (currentDownloadItem == null || !containers.contains(downloadItem.container.ifEmpty { getString(R.string.defaultValue) })){ downloadItem.container = if (containerPreference == getString(R.string.defaultValue)) "" else containerPreference!! } + if (downloadItem.videoPreferences.compatibilityMode) { + container.editText?.setText("mkv") + } containerAutoCompleteTextView!!.setText( downloadItem.container.ifEmpty { getString(R.string.defaultValue) }, false) @@ -326,9 +329,19 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> downloadItem.container = containers[index] if (containers[index] == getString(R.string.defaultValue)) downloadItem.container = "" + if (containers[index] == "gif") { + view.findViewById(R.id.adjust_audio).isEnabled = false + downloadItem.videoPreferences.removeAudio = true + view.findViewById(R.id.recode_video).isEnabled = false + downloadItem.videoPreferences.recodeVideo = true + }else { + view.findViewById(R.id.adjust_audio).isEnabled = true + downloadItem.videoPreferences.removeAudio = false + view.findViewById(R.id.recode_video).isEnabled = true + downloadItem.videoPreferences.recodeVideo = false + } } - view.findViewById(R.id.adjust).apply { visibility = if (shownFields.contains("adjust_video")) View.VISIBLE else View.GONE if (isVisible){ @@ -426,6 +439,14 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private recodeVideoClicked = { downloadItem.videoPreferences.recodeVideo = it }, + compatibilityModeClicked = { + downloadItem.videoPreferences.compatibilityMode = it + container.isEnabled = !it + if (it) { + container.editText?.setText("mkv") + downloadItem.container = "mkv" + } + }, alsoDownloadAsAudioClicked = { downloadItem.videoPreferences.alsoDownloadAsAudio = it }, 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 fccb605c..5302899c 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt @@ -1309,6 +1309,7 @@ object UiUtil { subtitleLanguagesSet: (String) -> Unit, removeAudioClicked: (Boolean) -> Unit, recodeVideoClicked: (Boolean) -> Unit, + compatibilityModeClicked: (Boolean) -> Unit, alsoDownloadAsAudioClicked: (Boolean) -> Unit, extraCommandsClicked: () -> Unit, liveFromStart: (Boolean) -> Unit, @@ -1414,7 +1415,7 @@ object UiUtil { adjustSubtitleDialog.show() } - if (items.size == 1 && items.first().id == 0L){ + if (items.size == 1){ val adjustAudio = view.findViewById(R.id.adjust_audio) adjustAudio.setOnClickListener { val adjustAudioView = context.layoutInflater.inflate(R.layout.audio_download_preferences_dialog, null) @@ -1440,6 +1441,7 @@ object UiUtil { adjustAudioDialog.show() } + adjustAudio.isEnabled = items.first().container != "gif" }else{ val adjustAudio = view.findViewById(R.id.adjust_audio) adjustAudio.isVisible = false @@ -1449,8 +1451,37 @@ object UiUtil { removeAudio.setOnCheckedChangeListener { _, _ -> removeAudioClicked(removeAudio.isChecked) } + removeAudio.isEnabled = !items.any { it.container == "gif" } } + val recodeVideo = view.findViewById(R.id.recode_video) + recodeVideo.setOnClickListener { + val adjustVideoView = context.layoutInflater.inflate(R.layout.video_download_preferences_dialog, null) + adjustVideoView.findViewById(R.id.recodeVideoSwitch).apply { + isChecked = items.all { it.videoPreferences.recodeVideo } + setOnCheckedChangeListener { _, b -> + recodeVideoClicked(b) + } + } + + adjustVideoView.findViewById(R.id.compatiblityModeSwitch).apply { + isChecked = items.first().videoPreferences.compatibilityMode + setOnCheckedChangeListener { _, b -> + compatibilityModeClicked(b) + } + } + + val adjustVideoDialog = MaterialAlertDialogBuilder(context) + .setTitle(context.getString(R.string.recode_video)) + .setView(adjustVideoView) + .setIcon(R.drawable.ic_video) + .setNegativeButton(context.resources.getString(R.string.dismiss)) { _: DialogInterface?, _: Int -> } + + adjustVideoDialog.show() + } + recodeVideo.isEnabled = items.first().container != "gif" + + val adjustLiveStream = view.findViewById(R.id.adjust_live_stream) if (items.size == 1) { adjustLiveStream.setOnClickListener { @@ -1509,13 +1540,6 @@ object UiUtil { adjustLiveStream.isVisible = false } - val recodeVideo = view.findViewById(R.id.recode_video) - recodeVideo.isChecked = items.all { it.videoPreferences.recodeVideo } - recodeVideo.setOnCheckedChangeListener { _, _ -> - recodeVideoClicked(recodeVideo.isChecked) - } - - val sponsorBlock = view.findViewById(R.id.sponsorblock_filters) sponsorBlock.isEnabled = sharedPreferences.getBoolean("use_sponsorblock", true) sponsorBlock!!.setOnClickListener { 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 f4990229..1dd6c33b 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 @@ -1127,10 +1127,16 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co if (downloadItem.videoPreferences.recodeVideo && !cantRecode.contains(cont)) { request.addOption("--recode-video", outputContainer.lowercase()) }else{ - request.addOption("--merge-output-format", outputContainer.lowercase()) + if (downloadItem.videoPreferences.compatibilityMode) { + request.addOption("--recode-video", "mp4") + request.addOption("--merge-output-format", "mkv") + } + else { + request.addOption("--merge-output-format", outputContainer.lowercase()) + } } - if (!listOf("webm", "avi", "flv").contains(outputContainer.lowercase())) { + if (!listOf("webm", "avi", "flv", "gif").contains(outputContainer.lowercase())) { val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false) if (embedThumb) { metadataCommands.addOption("--embed-thumbnail") @@ -1350,12 +1356,9 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co request.addOption("--sub-langs", downloadItem.videoPreferences.subsLanguages.ifEmpty { "en.*,.*-orig" }) } - - - if (downloadItem.videoPreferences.removeAudio){ + if (downloadItem.videoPreferences.removeAudio && outputContainer != "gif") { request.addOption("--use-postprocessor", "FFmpegCopyStream") request.addOption("--ppa", "CopyStream:-c copy -an") - } request.addOption("-P", downDir.absolutePath) diff --git a/app/src/main/res/layout/adjust_video.xml b/app/src/main/res/layout/adjust_video.xml index ffc076bc..60f71dc3 100644 --- a/app/src/main/res/layout/adjust_video.xml +++ b/app/src/main/res/layout/adjust_video.xml @@ -109,6 +109,16 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + - - diff --git a/app/src/main/res/layout/video_download_preferences_dialog.xml b/app/src/main/res/layout/video_download_preferences_dialog.xml new file mode 100644 index 00000000..0ec09920 --- /dev/null +++ b/app/src/main/res/layout/video_download_preferences_dialog.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index f5a58121..0765df91 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -29,6 +29,7 @@ mov avi flv + gif @@ -39,6 +40,7 @@ mov avi flv + gif diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a7ec95a3..6f041a64 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -483,4 +483,6 @@ Reverse Delete subtitle files after embedding When using both Embed Subtitles and Write Subtitles, don\'t keep the subtitle files after embedding + Compatible Video + Recodes the video making it compatible with other apps