From 73b5be6f6f3aeedecb16b7501dec7a3c4dbb6503 Mon Sep 17 00:00:00 2001 From: deniscerri <64997243+deniscerri@users.noreply.github.com> Date: Tue, 14 Jan 2025 21:16:38 +0100 Subject: [PATCH] more bug fixes --- app/build.gradle | 4 +- .../ytdl/database/models/VideoPreferences.kt | 4 +- .../ui/downloadcard/DownloadAudioFragment.kt | 8 + .../DownloadMultipleBottomSheetDialog.kt | 4 +- .../ui/downloadcard/DownloadVideoFragment.kt | 13 ++ .../com/deniscerri/ytdl/util/Extensions.kt | 9 ++ .../com/deniscerri/ytdl/util/FormatUtil.kt | 5 + .../deniscerri/ytdl/util/NotificationUtil.kt | 2 +- .../java/com/deniscerri/ytdl/util/UiUtil.kt | 62 +++++++- .../ytdl/util/extractors/YTDLPUtil.kt | 147 ++++++++++++------ .../deniscerri/ytdl/work/DownloadWorker.kt | 3 +- .../ytdl/work/TerminalDownloadWorker.kt | 19 ++- .../main/res/drawable/baseline_live_tv_24.xml | 5 + app/src/main/res/layout/adjust_video.xml | 23 ++- .../res/layout/filename_template_dialog.xml | 2 +- ...livestream_download_preferences_dialog.xml | 76 +++++++++ app/src/main/res/values/strings.xml | 7 + .../main/res/xml/downloading_preferences.xml | 2 +- .../main/res/xml/processing_preferences.xml | 117 +++++++------- 19 files changed, 396 insertions(+), 116 deletions(-) create mode 100644 app/src/main/res/drawable/baseline_live_tv_24.xml create mode 100644 app/src/main/res/layout/livestream_download_preferences_dialog.xml diff --git a/app/build.gradle b/app/build.gradle index 26f376c6..e7a9b29c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ plugins { def properties = new Properties() def versionMajor = 1 def versionMinor = 8 -def versionPatch = 1 -def versionBuild = 2 // bump for dogfood builds, public betas, etc. +def versionPatch = 2 +def versionBuild = 0 // bump for dogfood builds, public betas, etc. def isBeta = false def versionExt = "" 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 c4d14bbf..f612bf54 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 @@ -15,5 +15,7 @@ data class VideoPreferences ( var audioFormatIDs : ArrayList = arrayListOf(), var removeAudio: Boolean = false, var alsoDownloadAsAudio: Boolean = false, - var recodeVideo: Boolean = false + var recodeVideo: Boolean = false, + var liveFromStart: Boolean = false, + var waitForVideoMinutes: Int = 0 ) : Parcelable diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadAudioFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadAudioFragment.kt index 7823528f..89c22389 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadAudioFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadAudioFragment.kt @@ -31,6 +31,7 @@ import com.deniscerri.ytdl.database.models.ResultItem import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel.Type import com.deniscerri.ytdl.database.viewmodel.ResultViewModel +import com.deniscerri.ytdl.util.Extensions.applyFilenameTemplateForCuts import com.deniscerri.ytdl.util.FileUtil import com.deniscerri.ytdl.util.FormatUtil import com.deniscerri.ytdl.util.UiUtil @@ -335,6 +336,13 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private cutValueChanged = { downloadItem.downloadSections = it UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format, showSize = downloadItem.downloadSections.isEmpty()) + + if (it.isNotBlank()){ + downloadItem.customFileNameTemplate = downloadItem.customFileNameTemplate.applyFilenameTemplateForCuts() + }else{ + downloadItem.customFileNameTemplate = sharedPreferences.getString("file_name_template_audio", "%(uploader).30B - %(title).170B")!! + } + }, extraCommandsClicked = { val callback = object : ExtraCommandsListener { 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 33784df2..d155013b 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 @@ -692,7 +692,9 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure val bottomSheetDialog = AddExtraCommandsDialog(null, callback) bottomSheetDialog.show(parentFragmentManager, "extraCommands") - } + }, + waitForVideo = {b, i -> }, + liveFromStart = {} ) bottomSheet.show() 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 9f75dbb0..6e61c74b 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 @@ -31,6 +31,7 @@ import com.deniscerri.ytdl.database.models.ResultItem import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel.Type import com.deniscerri.ytdl.database.viewmodel.ResultViewModel +import com.deniscerri.ytdl.util.Extensions.applyFilenameTemplateForCuts import com.deniscerri.ytdl.util.FileUtil import com.deniscerri.ytdl.util.FormatUtil import com.deniscerri.ytdl.util.UiUtil @@ -382,6 +383,12 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private else downloadItem.allFormats.filter { f -> downloadItem.videoPreferences.audioFormatIDs.contains(f.format_id) }, showSize = downloadItem.downloadSections.isEmpty() ) + + if (it.isNotBlank()){ + downloadItem.customFileNameTemplate = downloadItem.customFileNameTemplate.applyFilenameTemplateForCuts() + }else{ + downloadItem.customFileNameTemplate = sharedPreferences.getString("file_name_template", "%(uploader).30B - %(title).170B")!! + } }, filenameTemplateSet = { downloadItem.customFileNameTemplate = it @@ -420,6 +427,12 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private val bottomSheetDialog = AddExtraCommandsDialog(downloadItem, callback) bottomSheetDialog.show(parentFragmentManager, "extraCommands") + }, + liveFromStart = { + downloadItem.videoPreferences.liveFromStart = it + }, + waitForVideo = { wait, value -> + downloadItem.videoPreferences.waitForVideoMinutes = if (wait) value else 0 } ) } diff --git a/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt b/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt index ba166403..5c944250 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt @@ -563,4 +563,13 @@ object Extensions { fun DownloadItem.needsDataUpdating() : Boolean { return this.title.isBlank() || this.author.isBlank() || this.thumb.isBlank() } + + fun String.applyFilenameTemplateForCuts() : String { + return if(this.isBlank()) { + "%(section_title&{} - |)s%(title).170B" + }else { + if(this.startsWith("%(section_title&{} - |)s")) this + else "%(section_title&{} - |)s$this" + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/util/FormatUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/FormatUtil.kt index 9a546610..2df328ac 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/FormatUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/FormatUtil.kt @@ -38,6 +38,11 @@ class FormatUtil(private var context: Context) { orderPreferences.remove("file_size") } + val preferContainerOverCodec = sharedPreferences.getBoolean("prefer_container_over_codec_audio", false) + if(preferContainerOverCodec) { + orderPreferences.remove("codec") + } + return orderPreferences } diff --git a/app/src/main/java/com/deniscerri/ytdl/util/NotificationUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/NotificationUtil.kt index 515144c9..3a1b65c3 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/NotificationUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/NotificationUtil.kt @@ -627,7 +627,7 @@ class NotificationUtil(var context: Context) { .setContentTitle(resources.getString(R.string.updating_download_data)) .setOngoing(true) .setCategory(Notification.CATEGORY_PROGRESS) - .setSmallIcon(R.drawable.ic_launcher_foreground) + .setSmallIcon(R.drawable.ic_launcher_foreground_large) .setLargeIcon( BitmapFactory.decodeResource( resources, 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 887a5de4..9d73fa6c 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt @@ -1205,7 +1205,9 @@ object UiUtil { removeAudioClicked: (Boolean) -> Unit, recodeVideoClicked: (Boolean) -> Unit, alsoDownloadAsAudioClicked: (Boolean) -> Unit, - extraCommandsClicked: () -> Unit + extraCommandsClicked: () -> Unit, + liveFromStart: (Boolean) -> Unit, + waitForVideo: (Boolean, Int) -> Unit, ){ val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) @@ -1343,6 +1345,64 @@ object UiUtil { } } + val adjustLiveStream = view.findViewById(R.id.adjust_live_stream) + if (items.size == 1) { + adjustLiveStream.setOnClickListener { + val adjustLiveStreamView = context.layoutInflater.inflate(R.layout.livestream_download_preferences_dialog, null) + val liveFromStartSwitch = adjustLiveStreamView.findViewById(R.id.live_from_start) + val waitForVideoSwitch = adjustLiveStreamView.findViewById(R.id.wait_for_video) + val waitForVideoSettings = adjustLiveStreamView.findViewById(R.id.wait_for_video_settings) + + val waitEveryNr = adjustLiveStreamView.findViewById(R.id.every_nr).editText!! + + val item = items.first() + + item.videoPreferences.waitForVideoMinutes.apply { + if(this > 0) { + waitEveryNr.setText(this.toString()) + } + } + + waitEveryNr.doOnTextChanged { text, start, before, count -> + var number = 1 + kotlin.runCatching { + number = Integer.parseInt(waitEveryNr.text.toString()) + } + + waitForVideo(true, number) + } + + liveFromStartSwitch.setOnCheckedChangeListener { compoundButton, b -> + liveFromStart(b) + } + + waitForVideoSwitch.setOnCheckedChangeListener { compoundButton, b -> + waitForVideoSettings.isVisible = b + + var number = 1 + kotlin.runCatching { + number = Integer.parseInt(waitEveryNr.text.toString()) + } + + waitForVideo(b, number) + } + + liveFromStartSwitch.isChecked = item.videoPreferences.liveFromStart + waitForVideoSwitch.isChecked = item.videoPreferences.waitForVideoMinutes > 0 + waitForVideoSettings.isVisible = waitForVideoSwitch.isChecked + + val adjustLiveStreamDialog = MaterialAlertDialogBuilder(context) + .setTitle(context.getString(R.string.live_stream)) + .setView(adjustLiveStreamView) + .setIcon(R.drawable.baseline_live_tv_24) + .setNegativeButton(context.resources.getString(R.string.dismiss)) { _: DialogInterface?, _: Int -> } + + adjustLiveStreamDialog.show() + } + }else { + adjustLiveStream.isVisible = false + } + val recodeVideo = view.findViewById(R.id.recode_video) recodeVideo.isChecked = items.all { it.videoPreferences.recodeVideo } recodeVideo.setOnCheckedChangeListener { _, _ -> 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 74f0cf7d..e3b8ebc1 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 @@ -76,7 +76,7 @@ class YTDLPUtil(private val context: Context) { } addOption("-P", FileUtil.getCachePath(context) + "/tmp") - if (sharedPreferences.getBoolean("no_check_certificates", true)) { + if (sharedPreferences.getBoolean("no_check_certificates", false)) { addOption("--no-check-certificates") } @@ -594,7 +594,9 @@ class YTDLPUtil(private val context: Context) { val downDir : File val canWrite = File(FileUtil.formatPath(downloadItem.downloadPath)).canWrite() - if (!sharedPreferences.getBoolean("cache_downloads", true) && canWrite){ + val writtenPath = type == DownloadViewModel.Type.command && downloadItem.format.format_note.contains("-P ") + + if (writtenPath || (!sharedPreferences.getBoolean("cache_downloads", true) && canWrite)){ downDir = File(FileUtil.formatPath(downloadItem.downloadPath)) request.addOption("--no-quiet") request.addOption("--no-simulate") @@ -648,7 +650,7 @@ class YTDLPUtil(private val context: Context) { } } - if (sharedPreferences.getBoolean("no_check_certificates", true)) { + if (sharedPreferences.getBoolean("no_check_certificates", false)) { request.addOption("--no-check-certificates") } @@ -671,7 +673,7 @@ class YTDLPUtil(private val context: Context) { request.addOption("--no-part") } - request.addOption("--trim-filenames", 254 - downDir.absolutePath.length) + request.addOption("--trim-filenames", 254/* - downDir.absolutePath.length*/) if (downloadItem.SaveThumb) { request.addOption("--write-thumbnail") @@ -705,13 +707,13 @@ class YTDLPUtil(private val context: Context) { } if(downloadItem.title.isNotBlank()){ - metadataCommands.addOption("--replace-in-metadata", "title", ".+", downloadItem.title.take(180)) + metadataCommands.addOption("--replace-in-metadata", "title", ".+", downloadItem.title) metadataCommands.addOption("--parse-metadata", "%(title)s:%(meta_title)s") } if (downloadItem.author.isNotBlank()){ - metadataCommands.addOption("--replace-in-metadata", "uploader", ".+", downloadItem.author.take(30)) + metadataCommands.addOption("--replace-in-metadata", "uploader", ".+", downloadItem.author) metadataCommands.addOption("--parse-metadata", "%(uploader)s:%(artist)s") } @@ -724,11 +726,7 @@ class YTDLPUtil(private val context: Context) { request.addOption("--force-keyframes-at-cuts") } } - filenameTemplate = if (filenameTemplate.isBlank()){ - "%(section_title&{} |)s%(title).170B" - }else{ - "%(section_title&{} |)s $filenameTemplate" - } + if (downloadItem.downloadSections.split(";").size > 1){ filenameTemplate = "%(autonumber)d. $filenameTemplate [%(section_start>%H∶%M∶%S)s]" } @@ -806,35 +804,53 @@ class YTDLPUtil(private val context: Context) { } request.addOption("-x") - val formatSorting = StringBuilder("hasaud") + 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}") + } + } + "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") { - formatSorting.append(",+br,+res,+fps") + if(formatSorting.contains("size")) { + formatSorting.remove("size") + } + formatSorting.addAll(0,listOf("+br", "+res", "+fps")) } if (abrSort.isNotBlank()){ - formatSorting.append(",abr:${abrSort}") + formatSorting.add(0, "abr:${abrSort}") } - formatSorting.append(",size") - - if (aCodecPref.isNotBlank()){ - formatSorting.append(",acodec:$aCodecPref") + if(formatSorting.isNotEmpty()) { + request.addOption("-S", formatSorting.joinToString(",")) } - if(ext.isNotBlank()){ - if(!ext.matches("(webm)|(Default)|(${context.getString(R.string.defaultValue)})".toRegex()) && supportedContainers.contains(ext)){ - request.addOption("--audio-format", ext) - formatSorting.append(",aext:$ext") - } - } - - if (preferredLanguage.isNotBlank()) { - formatSorting.append(",lang:${preferredLanguage}") - } request.addOption("-P", downDir.absolutePath) - request.addOption("-S", formatSorting.toString()) + val useArtistTags = if (downloadItem.url.isYoutubeURL()) "artists,artist," else "" if (downloadItem.author.isBlank()) { @@ -868,7 +884,7 @@ class YTDLPUtil(private val context: Context) { metadataCommands.addOption("--parse-metadata", "%(album_artist,first_artist|)s:%(album_artist)s") - metadataCommands.addOption("--parse-metadata", "description:(?:.+?Released\\ on\\s*(?P\\d{4}))?") + metadataCommands.addOption("--parse-metadata", "description:(?:.+?Released\\ on\\s*:\\s*(?P\\d{4}))?") metadataCommands.addOption("--parse-metadata", "%(dscrptn_year,release_year,release_date>%Y,upload_date>%Y)s:(?P\\d+)") if (isPlaylistItem) { @@ -1077,25 +1093,53 @@ class YTDLPUtil(private val context: Context) { val preferredLanguage = sharedPreferences.getString("audio_language","")!! - StringBuilder().apply { - if (downloadItem.format.format_id == context.resources.getString(R.string.worst_quality) || downloadItem.format.format_id == "worst") { - append(",+br,+res,+fps") - }else if (hasGenericResulutionFormat.isNotBlank()) { - append(",res:${hasGenericResulutionFormat}") + 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}") + } + } + "container" -> { + if (cont.isNotBlank()) formatSorting.add("vext:$cont") + if (acont.isNotBlank()) formatSorting.add("aext:$acont") + } } - if (sharedPreferences.getBoolean("prefer_smaller_formats", false)) append(",+size") - if (vCodecPref.isNotBlank()) append(",vcodec:$vCodecPref") - if (aCodecPref.isNotBlank()) append(",acodec:$aCodecPref") - if (cont.isNotBlank()) append(",vext:$cont") - if (acont.isNotBlank()) append(",aext:$acont") - if (abrSort.isNotBlank()) append(",abr~${abrSort}") - if (preferredLanguage.isNotBlank()) append(",lang:${preferredLanguage}") - if (this.isNotBlank()){ - request.addOption("-S", "+hasaud$this") + } + + 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 (abrSort.isNotBlank()) { + formatSorting.add("abr~${abrSort}") + } + + if (preferredLanguage.isNotBlank()) { + formatSorting.add("lang:${preferredLanguage}") + } + + if (formatSorting.isNotEmpty()) { + request.addOption("-S", formatSorting.joinToString(",")) + } + request.addOption("-f", f.toString().replace("/$".toRegex(), "")) if (downloadItem.videoPreferences.writeSubs){ @@ -1138,9 +1182,22 @@ class YTDLPUtil(private val context: Context) { } } + if (downloadItem.videoPreferences.liveFromStart) { + request.addOption("--live-from-start") + } + + downloadItem.videoPreferences.waitForVideoMinutes.apply { + if (this > 0) { + request.addOption("--wait-for-video", this * 60) + } + } + } DownloadViewModel.Type.command -> { - request.addOption("-P", downDir.absolutePath) + if (!writtenPath) { + request.addOption("-P", downDir.absolutePath) + } + request.addOption( "--config-locations", File(context.cacheDir.absolutePath + "/config[${downloadItem.id}].txt").apply { diff --git a/app/src/main/java/com/deniscerri/ytdl/work/DownloadWorker.kt b/app/src/main/java/com/deniscerri/ytdl/work/DownloadWorker.kt index 5aaef912..c170d17a 100644 --- a/app/src/main/java/com/deniscerri/ytdl/work/DownloadWorker.kt +++ b/app/src/main/java/com/deniscerri/ytdl/work/DownloadWorker.kt @@ -156,7 +156,8 @@ class DownloadWorker( notificationUtil.notify(downloadItem.id.toInt(), notification) CoroutineScope(Dispatchers.IO).launch { - val noCache = !sharedPreferences.getBoolean("cache_downloads", true) && File(FileUtil.formatPath(downloadItem.downloadPath)).canWrite() + val writtenPath = downloadItem.format.format_note.contains("-P ") + val noCache = writtenPath || (!sharedPreferences.getBoolean("cache_downloads", true) && File(FileUtil.formatPath(downloadItem.downloadPath)).canWrite()) val request = ytdlpUtil.buildYoutubeDLRequest(downloadItem) downloadItem.status = DownloadRepository.Status.Active.toString() diff --git a/app/src/main/java/com/deniscerri/ytdl/work/TerminalDownloadWorker.kt b/app/src/main/java/com/deniscerri/ytdl/work/TerminalDownloadWorker.kt index 5f5ffc37..abaa39d0 100644 --- a/app/src/main/java/com/deniscerri/ytdl/work/TerminalDownloadWorker.kt +++ b/app/src/main/java/com/deniscerri/ytdl/work/TerminalDownloadWorker.kt @@ -82,15 +82,22 @@ class TerminalDownloadWorker( } val commandPath = sharedPreferences.getString("command_path", FileUtil.getDefaultCommandPath())!! - val noCache = !sharedPreferences.getBoolean("cache_downloads", true) && File(FileUtil.formatPath(commandPath)).canWrite() - - if (!noCache){ - request.addOption("-P", FileUtil.getCachePath(context) + "TERMINAL/" + itemId) - }else if (!request.hasOption("-P")){ - request.addOption("-P", FileUtil.formatPath(commandPath)) + var noCache = !sharedPreferences.getBoolean("cache_downloads", true) && File(FileUtil.formatPath(commandPath)).canWrite() + + if (command.contains("-P ")) { + noCache = true + }else { + if (!noCache){ + request.addOption("-P", FileUtil.getCachePath(context) + "TERMINAL/" + itemId) + }else if (!request.hasOption("-P")){ + request.addOption("-P", FileUtil.formatPath(commandPath)) + } } + + + val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false) val initialLogDetails = "Terminal Task\n" + diff --git a/app/src/main/res/drawable/baseline_live_tv_24.xml b/app/src/main/res/drawable/baseline_live_tv_24.xml new file mode 100644 index 00000000..69c18f16 --- /dev/null +++ b/app/src/main/res/drawable/baseline_live_tv_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/adjust_video.xml b/app/src/main/res/layout/adjust_video.xml index f753550d..ffc076bc 100644 --- a/app/src/main/res/layout/adjust_video.xml +++ b/app/src/main/res/layout/adjust_video.xml @@ -110,12 +110,19 @@ app:layout_constraintTop_toTopOf="parent" /> + android:gravity="center" + android:text="@string/live_stream" + app:chipIconVisible="true" + app:chipIcon="@drawable/baseline_live_tv_24" + android:minWidth="30dp" + app:cornerRadius="10dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> @@ -162,6 +169,14 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + diff --git a/app/src/main/res/layout/filename_template_dialog.xml b/app/src/main/res/layout/filename_template_dialog.xml index c5bbb573..49684b35 100644 --- a/app/src/main/res/layout/filename_template_dialog.xml +++ b/app/src/main/res/layout/filename_template_dialog.xml @@ -27,7 +27,7 @@ android:id="@+id/filename_edittext" android:layout_width="match_parent" android:layout_height="wrap_content" - android:inputType="text" /> + android:inputType="text|textMultiLine" /> diff --git a/app/src/main/res/layout/livestream_download_preferences_dialog.xml b/app/src/main/res/layout/livestream_download_preferences_dialog.xml new file mode 100644 index 00000000..34cd11e1 --- /dev/null +++ b/app/src/main/res/layout/livestream_download_preferences_dialog.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0d00b259..5cdbeef2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -444,4 +444,11 @@ YT-DLP Youtube Liked Videos (needs cookies) YT-DLP Youtube Watch History (needs cookies) Suppress HTTPS certificate validation + Live Stream + Live From Start + Wait For Video + Retry Every + Minutes + Prefer Container over Codec For Audio Downloads + With this enabled, the preferred audio codec preference will be ignored and only container will change \ No newline at end of file diff --git a/app/src/main/res/xml/downloading_preferences.xml b/app/src/main/res/xml/downloading_preferences.xml index cd0bfa36..234a32b6 100644 --- a/app/src/main/res/xml/downloading_preferences.xml +++ b/app/src/main/res/xml/downloading_preferences.xml @@ -69,7 +69,7 @@ diff --git a/app/src/main/res/xml/processing_preferences.xml b/app/src/main/res/xml/processing_preferences.xml index e3e1e2a5..a7a78bd2 100644 --- a/app/src/main/res/xml/processing_preferences.xml +++ b/app/src/main/res/xml/processing_preferences.xml @@ -98,6 +98,65 @@ app:summary="@string/playlist_as_album_summary" app:title="@string/playlist_as_album" /> + + + + + + + + + + + + + + @@ -167,17 +226,8 @@ app:key="add_chapters" app:summary="@string/add_chapters_summary" app:title="@string/add_chapters" /> - - - + - - - - - - - - + + +