lot of features, forgor to note

This commit is contained in:
deniscerri 2025-09-21 14:24:04 +02:00
parent 8c254c95d6
commit c7a0079737
No known key found for this signature in database
GPG key ID: 95C43D517D830350
17 changed files with 161 additions and 100 deletions

View file

@ -37,60 +37,11 @@ jobs:
- name: Set current date as env variable - name: Set current date as env variable
run: echo "date_today=$(date +'%Y-%m-%d')" >> $GITHUB_ENV run: echo "date_today=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
# Create APK Debug
- name: Build apk debug project (APK)
run: ./gradlew assembleDebug
# Create APK Release # Create APK Release
- name: Build apk release project (APK) - name: Build apk release project (APK)
run: ./gradlew assemble run: ./gradlew assemble
# Upload Artifact Build # Upload Artifact Build
# Noted For Output [main_project_module]/build/outputs/apk/debug/
- name: Find Debug arm64
run: echo "APK_PATH=$(find ${{ env.main_project_module }}/build/outputs/apk/debug/ -type f -name '*arm64*.apk')" >> $GITHUB_ENV
- name: Upload APK Debug arm64
uses: actions/upload-artifact@v4
with:
name: ytdlnis-autogenerated-arm64-v8a-debug
path: ${{ env.APK_PATH }}
- name: Find Debug armeabiv7
run: echo "APK_PATH=$(find ${{ env.main_project_module }}/build/outputs/apk/debug/ -type f -name '*armeabi*.apk')" >> $GITHUB_ENV
- name: Upload APK Debug armeabiv7
uses: actions/upload-artifact@v4
with:
name: ytdlnis-autogenerated-armeabi-v7a-debug
path: ${{ env.APK_PATH }}
- name: Find Debug universal
run: echo "APK_PATH=$(find ${{ env.main_project_module }}/build/outputs/apk/debug/ -type f -name '*universal*.apk')" >> $GITHUB_ENV
- name: Upload APK Debug universal
uses: actions/upload-artifact@v4
with:
name: ytdlnis-autogenerated-universal-debug
path: ${{ env.APK_PATH }}
- name: Find Debug x86
run: echo "APK_PATH=$(find ${{ env.main_project_module }}/build/outputs/apk/debug/ -type f -name '*x86-*.apk')" >> $GITHUB_ENV
- name: Upload APK Debug x86
uses: actions/upload-artifact@v4
with:
name: ytdlnis-autogenerated-x86-debug
path: ${{ env.APK_PATH }}
- name: Find Debug x86_64
run: echo "APK_PATH=$(find ${{ env.main_project_module }}/build/outputs/apk/debug/ -type f -name '*x86_64*.apk')" >> $GITHUB_ENV
- name: Upload APK Debug x86_64
uses: actions/upload-artifact@v4
with:
name: ytdlnis-autogenerated-x86_64-debug
path: ${{ env.APK_PATH }}
# Noted For Output [main_project_module]/build/outputs/apk/release/ # Noted For Output [main_project_module]/build/outputs/apk/release/
- name: Find Release arm64 - name: Find Release arm64
run: echo "APK_PATH=$(find ${{ env.main_project_module }}/build/outputs/apk/release/ -type f -name '*arm64*.apk')" >> $GITHUB_ENV run: echo "APK_PATH=$(find ${{ env.main_project_module }}/build/outputs/apk/release/ -type f -name '*arm64*.apk')" >> $GITHUB_ENV
@ -137,13 +88,6 @@ jobs:
name: ytdlnis-autogenerated-x86_64-release name: ytdlnis-autogenerated-x86_64-release
path: ${{ env.APK_PATH }} path: ${{ env.APK_PATH }}
# Noted For Output [main_project_module]/build/outputs/apk/debug/
- name: Upload APK Debug
uses: actions/upload-artifact@v4
with:
name: YTDLnis APK debug generated
path: ${{ env.main_project_module }}/build/outputs/apk/debug/
# Noted For Output [main_project_module]/build/outputs/apk/release/ # Noted For Output [main_project_module]/build/outputs/apk/release/
- name: Upload APK Release - name: Upload APK Release
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@ -220,5 +164,4 @@ jobs:
# prerelease: true # prerelease: true
# files: | # files: |
# ${{ env.main_project_module }}/build/outputs/apk/release/* # ${{ env.main_project_module }}/build/outputs/apk/release/*
# ${{ env.main_project_module }}/build/outputs/apk/debug/*

View file

@ -374,10 +374,11 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
} }
}, },
extraCommandsClicked = { extraCommandsClicked = { returnValue ->
val callback = object : ExtraCommandsListener { val callback = object : ExtraCommandsListener {
override fun onChangeExtraCommand(c: String) { override fun onChangeExtraCommand(c: String) {
downloadItem.extraCommands = c downloadItem.extraCommands = c
returnValue(c)
} }
} }

View file

@ -591,13 +591,14 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
cutClicked = {}, cutClicked = {},
cutDisabledClicked = {}, cutDisabledClicked = {},
cutValueChanged = {}, cutValueChanged = {},
extraCommandsClicked = { extraCommandsClicked = { returnValue ->
val callback = object : ExtraCommandsListener { val callback = object : ExtraCommandsListener {
override fun onChangeExtraCommand(c: String) { override fun onChangeExtraCommand(c: String) {
items.forEach { it.extraCommands = c } items.forEach { it.extraCommands = c }
requireActivity().lifecycleScope.launch { requireActivity().lifecycleScope.launch {
items.forEach { downloadViewModel.updateDownload(it) } items.forEach { downloadViewModel.updateDownload(it) }
} }
returnValue(c)
bottomSheet.dismiss() bottomSheet.dismiss()
} }
} }
@ -696,11 +697,12 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
CoroutineScope(Dispatchers.IO).launch { items.forEach { downloadViewModel.updateDownload(it) } } CoroutineScope(Dispatchers.IO).launch { items.forEach { downloadViewModel.updateDownload(it) } }
}, },
alsoDownloadAsAudioClicked = {}, alsoDownloadAsAudioClicked = {},
extraCommandsClicked = { extraCommandsClicked = { returnValue ->
val callback = object : ExtraCommandsListener { val callback = object : ExtraCommandsListener {
override fun onChangeExtraCommand(c: String) { override fun onChangeExtraCommand(c: String) {
items.forEach { it.extraCommands = c } items.forEach { it.extraCommands = c }
CoroutineScope(Dispatchers.IO).launch { items.forEach { downloadViewModel.updateDownload(it) } } CoroutineScope(Dispatchers.IO).launch { items.forEach { downloadViewModel.updateDownload(it) } }
returnValue(c)
bottomSheet.dismiss() bottomSheet.dismiss()
} }
} }

View file

@ -457,10 +457,11 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
alsoDownloadAsAudioClicked = { alsoDownloadAsAudioClicked = {
downloadItem.videoPreferences.alsoDownloadAsAudio = it downloadItem.videoPreferences.alsoDownloadAsAudio = it
}, },
extraCommandsClicked = { extraCommandsClicked = { returnValue ->
val callback = object : ExtraCommandsListener { val callback = object : ExtraCommandsListener {
override fun onChangeExtraCommand(c: String) { override fun onChangeExtraCommand(c: String) {
downloadItem.extraCommands = c downloadItem.extraCommands = c
returnValue(c)
} }
} }

View file

@ -75,14 +75,10 @@ class WebViewActivity : BaseActivity() {
} }
toolbar.menu.children.firstOrNull { it.itemId == R.id.incognito }?.isChecked = incognito toolbar.menu.children.firstOrNull { it.itemId == R.id.incognito }?.isChecked = incognito
toolbar.menu.children.firstOrNull { it.itemId == R.id.get_data_sync_id }?.isVisible = false
toolbar.setOnMenuItemClickListener { m : MenuItem -> toolbar.setOnMenuItemClickListener { m : MenuItem ->
when(m.itemId) { when(m.itemId) {
R.id.get_data_sync_id -> {
webView?.evaluateJavascript("ytcfg.get('DATASYNC_ID')") { id ->
UiUtil.copyToClipboard(id.replace("\"", ""), this@WebViewActivity)
}
}
R.id.incognito -> { R.id.incognito -> {
intent.putExtra("incognito", !incognito) intent.putExtra("incognito", !incognito)
recreate() recreate()

View file

@ -492,7 +492,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
val builder = MaterialAlertDialogBuilder(requireContext()) val builder = MaterialAlertDialogBuilder(requireContext())
builder.setTitle(getString(R.string.restore)) builder.setTitle(getString(R.string.restore))
builder.setMessage("${getString(R.string.restore_complete)}\n $restoreDataMessage") builder.setMessage("${getString(R.string.restore_complete)}\n$restoreDataMessage")
builder.setCancelable(false) builder.setCancelable(false)
builder.setPositiveButton( builder.setPositiveButton(
getString(R.string.ok) getString(R.string.ok)

View file

@ -173,16 +173,24 @@ class TerminalFragment : Fragment() {
if (shortcutCount > 0){ if (shortcutCount > 0){
UiUtil.showShortcuts(requireActivity(), commandTemplateViewModel, UiUtil.showShortcuts(requireActivity(), commandTemplateViewModel,
itemSelected = {sh -> itemSelected = {sh ->
val txt = "${input.text} $sh" val txt = "${input.text.trim()} $sh"
input.setText(txt) input.setText(txt)
input.setSelection(input.text.length)
}, },
itemRemoved = {removed -> itemRemoved = {removed ->
input.setText(input.text.replace("(${Regex.escape(removed)})(?!.*\\1)".toRegex(), "").trimEnd()) input.setText(input.text.replace("(${Regex.escape(removed)})(?!.*\\1)".toRegex(), "").trim())
input.setSelection(input.text.length) input.setSelection(input.text.length)
}) })
} }
} }
} }
R.id.filename_template -> {
UiUtil.showFilenameTemplateDialog(requireActivity(), "") { filenameSelected ->
val txt = "${input.text.replace("-o\\s+(?:\"([^\"]+)\"|(\\S+))".toRegex(), "").trim()} -o \"$filenameSelected\""
input.setText(txt)
input.setSelection(input.text.length)
}
}
R.id.folder -> { R.id.folder -> {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)

View file

@ -24,12 +24,14 @@ import android.util.TypedValue
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewGroupOverlay
import android.view.ViewOutlineProvider import android.view.ViewOutlineProvider
import android.view.animation.Interpolator import android.view.animation.Interpolator
import android.widget.EditText import android.widget.EditText
import android.widget.ImageView import android.widget.ImageView
import android.widget.ScrollView import android.widget.ScrollView
import android.widget.TextView import android.widget.TextView
import androidx.annotation.OptIn
import androidx.annotation.Px import androidx.annotation.Px
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat import androidx.core.graphics.drawable.DrawableCompat
@ -44,8 +46,12 @@ import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesItem import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesItem
import com.deniscerri.ytdl.database.repository.DownloadRepository import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.database.repository.ObserveSourcesRepository.EveryCategory import com.deniscerri.ytdl.database.repository.ObserveSourcesRepository.EveryCategory
import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.badge.BadgeUtils
import com.google.android.material.badge.ExperimentalBadgeUtils
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.chip.Chip
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.neoutils.highlight.core.Highlight import com.neoutils.highlight.core.Highlight
import com.neoutils.highlight.core.scheme.TextColorScheme import com.neoutils.highlight.core.scheme.TextColorScheme
@ -284,6 +290,23 @@ object Extensions {
animator.start() animator.start()
} }
@OptIn(ExperimentalBadgeUtils::class)
fun Chip.createBadge(context: Context, nr: Int) {
this.overlay.clear()
if (nr > 0) {
val badge = BadgeDrawable.create(context).apply {
number = nr
backgroundColor = context.getColor(R.color.white)
verticalOffset = 25
horizontalOffset =
if (nr < 10) dp(App.instance.resources, 17f)
else if (nr < 100) dp(App.instance.resources, 19f)
else dp(App.instance.resources, 22f)
}
BadgeUtils.attachBadgeDrawable(badge, this)
}
}
fun TabLayout.Tab.createBadge(nr: Int){ fun TabLayout.Tab.createBadge(nr: Int){
removeBadge() removeBadge()
if (nr > 0) { if (nr > 0) {

View file

@ -67,6 +67,7 @@ import com.deniscerri.ytdl.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.YTDLPViewModel import com.deniscerri.ytdl.database.viewmodel.YTDLPViewModel
import com.deniscerri.ytdl.ui.downloadcard.VideoCutListener import com.deniscerri.ytdl.ui.downloadcard.VideoCutListener
import com.deniscerri.ytdl.util.Extensions.createBadge
import com.deniscerri.ytdl.util.Extensions.enableTextHighlight import com.deniscerri.ytdl.util.Extensions.enableTextHighlight
import com.deniscerri.ytdl.util.Extensions.getMediaDuration import com.deniscerri.ytdl.util.Extensions.getMediaDuration
import com.deniscerri.ytdl.util.Extensions.toStringDuration import com.deniscerri.ytdl.util.Extensions.toStringDuration
@ -1318,7 +1319,7 @@ object UiUtil {
recodeVideoClicked: (Boolean) -> Unit, recodeVideoClicked: (Boolean) -> Unit,
compatibilityModeClicked: (Boolean) -> Unit, compatibilityModeClicked: (Boolean) -> Unit,
alsoDownloadAsAudioClicked: (Boolean) -> Unit, alsoDownloadAsAudioClicked: (Boolean) -> Unit,
extraCommandsClicked: () -> Unit, extraCommandsClicked: (changed: (newExtraCommandString: String) -> Unit) -> Unit,
liveFromStart: (Boolean) -> Unit, liveFromStart: (Boolean) -> Unit,
waitForVideo: (Boolean, Int) -> Unit, waitForVideo: (Boolean, Int) -> Unit,
){ ){
@ -1362,6 +1363,18 @@ object UiUtil {
val adjustSubtitles = view.findViewById<Chip>(R.id.adjust_subtitles) val adjustSubtitles = view.findViewById<Chip>(R.id.adjust_subtitles)
fun calculateAdjustSubtitlesChangeCount() {
if (items.size == 1) {
val firstItem = items.first()
val count = listOf(
firstItem.videoPreferences.embedSubs,
firstItem.videoPreferences.writeSubs,
firstItem.videoPreferences.writeAutoSubs,
)
adjustSubtitles.createBadge(context, count.filter { it }.size)
}
}
calculateAdjustSubtitlesChangeCount()
adjustSubtitles.setOnClickListener { adjustSubtitles.setOnClickListener {
val adjustSubtitleView = context.layoutInflater.inflate(R.layout.subtitle_download_preferences_dialog, null) val adjustSubtitleView = context.layoutInflater.inflate(R.layout.subtitle_download_preferences_dialog, null)
val embedSubs = adjustSubtitleView.findViewById<MaterialSwitch>(R.id.embed_subtitles) val embedSubs = adjustSubtitleView.findViewById<MaterialSwitch>(R.id.embed_subtitles)
@ -1376,6 +1389,9 @@ object UiUtil {
embedSubs.setOnClickListener { embedSubs.setOnClickListener {
subtitleLanguages.isClickable = embedSubs.isChecked || saveSubtitles.isChecked subtitleLanguages.isClickable = embedSubs.isChecked || saveSubtitles.isChecked
embedSubsClicked(embedSubs.isChecked) embedSubsClicked(embedSubs.isChecked)
items.forEach { it.videoPreferences.embedSubs = embedSubs.isChecked }
calculateAdjustSubtitlesChangeCount()
} }
if (items.all { it.videoPreferences.writeSubs}) { if (items.all { it.videoPreferences.writeSubs}) {
@ -1391,11 +1407,15 @@ object UiUtil {
saveSubtitles.setOnCheckedChangeListener { _, _ -> saveSubtitles.setOnCheckedChangeListener { _, _ ->
subtitleLanguages.isClickable = embedSubs.isChecked || saveSubtitles.isChecked || saveAutoSubtitles.isChecked subtitleLanguages.isClickable = embedSubs.isChecked || saveSubtitles.isChecked || saveAutoSubtitles.isChecked
saveSubtitlesClicked(saveSubtitles.isChecked) saveSubtitlesClicked(saveSubtitles.isChecked)
items.forEach { it.videoPreferences.writeSubs = saveSubtitles.isChecked }
calculateAdjustSubtitlesChangeCount()
} }
saveAutoSubtitles.setOnCheckedChangeListener { _, _ -> saveAutoSubtitles.setOnCheckedChangeListener { _, _ ->
subtitleLanguages.isClickable = embedSubs.isChecked || saveSubtitles.isChecked || saveAutoSubtitles.isChecked subtitleLanguages.isClickable = embedSubs.isChecked || saveSubtitles.isChecked || saveAutoSubtitles.isChecked
saveAutoSubtitlesClicked(saveAutoSubtitles.isChecked) saveAutoSubtitlesClicked(saveAutoSubtitles.isChecked)
items.forEach { it.videoPreferences.writeAutoSubs = saveAutoSubtitles.isChecked }
calculateAdjustSubtitlesChangeCount()
} }
subtitleLanguages.isClickable = embedSubs.isChecked || saveSubtitles.isChecked subtitleLanguages.isClickable = embedSubs.isChecked || saveSubtitles.isChecked
@ -1424,12 +1444,19 @@ object UiUtil {
if (items.size == 1){ if (items.size == 1){
val adjustAudio = view.findViewById<Chip>(R.id.adjust_audio) val adjustAudio = view.findViewById<Chip>(R.id.adjust_audio)
fun calculateAdjustAudioChanges() {
val count = listOf(items.first().videoPreferences.removeAudio, items.first().videoPreferences.alsoDownloadAsAudio)
adjustAudio.createBadge(context, count.filter { it }.size)
}
calculateAdjustAudioChanges()
adjustAudio.setOnClickListener { adjustAudio.setOnClickListener {
val adjustAudioView = context.layoutInflater.inflate(R.layout.audio_download_preferences_dialog, null) val adjustAudioView = context.layoutInflater.inflate(R.layout.audio_download_preferences_dialog, null)
adjustAudioView.findViewById<MaterialSwitch>(R.id.remove_audio).apply { adjustAudioView.findViewById<MaterialSwitch>(R.id.remove_audio).apply {
isChecked = items.first().videoPreferences.removeAudio isChecked = items.first().videoPreferences.removeAudio
setOnCheckedChangeListener { _, b -> setOnCheckedChangeListener { _, b ->
removeAudioClicked(b) removeAudioClicked(b)
items.first().videoPreferences.removeAudio = b
calculateAdjustAudioChanges()
} }
} }
@ -1437,6 +1464,8 @@ object UiUtil {
isChecked = items.first().videoPreferences.alsoDownloadAsAudio isChecked = items.first().videoPreferences.alsoDownloadAsAudio
setOnCheckedChangeListener { _, b -> setOnCheckedChangeListener { _, b ->
alsoDownloadAsAudioClicked(b) alsoDownloadAsAudioClicked(b)
items.first().videoPreferences.alsoDownloadAsAudio = b
calculateAdjustAudioChanges()
} }
} }
@ -1462,6 +1491,13 @@ object UiUtil {
} }
val recodeVideo = view.findViewById<Chip>(R.id.recode_video) val recodeVideo = view.findViewById<Chip>(R.id.recode_video)
fun calculateRecodeVideoChanges() {
if (items.size == 1) {
val count = listOf(items.first().videoPreferences.recodeVideo, items.first().videoPreferences.compatibilityMode)
recodeVideo.createBadge(context, count.filter { it }.size)
}
}
calculateRecodeVideoChanges()
recodeVideo.setOnClickListener { recodeVideo.setOnClickListener {
val adjustVideoView = context.layoutInflater.inflate(R.layout.video_download_preferences_dialog, null) val adjustVideoView = context.layoutInflater.inflate(R.layout.video_download_preferences_dialog, null)
@ -1475,6 +1511,7 @@ object UiUtil {
compatibilityModeSwitch.isChecked = false compatibilityModeSwitch.isChecked = false
compatibilityModeClicked(false) compatibilityModeClicked(false)
recodeVideo.createBadge(context, if (isChecked) 1 else 0)
} }
} }
@ -1485,6 +1522,7 @@ object UiUtil {
recodeVideoSwitch.isChecked = false recodeVideoSwitch.isChecked = false
recodeVideoClicked(false) recodeVideoClicked(false)
recodeVideo.createBadge(context, if (isChecked) 1 else 0)
} }
} }
@ -1559,6 +1597,9 @@ object UiUtil {
val sponsorBlock = view.findViewById<Chip>(R.id.sponsorblock_filters) val sponsorBlock = view.findViewById<Chip>(R.id.sponsorblock_filters)
sponsorBlock.isEnabled = sharedPreferences.getBoolean("use_sponsorblock", true) sponsorBlock.isEnabled = sharedPreferences.getBoolean("use_sponsorblock", true)
if (items.size == 1 && sponsorBlock.isEnabled) {
sponsorBlock.createBadge(context, items.first().videoPreferences.sponsorBlockFilters.size)
}
sponsorBlock!!.setOnClickListener { sponsorBlock!!.setOnClickListener {
val builder = MaterialAlertDialogBuilder(context) val builder = MaterialAlertDialogBuilder(context)
builder.setTitle(context.getString(R.string.select_sponsorblock_filtering)) builder.setTitle(context.getString(R.string.select_sponsorblock_filtering))
@ -1583,6 +1624,9 @@ object UiUtil {
builder.setPositiveButton( builder.setPositiveButton(
context.getString(R.string.ok) context.getString(R.string.ok)
) { _: DialogInterface?, _: Int -> ) { _: DialogInterface?, _: Int ->
if (items.size == 1) {
sponsorBlock.createBadge(context, checkedItems.filter { it }.size)
}
sponsorBlockItemsSet(values, checkedItems) sponsorBlockItemsSet(values, checkedItems)
} }
@ -1658,10 +1702,18 @@ object UiUtil {
} }
val extraCommands = view.findViewById<Chip>(R.id.extra_commands) val extraCommands = view.findViewById<Chip>(R.id.extra_commands)
if (items.size == 1) {
extraCommands.createBadge(context, if (items.first().extraCommands.isNotBlank()) 1 else 0)
}
if (sharedPreferences.getBoolean("use_extra_commands", false)){ if (sharedPreferences.getBoolean("use_extra_commands", false)){
extraCommands.visibility = View.VISIBLE extraCommands.visibility = View.VISIBLE
extraCommands.setOnClickListener { extraCommands.setOnClickListener {
extraCommandsClicked() extraCommandsClicked { newExtraCommandString ->
items.forEach { it.extraCommands = newExtraCommandString }
if (items.size == 1) {
extraCommands.createBadge(context, if (newExtraCommandString.isNotBlank()) 1 else 0)
}
}
} }
}else{ }else{
extraCommands.visibility = View.GONE extraCommands.visibility = View.GONE
@ -1681,8 +1733,10 @@ object UiUtil {
cutClicked: (VideoCutListener) -> Unit, cutClicked: (VideoCutListener) -> Unit,
cutDisabledClicked: () -> Unit, cutDisabledClicked: () -> Unit,
cutValueChanged: (String) -> Unit, cutValueChanged: (String) -> Unit,
extraCommandsClicked: () -> Unit extraCommandsClicked: (changed: (newExtraCommandString: String) -> Unit) -> Unit
){ ){
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
val embedThumb = view.findViewById<Chip>(R.id.embed_thumb) val embedThumb = view.findViewById<Chip>(R.id.embed_thumb)
val cropThumb = view.findViewById<Chip>(R.id.crop_thumb) val cropThumb = view.findViewById<Chip>(R.id.crop_thumb)
@ -1751,6 +1805,10 @@ object UiUtil {
} }
val sponsorBlock = view.findViewById<Chip>(R.id.sponsorblock_filters) val sponsorBlock = view.findViewById<Chip>(R.id.sponsorblock_filters)
sponsorBlock.isEnabled = sharedPreferences.getBoolean("use_sponsorblock", true)
if (items.size == 1 && sponsorBlock.isEnabled) {
sponsorBlock.createBadge(context, items.first().videoPreferences.sponsorBlockFilters.size)
}
sponsorBlock!!.setOnClickListener { sponsorBlock!!.setOnClickListener {
val builder = MaterialAlertDialogBuilder(context) val builder = MaterialAlertDialogBuilder(context)
builder.setTitle(context.getString(R.string.select_sponsorblock_filtering)) builder.setTitle(context.getString(R.string.select_sponsorblock_filtering))
@ -1775,6 +1833,9 @@ object UiUtil {
builder.setPositiveButton( builder.setPositiveButton(
context.getString(R.string.ok) context.getString(R.string.ok)
) { _: DialogInterface?, _: Int -> ) { _: DialogInterface?, _: Int ->
if (items.size == 1) {
sponsorBlock.createBadge(context, checkedItems.filter { it }.size)
}
sponsorBlockItemsSet(values, checkedItems) sponsorBlockItemsSet(values, checkedItems)
} }
@ -1829,14 +1890,19 @@ object UiUtil {
} }
} }
val extraCommands = view.findViewById<Chip>(R.id.extra_commands) val extraCommands = view.findViewById<Chip>(R.id.extra_commands)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) if (items.size == 1) {
extraCommands.createBadge(context, if (items.first().extraCommands.isNotBlank()) 1 else 0)
}
if (sharedPreferences.getBoolean("use_extra_commands", false)){ if (sharedPreferences.getBoolean("use_extra_commands", false)){
extraCommands.visibility = View.VISIBLE extraCommands.visibility = View.VISIBLE
extraCommands.setOnClickListener { extraCommands.setOnClickListener {
extraCommandsClicked() extraCommandsClicked { newExtraCommandString ->
items.forEach { it.extraCommands = newExtraCommandString }
if (items.size == 1) {
extraCommands.createBadge(context, if (newExtraCommandString.isNotBlank()) 1 else 0)
}
}
} }
}else{ }else{
extraCommands.visibility = View.GONE extraCommands.visibility = View.GONE

View file

@ -133,7 +133,10 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
request.setYoutubeExtractorArgs(query) request.setYoutubeExtractorArgs(query)
} }
request.addOption("--flat-playlist") if (!sharedPreferences.getBoolean("no_flat_playlist", false)) {
request.addOption("--flat-playlist")
}
request.addOption("--lazy-playlist") request.addOption("--lazy-playlist")
request.addOption(if (singleItem) "-J" else "-j") request.addOption(if (singleItem) "-J" else "-j")
request.applyDefaultOptionsForFetchingData(if (query.isURL()) query else null) request.applyDefaultOptionsForFetchingData(if (query.isURL()) query else null)
@ -508,6 +511,7 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
if (formatProper.format_note.contains("storyboard", ignoreCase = true)) continue if (formatProper.format_note.contains("storyboard", ignoreCase = true)) continue
formatProper.format_note = formatProper.format_note.trim()
formatProper.container = format.getString("ext") formatProper.container = format.getString("ext")
if (formatProper.tbr == "None") formatProper.tbr = "" if (formatProper.tbr == "None") formatProper.tbr = ""
if (!formatProper.tbr.isNullOrBlank()){ if (!formatProper.tbr.isNullOrBlank()){
@ -817,9 +821,6 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
request.addOption("--socket-timeout", socketTimeout) request.addOption("--socket-timeout", socketTimeout)
} }
val sponsorblockURL = sharedPreferences.getString("sponsorblock_url", "")!!
if (sponsorblockURL.isNotBlank()) request.addOption("--sponsorblock-api", sponsorblockURL)
if (sharedPreferences.getBoolean("restrict_filenames", true)) request.addOption("--restrict-filenames") if (sharedPreferences.getBoolean("restrict_filenames", true)) request.addOption("--restrict-filenames")
if (sharedPreferences.getBoolean("force_ipv4", false)){ if (sharedPreferences.getBoolean("force_ipv4", false)){
request.addOption("-4") request.addOption("-4")
@ -1426,6 +1427,11 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
request.addOption(downloadItem.extraCommands) request.addOption(downloadItem.extraCommands)
} }
if (request.toString().contains("sponsorblock")) {
val sponsorBlockURL = sharedPreferences.getString("sponsorblock_url", "")!!
if (sponsorBlockURL.isNotBlank()) request.addOption("--sponsorblock-api", sponsorBlockURL)
}
val cache = File(FileUtil.getCachePath(context)) val cache = File(FileUtil.getCachePath(context))
cache.mkdirs() cache.mkdirs()
val conf = File(cache.absolutePath + "/${System.currentTimeMillis()}${UUID.randomUUID()}.txt") val conf = File(cache.absolutePath + "/${System.currentTimeMillis()}${UUID.randomUUID()}.txt")

View file

@ -118,7 +118,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:visibility="gone" android:visibility="gone"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="URL Regex" android:text="@string/url_regex"
android:background="@drawable/rounded_corner" android:background="@drawable/rounded_corner"
android:backgroundTint="?attr/colorTertiaryContainer" android:backgroundTint="?attr/colorTertiaryContainer"
android:clickable="false" android:clickable="false"
@ -130,8 +130,7 @@
app:cornerRadius="10dp" app:cornerRadius="10dp"
app:layout_constraintTop_toBottomOf="parent" app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"/>
tools:ignore="HardcodedText" />
</com.google.android.material.chip.ChipGroup> </com.google.android.material.chip.ChipGroup>

View file

@ -51,11 +51,10 @@
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
android:textSize="15sp" android:textSize="15sp"
android:textStyle="bold" android:textStyle="bold"
android:text="PO Token (GVS)" android:text="@string/potoken_gvs"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent" />
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/content_gvs" android:id="@+id/content_gvs"
@ -97,11 +96,10 @@
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
android:textSize="15sp" android:textSize="15sp"
android:textStyle="bold" android:textStyle="bold"
android:text="PO Token (Player)" android:text="@string/potoken_player"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"/>
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/content_player" android:id="@+id/content_player"
@ -143,11 +141,10 @@
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
android:textSize="15sp" android:textSize="15sp"
android:textStyle="bold" android:textStyle="bold"
android:text="PO Token (Subs)" android:text="@string/potoken_subs"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent" />
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/content_subs" android:id="@+id/content_subs"
@ -189,11 +186,10 @@
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
android:textSize="15sp" android:textSize="15sp"
android:textStyle="bold" android:textStyle="bold"
android:text="Visitor Data" android:text="@string/visitor_data"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"/>
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/content_visitordata" android:id="@+id/content_visitordata"

View file

@ -131,8 +131,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:text="@string/potoken" android:text="@string/potoken"/>
tools:ignore="HardcodedText" />
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:id="@+id/po_token_gvs" android:id="@+id/po_token_gvs"

View file

@ -11,6 +11,10 @@
android:icon="@drawable/ic_shortcut" android:icon="@drawable/ic_shortcut"
app:showAsAction="ifRoom" app:showAsAction="ifRoom"
android:id="@+id/shortcuts"/> android:id="@+id/shortcuts"/>
<item android:title="@string/file_name_template"
android:icon="@drawable/ic_edit"
app:showAsAction="ifRoom"
android:id="@+id/filename_template"/>
<item <item
android:id="@+id/folder" android:id="@+id/folder"
android:title="@string/command_directory" android:title="@string/command_directory"

View file

@ -5,8 +5,7 @@
<item <item
android:id="@+id/get_data_sync_id" android:id="@+id/get_data_sync_id"
android:title="Get Data Sync ID" android:title="@string/get_data_sync_id" />
tools:ignore="HardcodedText" />
<item <item
android:id="@+id/incognito" android:id="@+id/incognito"
@ -17,7 +16,7 @@
<item <item
android:id="@+id/desktop" android:id="@+id/desktop"
android:title="Desktop" android:title="@string/desktop"
android:checkable="true" android:checkable="true"
app:showAsAction="never" /> app:showAsAction="never" />

View file

@ -490,4 +490,13 @@
<string name="smallest">Smallest</string> <string name="smallest">Smallest</string>
<string name="largest">Largest</string> <string name="largest">Largest</string>
<string name="no_prefer_drc_audio">Don\'t prefer DRC Audio</string> <string name="no_prefer_drc_audio">Don\'t prefer DRC Audio</string>
<string name="potoken_gvs">PO Token (GVS)</string>
<string name="potoken_player">PO Token (Player)</string>
<string name="potoken_subs">PO Token (Subs)</string>
<string name="visitor_data">Visitor Data</string>
<string name="get_data_sync_id">Visitor Data</string>
<string name="desktop">Desktop</string>
<string name="url_regex">URL Regex</string>
<string name="disable_flat_playlist">Disable flat playlist</string>
<string name="disable_flat_playlist_summary">Don\'t use --flat-playlist. Slower data fetching, but more data rich</string>
</resources> </resources>

View file

@ -79,6 +79,15 @@
android:title="@string/disable_write_info_json" /> android:title="@string/disable_write_info_json" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/misc">
<SwitchPreferenceCompat
android:widgetLayout="@layout/preferece_material_switch"
android:icon="@drawable/ic_search"
android:key="no_flat_playlist"
android:summary="@string/disable_flat_playlist_summary"
android:title="@string/disable_flat_playlist" />
</PreferenceCategory>
<Preference <Preference
app:allowDividerAbove="true" app:allowDividerAbove="true"
app:icon="@drawable/baseline_reset_tv_24" app:icon="@drawable/baseline_reset_tv_24"