new features
added a header on cancelled, errored, saved, scheduled tabs to show the count of items and their own separate menus to copy the urls and delete them all fix app not starting a scheduled download when there were no paused items, strange ik add socket timeout in download settings fixed app not putting extra commands in the very end of the command list home screen channel tab filter bug fixes Add ability to Set default command template
This commit is contained in:
parent
02a5c0c253
commit
80672a2556
52 changed files with 371 additions and 142 deletions
|
|
@ -273,6 +273,9 @@ interface DownloadDao {
|
|||
@Query("UPDATE downloads SET downloadStartTime=0, status='Queued' where id in (:list)")
|
||||
suspend fun resetScheduleTimeForItems(list: List<Long>)
|
||||
|
||||
@Query("UPDATE downloads SET downloadStartTime=0, status='Queued' WHERE status = 'Scheduled'")
|
||||
suspend fun resetScheduleTimeForAllScheduledItems()
|
||||
|
||||
@Query("Update downloads SET status='Queued', downloadStartTime = 0 WHERE id in (:list)")
|
||||
suspend fun reQueueDownloadItems(list: List<Long>)
|
||||
|
||||
|
|
|
|||
|
|
@ -754,6 +754,11 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
repository.startDownloadWorker(emptyList(), application)
|
||||
}
|
||||
|
||||
suspend fun resetScheduleItemForAllScheduledItemsAndStartDownload() = CoroutineScope(Dispatchers.IO).launch {
|
||||
dbManager.downloadDao.resetScheduleTimeForAllScheduledItems()
|
||||
repository.startDownloadWorker(emptyList(), application)
|
||||
}
|
||||
|
||||
suspend fun putAtTopOfQueue(ids: List<Long>) = CoroutineScope(Dispatchers.IO).launch{
|
||||
val downloads = dao.getQueuedDownloadsListIDs()
|
||||
val lastID = ids.maxOf { it }
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
|
|||
val sortOrder = MutableLiveData(SORTING.DESC)
|
||||
val sortType = MutableLiveData(HistorySortType.DATE)
|
||||
val websiteFilter = MutableLiveData("")
|
||||
val statusFilter = MutableLiveData(HistoryStatus.UNSET)
|
||||
val statusFilter = MutableLiveData(HistoryStatus.ALL)
|
||||
private val queryFilter = MutableLiveData("")
|
||||
private val typeFilter = MutableLiveData("")
|
||||
|
||||
|
|
|
|||
|
|
@ -913,7 +913,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
|||
downloadViewModel.deleteDownload(id)
|
||||
|
||||
if (processingItemsCount > 0){
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_LONG)
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
processingItemsCount++
|
||||
|
|
@ -976,7 +976,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
|||
|
||||
|
||||
if (processingItemsCount > 0) {
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_LONG)
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
processingItemsCount++
|
||||
downloadViewModel.insert(deletedItem)
|
||||
|
|
|
|||
|
|
@ -6,17 +6,23 @@ import android.content.DialogInterface
|
|||
import android.content.SharedPreferences
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.get
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
|
@ -36,6 +42,7 @@ import com.deniscerri.ytdl.util.Extensions.forceFastScrollMode
|
|||
import com.deniscerri.ytdl.util.Extensions.toListString
|
||||
import com.deniscerri.ytdl.util.UiUtil
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
|
@ -60,6 +67,10 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
private var actionMode : ActionMode? = null
|
||||
private var totalSize = 0
|
||||
|
||||
private lateinit var listHeader : ConstraintLayout
|
||||
private lateinit var count : TextView
|
||||
private lateinit var headerMenuBtn : TextView
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
|
@ -72,7 +83,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
return fragmentView
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@SuppressLint("RestrictedApi", "SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
|
@ -100,8 +111,39 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
}
|
||||
}
|
||||
|
||||
listHeader = view.findViewById(R.id.list_header)
|
||||
count = view.findViewById(R.id.count)
|
||||
headerMenuBtn = view.findViewById(R.id.dropdown_menu)
|
||||
|
||||
headerMenuBtn.setOnClickListener {
|
||||
val popup = PopupMenu(activity, it)
|
||||
popup.menuInflater.inflate(R.menu.cancelled_header_menu, popup.menu)
|
||||
popup.setOnMenuItemClickListener { m ->
|
||||
when(m.itemId){
|
||||
R.id.delete_all -> {
|
||||
UiUtil.showGenericDeleteAllDialog(requireContext()) {
|
||||
downloadViewModel.deleteCancelled()
|
||||
}
|
||||
}
|
||||
R.id.copy_urls -> {
|
||||
lifecycleScope.launch {
|
||||
val urls = withContext(Dispatchers.IO){
|
||||
downloadViewModel.getURLsByStatus(listOf(DownloadRepository.Status.Cancelled))
|
||||
}
|
||||
UiUtil.copyToClipboard(urls.joinToString("\n"), requireActivity())
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
popup.show()
|
||||
}
|
||||
|
||||
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Cancelled)).observe(viewLifecycleOwner){
|
||||
totalSize = it
|
||||
listHeader.isVisible = it > 0
|
||||
count.text = "$it ${getString(R.string.items)}"
|
||||
noResults.visibility = if (it == 0) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
|
@ -331,7 +373,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
downloadViewModel.getItemByID(itemID)
|
||||
}
|
||||
downloadViewModel.deleteDownload(deletedItem.id)
|
||||
Snackbar.make(cancelledRecyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title.ifEmpty { deletedItem.url }, Snackbar.LENGTH_LONG)
|
||||
Snackbar.make(cancelledRecyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title.ifEmpty { deletedItem.url }, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
downloadViewModel.insert(deletedItem)
|
||||
}.show()
|
||||
|
|
|
|||
|
|
@ -208,54 +208,15 @@ class DownloadQueueMainFragment : Fragment(){
|
|||
try{
|
||||
when(m.itemId){
|
||||
R.id.clear_all -> {
|
||||
showDeleteDialog {
|
||||
UiUtil.showGenericDeleteAllDialog(requireContext()) {
|
||||
downloadViewModel.deleteAll()
|
||||
}
|
||||
}
|
||||
R.id.clear_queue -> {
|
||||
showDeleteDialog {
|
||||
UiUtil.showGenericDeleteAllDialog(requireContext()) {
|
||||
downloadViewModel.cancelAllDownloads()
|
||||
}
|
||||
}
|
||||
R.id.clear_cancelled -> {
|
||||
showDeleteDialog {
|
||||
downloadViewModel.deleteCancelled()
|
||||
}
|
||||
}
|
||||
R.id.clear_scheduled -> {
|
||||
showDeleteDialog {
|
||||
downloadViewModel.deleteScheduled()
|
||||
}
|
||||
}
|
||||
R.id.clear_errored -> {
|
||||
showDeleteDialog {
|
||||
downloadViewModel.deleteErrored()
|
||||
}
|
||||
}
|
||||
R.id.clear_saved -> {
|
||||
showDeleteDialog {
|
||||
downloadViewModel.deleteSaved()
|
||||
}
|
||||
}
|
||||
R.id.copy_urls -> {
|
||||
lifecycleScope.launch {
|
||||
val tabStatus = mapOf(
|
||||
0 to listOf(DownloadRepository.Status.Active),
|
||||
1 to listOf(DownloadRepository.Status.Queued),
|
||||
2 to listOf(DownloadRepository.Status.Scheduled),
|
||||
3 to listOf(DownloadRepository.Status.Cancelled),
|
||||
4 to listOf(DownloadRepository.Status.Error),
|
||||
5 to listOf(DownloadRepository.Status.Saved),
|
||||
)
|
||||
tabStatus[tabLayout.selectedTabPosition]?.apply {
|
||||
val urls = withContext(Dispatchers.IO){
|
||||
downloadViewModel.getURLsByStatus(this@apply)
|
||||
}
|
||||
UiUtil.copyToClipboard(urls.joinToString("\n"), requireActivity())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}catch (e: Exception){
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
|
|
@ -265,16 +226,6 @@ class DownloadQueueMainFragment : Fragment(){
|
|||
}
|
||||
}
|
||||
|
||||
private fun showDeleteDialog (deleteClicked: (deleteClicked: Boolean) -> Unit){
|
||||
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
|
||||
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
|
||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
deleteClicked(true)
|
||||
}
|
||||
deleteDialog.show()
|
||||
}
|
||||
|
||||
fun scrollToActive(){
|
||||
tabLayout.getTabAt(0)!!.select()
|
||||
viewPager2.setCurrentItem(0, true)
|
||||
|
|
|
|||
|
|
@ -14,10 +14,14 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.AdapterView.OnItemClickListener
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
|
@ -60,6 +64,11 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
private lateinit var adapter : GenericDownloadAdapter
|
||||
private var actionMode : ActionMode? = null
|
||||
private var totalSize: Int = 0
|
||||
|
||||
private lateinit var listHeader : ConstraintLayout
|
||||
private lateinit var count : TextView
|
||||
private lateinit var headerMenuBtn : TextView
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
|
@ -72,7 +81,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
return fragmentView
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@SuppressLint("RestrictedApi", "SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
|
@ -100,8 +109,39 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
}
|
||||
}
|
||||
|
||||
listHeader = view.findViewById(R.id.list_header)
|
||||
count = view.findViewById(R.id.count)
|
||||
headerMenuBtn = view.findViewById(R.id.dropdown_menu)
|
||||
|
||||
headerMenuBtn.setOnClickListener {
|
||||
val popup = PopupMenu(activity, it)
|
||||
popup.menuInflater.inflate(R.menu.errored_header_menu, popup.menu)
|
||||
popup.setOnMenuItemClickListener { m ->
|
||||
when(m.itemId){
|
||||
R.id.delete_all -> {
|
||||
UiUtil.showGenericDeleteAllDialog(requireContext()) {
|
||||
downloadViewModel.deleteErrored()
|
||||
}
|
||||
}
|
||||
R.id.copy_urls -> {
|
||||
lifecycleScope.launch {
|
||||
val urls = withContext(Dispatchers.IO){
|
||||
downloadViewModel.getURLsByStatus(listOf(DownloadRepository.Status.Error))
|
||||
}
|
||||
UiUtil.copyToClipboard(urls.joinToString("\n"), requireActivity())
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
popup.show()
|
||||
}
|
||||
|
||||
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Error)).observe(viewLifecycleOwner){
|
||||
totalSize = it
|
||||
listHeader.isVisible = it > 0
|
||||
count.text = "$it ${getString(R.string.items)}"
|
||||
noResults.visibility = if (it == 0) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
|
@ -334,7 +374,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
downloadViewModel.getItemByID(itemID)
|
||||
}
|
||||
downloadViewModel.deleteDownload(deletedItem.id)
|
||||
Snackbar.make(erroredRecyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title.ifEmpty { deletedItem.url }, Snackbar.LENGTH_LONG)
|
||||
Snackbar.make(erroredRecyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title.ifEmpty { deletedItem.url }, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
downloadViewModel.insert(deletedItem)
|
||||
}.show()
|
||||
|
|
|
|||
|
|
@ -684,7 +684,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
}
|
||||
|
||||
if (!deleteFile){
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_LONG)
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
historyViewModel.insert(deletedItem)
|
||||
}.show()
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ class QueuedDownloadsFragment : Fragment(), QueuedDownloadAdapter.OnItemClickLis
|
|||
downloadViewModel.updateDownload(item)
|
||||
}
|
||||
|
||||
Snackbar.make(queuedRecyclerView, getString(R.string.cancelled) + ": " + item.title.ifEmpty { item.url }, Snackbar.LENGTH_LONG)
|
||||
Snackbar.make(queuedRecyclerView, getString(R.string.cancelled) + ": " + item.title.ifEmpty { item.url }, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
downloadViewModel.deleteDownload(item.id)
|
||||
|
|
|
|||
|
|
@ -12,11 +12,15 @@ import android.view.Menu
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
|
@ -59,6 +63,11 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
private lateinit var noResults: RelativeLayout
|
||||
private var actionMode : ActionMode? = null
|
||||
private var totalSize : Int = 0
|
||||
|
||||
private lateinit var listHeader : ConstraintLayout
|
||||
private lateinit var count : TextView
|
||||
private lateinit var headerMenuBtn : TextView
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
|
@ -71,7 +80,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
return fragmentView
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@SuppressLint("RestrictedApi", "SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
|
@ -100,8 +109,40 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
}
|
||||
}
|
||||
|
||||
listHeader = view.findViewById(R.id.list_header)
|
||||
count = view.findViewById(R.id.count)
|
||||
headerMenuBtn = view.findViewById(R.id.dropdown_menu)
|
||||
|
||||
headerMenuBtn.setOnClickListener {
|
||||
val popup = PopupMenu(activity, it)
|
||||
popup.menuInflater.inflate(R.menu.saved_header_menu, popup.menu)
|
||||
popup.setOnMenuItemClickListener { m ->
|
||||
when(m.itemId){
|
||||
R.id.delete_all -> {
|
||||
UiUtil.showGenericDeleteAllDialog(requireContext()) {
|
||||
downloadViewModel.deleteSaved()
|
||||
}
|
||||
}
|
||||
R.id.copy_urls -> {
|
||||
lifecycleScope.launch {
|
||||
val urls = withContext(Dispatchers.IO){
|
||||
downloadViewModel.getURLsByStatus(listOf(DownloadRepository.Status.Saved))
|
||||
}
|
||||
UiUtil.copyToClipboard(urls.joinToString("\n"), requireActivity())
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
popup.show()
|
||||
}
|
||||
|
||||
|
||||
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Saved)).observe(viewLifecycleOwner){
|
||||
totalSize = it
|
||||
listHeader.isVisible = it > 0
|
||||
count.text = "$it ${getString(R.string.items)}"
|
||||
noResults.visibility = if (it == 0) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
|
@ -321,7 +362,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
downloadViewModel.getItemByID(itemID)
|
||||
}
|
||||
downloadViewModel.deleteDownload(deletedItem.id)
|
||||
Snackbar.make(savedRecyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title.ifEmpty { deletedItem.url }, Snackbar.LENGTH_LONG)
|
||||
Snackbar.make(savedRecyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title.ifEmpty { deletedItem.url }, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
downloadViewModel.insert(deletedItem)
|
||||
}.show()
|
||||
|
|
|
|||
|
|
@ -12,11 +12,15 @@ import android.view.Menu
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
|
@ -61,6 +65,10 @@ class ScheduledDownloadsFragment : Fragment(), ScheduledDownloadAdapter.OnItemCl
|
|||
private var actionMode : ActionMode? = null
|
||||
private var totalSize = 0
|
||||
|
||||
private lateinit var listHeader : ConstraintLayout
|
||||
private lateinit var count : TextView
|
||||
private lateinit var headerMenuBtn : TextView
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
|
@ -73,7 +81,7 @@ class ScheduledDownloadsFragment : Fragment(), ScheduledDownloadAdapter.OnItemCl
|
|||
return fragmentView
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@SuppressLint("RestrictedApi", "SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
|
@ -101,9 +109,47 @@ class ScheduledDownloadsFragment : Fragment(), ScheduledDownloadAdapter.OnItemCl
|
|||
}
|
||||
}
|
||||
|
||||
listHeader = view.findViewById(R.id.list_header)
|
||||
count = view.findViewById(R.id.count)
|
||||
headerMenuBtn = view.findViewById(R.id.dropdown_menu)
|
||||
|
||||
headerMenuBtn.setOnClickListener {
|
||||
val popup = PopupMenu(activity, it)
|
||||
popup.menuInflater.inflate(R.menu.scheduled_header_menu, popup.menu)
|
||||
popup.setOnMenuItemClickListener { m ->
|
||||
when(m.itemId){
|
||||
R.id.download_now -> {
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO){
|
||||
downloadViewModel.resetScheduleItemForAllScheduledItemsAndStartDownload()
|
||||
}
|
||||
}
|
||||
}
|
||||
R.id.delete_all -> {
|
||||
UiUtil.showGenericDeleteAllDialog(requireContext()) {
|
||||
downloadViewModel.deleteScheduled()
|
||||
}
|
||||
}
|
||||
R.id.copy_urls -> {
|
||||
lifecycleScope.launch {
|
||||
val urls = withContext(Dispatchers.IO){
|
||||
downloadViewModel.getURLsByStatus(listOf(DownloadRepository.Status.Scheduled))
|
||||
}
|
||||
UiUtil.copyToClipboard(urls.joinToString("\n"), requireActivity())
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
popup.show()
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
downloadViewModel.scheduledDownloadsCount.collectLatest {
|
||||
totalSize = it
|
||||
listHeader.isVisible = it > 0
|
||||
count.text = "$it ${getString(R.string.items)}"
|
||||
noResults.visibility = if (it == 0) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
|
@ -336,7 +382,7 @@ class ScheduledDownloadsFragment : Fragment(), ScheduledDownloadAdapter.OnItemCl
|
|||
downloadViewModel.getItemByID(itemID)
|
||||
}
|
||||
downloadViewModel.deleteDownload(deletedItem.id)
|
||||
Snackbar.make(scheduledRecyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title.ifEmpty { deletedItem.url }, Snackbar.LENGTH_LONG)
|
||||
Snackbar.make(scheduledRecyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title.ifEmpty { deletedItem.url }, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
downloadViewModel.insert(deletedItem)
|
||||
}.show()
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ class DownloadLogListFragment : Fragment(), DownloadLogsAdapter.OnItemClickListe
|
|||
logViewModel.getItemById(items[position].id)
|
||||
}
|
||||
logViewModel.delete(deletedItem)
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_LONG)
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
lifecycleScope.launch(Dispatchers.IO){
|
||||
logViewModel.insert(deletedItem)
|
||||
|
|
|
|||
|
|
@ -1637,6 +1637,16 @@ object UiUtil {
|
|||
deleteDialog.show()
|
||||
}
|
||||
|
||||
fun showGenericDeleteAllDialog(context: Context, accepted: () -> Unit){
|
||||
val deleteDialog = MaterialAlertDialogBuilder(context)
|
||||
deleteDialog.setTitle(context.getString(R.string.you_are_going_to_delete_multiple_items))
|
||||
deleteDialog.setNegativeButton(context.getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
deleteDialog.setPositiveButton(context.getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
accepted()
|
||||
}
|
||||
deleteDialog.show()
|
||||
}
|
||||
|
||||
fun showRemoveHistoryItemDialog(item: HistoryItem, context: Activity, delete: (item: HistoryItem, deleteFile: Boolean) -> Unit){
|
||||
val deleteFile = booleanArrayOf(false)
|
||||
val deleteDialog = MaterialAlertDialogBuilder(context)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,8 @@ class YTDLPUtil(private val context: Context) {
|
|||
request.addOption("--skip-download")
|
||||
request.addOption("-R", "1")
|
||||
request.addOption("--compat-options", "manifest-filesize-approx")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
val socketTimeout = sharedPreferences.getString("socket_timeout", "5")!!.ifEmpty { "5" }
|
||||
request.addOption("--socket-timeout", socketTimeout)
|
||||
|
||||
if (sharedPreferences.getBoolean("force_ipv4", false)){
|
||||
request.addOption("-4")
|
||||
|
|
@ -240,7 +241,8 @@ class YTDLPUtil(private val context: Context) {
|
|||
request.addOption("-a", urlsFile.absolutePath)
|
||||
request.addOption("--skip-download")
|
||||
request.addOption("-R", "1")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
val socketTimeout = sharedPreferences.getString("socket_timeout", "5")!!.ifEmpty { "5" }
|
||||
request.addOption("--socket-timeout", socketTimeout)
|
||||
|
||||
if (sharedPreferences.getBoolean("force_ipv4", false)){
|
||||
request.addOption("-4")
|
||||
|
|
@ -435,7 +437,8 @@ class YTDLPUtil(private val context: Context) {
|
|||
request.addOption("--print", "%(.{urls,chapters})s")
|
||||
request.addOption("--skip-download")
|
||||
request.addOption("-R", "1")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
val socketTimeout = sharedPreferences.getString("socket_timeout", "5")!!.ifEmpty { "5" }
|
||||
request.addOption("--socket-timeout", socketTimeout)
|
||||
|
||||
if (sharedPreferences.getBoolean("force_ipv4", false)){
|
||||
request.addOption("-4")
|
||||
|
|
@ -524,6 +527,7 @@ class YTDLPUtil(private val context: Context) {
|
|||
@SuppressLint("RestrictedApi")
|
||||
fun buildYoutubeDLRequest(downloadItem: DownloadItem) : YoutubeDLRequest {
|
||||
val useItemURL = sharedPreferences.getBoolean("use_itemurl_instead_playlisturl", false)
|
||||
var isPlaylistItem = false
|
||||
|
||||
val request = if (downloadItem.url.endsWith(".txt")) {
|
||||
YoutubeDLRequest(listOf()).apply {
|
||||
|
|
@ -532,6 +536,7 @@ class YTDLPUtil(private val context: Context) {
|
|||
}else if (downloadItem.playlistURL.isNullOrBlank() || downloadItem.playlistTitle.isBlank() || useItemURL){
|
||||
YoutubeDLRequest(downloadItem.url)
|
||||
}else{
|
||||
isPlaylistItem = true
|
||||
YoutubeDLRequest(downloadItem.playlistURL!!).apply {
|
||||
if(downloadItem.playlistIndex == null){
|
||||
val matchPortion = downloadItem.url.split("/").last().split("=").last().split("&").first()
|
||||
|
|
@ -588,6 +593,11 @@ class YTDLPUtil(private val context: Context) {
|
|||
request.addOption("--no-resize-buffer")
|
||||
}
|
||||
|
||||
val socketTimeout = sharedPreferences.getString("socket_timeout", "")!!
|
||||
if (socketTimeout.isNotBlank()) {
|
||||
request.addOption("--socket-timeout", socketTimeout)
|
||||
}
|
||||
|
||||
val sponsorblockURL = sharedPreferences.getString("sponsorblock_url", "")!!
|
||||
if (sponsorblockURL.isNotBlank()) request.addOption("--sponsorblock-api", sponsorblockURL)
|
||||
|
||||
|
|
@ -801,9 +811,10 @@ class YTDLPUtil(private val context: Context) {
|
|||
metadataCommands.addOption("--parse-metadata", "description:(?:Released on: )(?P<dscrptn_year>\\d{4})")
|
||||
metadataCommands.addOption("--parse-metadata", "%(dscrptn_year,release_year,release_date>%Y,upload_date>%Y)s:(?P<meta_date>\\d+)")
|
||||
metadataCommands.addOption("--parse-metadata", "%(album_artist,first_artist|)s:%(album_artist)s")
|
||||
metadataCommands.addOption("--parse-metadata", "%(track_number,playlist_index)d:(?P<track_number>\\d+)")
|
||||
|
||||
|
||||
if (isPlaylistItem) {
|
||||
metadataCommands.addOption("--parse-metadata", "%(track_number,playlist_index)d:(?P<track_number>\\d+)")
|
||||
}
|
||||
}
|
||||
|
||||
val cropThumb = downloadItem.audioPreferences.cropThumb ?: sharedPreferences.getBoolean("crop_thumbnail", true)
|
||||
|
|
@ -1081,21 +1092,21 @@ class YTDLPUtil(private val context: Context) {
|
|||
else -> {}
|
||||
}
|
||||
|
||||
if (metadataCommands.isNotEmpty()){
|
||||
request.addCommands(metadataCommands)
|
||||
}
|
||||
|
||||
if (downloadItem.extraCommands.isNotBlank() && downloadItem.type != DownloadViewModel.Type.command){
|
||||
val cache = File(FileUtil.getCachePath(context))
|
||||
cache.mkdirs()
|
||||
val conf = File(cache.absolutePath + "/${System.currentTimeMillis()}${UUID.randomUUID()}.txt")
|
||||
conf.createNewFile()
|
||||
conf.writeText(downloadItem.extraCommands)
|
||||
request.addOption(
|
||||
"--config-locations",
|
||||
conf.absolutePath
|
||||
)
|
||||
val tmp = mutableListOf<String>()
|
||||
tmp.addOption("--config-locations", conf.absolutePath)
|
||||
request.addCommands(tmp)
|
||||
}
|
||||
|
||||
if (metadataCommands.isNotEmpty()){
|
||||
request.addCommands(metadataCommands)
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
|
|
@ -1103,8 +1114,8 @@ class YTDLPUtil(private val context: Context) {
|
|||
val playerClient = sharedPreferences.getString("youtube_player_client", "default,mediaconnect")!!
|
||||
.ifEmpty { "default,mediaconnect" }
|
||||
val extractorArgs = mutableListOf<String>()
|
||||
extractorArgs.add("player_client:${playerClient}")
|
||||
val lang = sharedPreferences.getString("app_language", "en")
|
||||
extractorArgs.add("player_client=${playerClient}")
|
||||
val lang = Locale.getDefault().language
|
||||
if (context.getStringArray(R.array.subtitle_langs).contains(lang)) {
|
||||
extractorArgs.add("lang=$lang")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ class DownloadWorker(
|
|||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val time = System.currentTimeMillis() + 6000
|
||||
val queuedItems = dao.getQueuedScheduledDownloadsUntil(time)
|
||||
val priorityItemIDs = inputData.getLongArray("priority_item_ids")!!.toMutableList()
|
||||
val priorityItemIDs = (inputData.getLongArray("priority_item_ids") ?: longArrayOf()).toMutableList()
|
||||
val continueAfterPriorityIds = inputData.getBoolean("continue_after_priority_ids", true)
|
||||
|
||||
// this is needed for observe sources call, so it wont create result items
|
||||
|
|
|
|||
5
app/src/main/res/drawable/baseline_more_horiz_24.xml
Normal file
5
app/src/main/res/drawable/baseline_more_horiz_24.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
|
||||
|
||||
</vector>
|
||||
|
|
@ -1,10 +1,46 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/list_header"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingVertical="10dp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dropdown_menu"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:paddingVertical="10dp"
|
||||
android:paddingHorizontal="20dp"
|
||||
app:drawableStartCompat="@drawable/baseline_more_horiz_24"
|
||||
app:drawableTint="?android:textColorPrimary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toEndOf="@id/count"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView android:id="@+id/download_recyclerview"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -16,4 +52,4 @@
|
|||
<include layout="@layout/no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</LinearLayout>
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
<LinearLayout
|
||||
android:id="@+id/format_filter_linear"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
|
@ -66,7 +67,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="@string/websites"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
|
|
|||
13
app/src/main/res/menu/cancelled_header_menu.xml
Normal file
13
app/src/main/res/menu/cancelled_header_menu.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/delete_all"
|
||||
android:title="@string/clear_cancelled"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/copy_urls"
|
||||
android:title="@string/copy_urls"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
|
|
@ -7,42 +7,9 @@
|
|||
android:icon="@drawable/ic_delete_all"
|
||||
android:title="@string/remove_downloading"
|
||||
app:showAsAction="never" />
|
||||
|
||||
|
||||
<item
|
||||
android:id="@+id/clear_cancelled"
|
||||
android:icon="@drawable/ic_delete_all"
|
||||
android:title="@string/clear_cancelled"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/clear_scheduled"
|
||||
android:icon="@drawable/ic_delete_all"
|
||||
android:title="@string/clear_scheduled"
|
||||
app:showAsAction="never" />
|
||||
|
||||
|
||||
<item
|
||||
android:id="@+id/clear_errored"
|
||||
android:icon="@drawable/ic_delete_all"
|
||||
android:title="@string/clear_errored"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/clear_saved"
|
||||
android:icon="@drawable/ic_delete_all"
|
||||
android:title="@string/clear_saved"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/clear_all"
|
||||
android:icon="@drawable/ic_delete_all"
|
||||
android:title="@string/remove_all"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/copy_urls"
|
||||
android:icon="@drawable/ic_delete_all"
|
||||
android:title="@string/copy_urls"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
13
app/src/main/res/menu/errored_header_menu.xml
Normal file
13
app/src/main/res/menu/errored_header_menu.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/delete_all"
|
||||
android:title="@string/clear_errored"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/copy_urls"
|
||||
android:title="@string/copy_urls"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
13
app/src/main/res/menu/saved_header_menu.xml
Normal file
13
app/src/main/res/menu/saved_header_menu.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/delete_all"
|
||||
android:title="@string/clear_saved"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/copy_urls"
|
||||
android:title="@string/copy_urls"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
19
app/src/main/res/menu/scheduled_header_menu.xml
Normal file
19
app/src/main/res/menu/scheduled_header_menu.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/download_now"
|
||||
android:title="@string/download_now"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/delete_all"
|
||||
android:title="@string/clear_scheduled"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/copy_urls"
|
||||
android:title="@string/copy_urls"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
|
|
@ -409,7 +409,7 @@
|
|||
<string name="use_alarm_manager">استخدام AlarmManager بدلًا من WorkManager</string>
|
||||
<string name="use_alarm_manager_summary">يتعين تمكين هذا الخيار عندما تكون أداة الـ WorkManager مقيدًة من قبل مُصنِّع الجهاز أو إذا كانت المهام المجدولة ليست دقيقة جدًا</string>
|
||||
<string name="use_item_url_not_playlist">استخدام رابط العنصر بدلًا من رابط قائمة التشغيل</string>
|
||||
<string name="use_item_url_not_playlist_summary">مفيد لقوائم تشغيل LibreTube غير المتصلة بالإنترنت والتي لا يتعرف عليها yt-dlp، لن يتم تضمين البيانات الوصفية لقائمة التشغيل مع تمكين هذا الخيار</string>
|
||||
<string name="use_item_url_not_playlist_summary">لن يتم تضمين البيانات الوصفية لقائمة التشغيل مع تمكين هذا الخيار</string>
|
||||
<string name="recode_video">إعادة ترميز الفيديو</string>
|
||||
<string name="recode_video_summary">يعيد ترميز ملف الفيديو إلى تنسيق الفيديو المحدد</string>
|
||||
<string name="daily">يوميًا</string>
|
||||
|
|
|
|||
|
|
@ -418,6 +418,6 @@
|
|||
<string name="recode_video">Прекодиране на видео</string>
|
||||
<string name="recode_video_summary">Перекодира видео файлът в указания видеоформат</string>
|
||||
<string name="format_importance_note">Подреждане важността на елемента на формат. Това подреждане ще се използва, само когато приложението извлече форматите от картата за изтегляне и автоматично избере формата!</string>
|
||||
<string name="use_item_url_not_playlist_summary">Полезно за офлайн плейлисти Libretube, които не се разпознават от yt-dlp. Метаданните на плейлиста няма да бъдат вградени, ако функция та е включена</string>
|
||||
<string name="use_item_url_not_playlist_summary">Метаданните на плейлиста няма да бъдат вградени, ако функция та е включена</string>
|
||||
<string name="data_fetching_extractor_youtube">Екстрактор за извличане на данни (YouTube)</string>
|
||||
</resources>
|
||||
|
|
@ -409,7 +409,7 @@
|
|||
<string name="use_alarm_manager">Použít AlarmManager místo WorkManageru pro plánování</string>
|
||||
<string name="use_alarm_manager_summary">Funkci povolte, pokud je WorkManager omezen výrobcem zařízení nebo pokud naplánované úlohy nejsou příliš přesné</string>
|
||||
<string name="use_item_url_not_playlist">Použít URL položky místo URL playlistu</string>
|
||||
<string name="use_item_url_not_playlist_summary">Užitečné pro offline playlisty Libretube, které nejsou rozpoznány yt-dlp. Metadata playlistu nebudou vložena, pokud je tato funkce povolena</string>
|
||||
<string name="use_item_url_not_playlist_summary">Metadata playlistu nebudou vložena, pokud je tato funkce povolena</string>
|
||||
<string name="recode_video">Překódovat video</string>
|
||||
<string name="recode_video_summary">Překóduje videosoubor do zadaného formátu videa</string>
|
||||
<string name="daily">Denně</string>
|
||||
|
|
|
|||
|
|
@ -418,5 +418,5 @@
|
|||
<string name="recode_video_summary">Nimmt die Videodatei im bestimmten Format auf</string>
|
||||
<string name="use_alarm_manager">AlarmManager anstatt WorkManager für die Zeitplanung nutzen</string>
|
||||
<string name="use_item_url_not_playlist">Die Element URL anstatt die Playlist URL nutzen</string>
|
||||
<string name="use_item_url_not_playlist_summary">Nützlich für Libretube Offline-Wiedergabelisten, die von yt-dlp nicht erkannt werden. Wiedergabelisten-Metadaten werden nicht eingebettet, wenn diese Option aktiviert ist</string>
|
||||
<string name="use_item_url_not_playlist_summary">Wiedergabelisten-Metadaten werden nicht eingebettet, wenn diese Option aktiviert ist</string>
|
||||
</resources>
|
||||
|
|
@ -409,7 +409,7 @@
|
|||
<string name="use_alarm_manager">Utilizar AlarmManager en lugar de WorkManager para la programación</string>
|
||||
<string name="use_alarm_manager_summary">Habilite esta opción si WorkManager está restringido por el proveedor de su dispositivo o si los trabajos programados no son demasiado precisos</string>
|
||||
<string name="use_item_url_not_playlist">Utilizar la URL del artículo en lugar de la URL de la lista de reproducción</string>
|
||||
<string name="use_item_url_not_playlist_summary">Útil para listas de reproducción sin conexión de Libretube que no son reconocidas por yt-dlp. Los metadatos de la lista de reproducción no se incrustarán con esta opción activada</string>
|
||||
<string name="use_item_url_not_playlist_summary">Los metadatos de la lista de reproducción no se incrustarán con esta opción activada</string>
|
||||
<string name="recode_video">Recodificar video</string>
|
||||
<string name="recode_video_summary">Recodifica el archivo de vídeo al formato de vídeo especificado</string>
|
||||
<string name="daily">Diariamente</string>
|
||||
|
|
|
|||
|
|
@ -419,6 +419,6 @@
|
|||
<string name="format_importance_note">Ajuste l\'ordre de priorité des formats. Cette ordre ne sera utilisée que lorsque l\'application récupère les formats dans la carte de téléchargement et sélectionne automatiquement le format !</string>
|
||||
<string name="enable_alarm_permission">Vous devez activer la permission SCHEDULE_EXACT_ALARM dans les paramètres de l\'application.</string>
|
||||
<string name="process_downloads_background">"Les téléchargements sont toujours en cours de chargement. Voulez-vous continuer à les charger en arrière-plan et commencer à télécharger ? "</string>
|
||||
<string name="use_item_url_not_playlist_summary">Utile pour les playlists hors-ligne de Libretube qui ne sont pas reconnues par yt-dlp. Les métadonnées de la liste de lecture ne seront pas intégrées quand ceci est activé</string>
|
||||
<string name="use_item_url_not_playlist_summary">Les métadonnées de la liste de lecture ne seront pas intégrées quand ceci est activé</string>
|
||||
<string name="use_item_url_not_playlist">Utiliser l\'URL de l\'élément au lieu de celui de la liste de lecture</string>
|
||||
</resources>
|
||||
|
|
@ -408,7 +408,7 @@
|
|||
\nफाइल में सहेजे गए डेटा को मिटाने और केवल उसका उपयोग करने के लिए \'रीसेट करें\' दबाएं।</string>
|
||||
<string name="use_alarm_manager">शेड्यूलिंग के लिए WorkManager के बजाय AlarmManager का उपयोग करें</string>
|
||||
<string name="use_alarm_manager_summary">यदि WorkManager आपके डिवाइस विक्रेता द्वारा प्रतिबंधित है या शेड्यूल किए गए कार्य बहुत सटीक नहीं हैं तो इसे सक्षम करें</string>
|
||||
<string name="use_item_url_not_playlist_summary">Libretube ऑफ़लाइन प्लेलिस्ट के लिए उपयोगी है जो yt-dlp द्वारा पहचाने नहीं जाते हैं। इस सक्षम के साथ प्लेलिस्ट मेटाडेटा एम्बेड नहीं किया जाएगा</string>
|
||||
<string name="use_item_url_not_playlist_summary">नहीं जाते हैं। इस सक्षम के साथ प्लेलिस्ट मेटाडेटा एम्बेड नहीं किया जाएगा</string>
|
||||
<string name="use_item_url_not_playlist">प्लेलिस्ट URL के बजाय आइटम URL का उपयोग करें</string>
|
||||
<string name="recode_video">वीडियो पुनःकोड करें</string>
|
||||
<string name="recode_video_summary">वीडियो फ़ाइल को निर्दिष्ट वीडियो प्रारूप में पुनःकोडित करता है</string>
|
||||
|
|
|
|||
|
|
@ -419,5 +419,5 @@
|
|||
<string name="data_fetching_extractor_youtube">Adatszerző Extractor (YouTube)</string>
|
||||
<string name="restore_info">Nyomja meg a \'Restore\' gombot hogy összeolvassza a lementett adatokat a jelenlegiekkel.
|
||||
\nNyomja meg a \'Reset\' gombot ha csak a lementett adatokat kívánja megtartani.</string>
|
||||
<string name="use_item_url_not_playlist_summary">Hasznos tud lenni olyan Libretube offline playlistekhez, amelyeket a yt-dlp nem ismer fel. Ennek bekapcsolásával a playlistek metadatája nem fog beágyazódni</string>
|
||||
<string name="use_item_url_not_playlist_summary">Ennek bekapcsolásával a playlistek metadatája nem fog beágyazódni</string>
|
||||
</resources>
|
||||
|
|
@ -413,7 +413,7 @@
|
|||
<string name="use_alarm_manager_summary">Aktifkan ini jika WorkManager dibatasi oleh vendor perangkatmu atau penjadwalan tugas tidak terlalu tepat waktu</string>
|
||||
<string name="daily">Tiap hari</string>
|
||||
<string name="use_item_url_not_playlist">Gunakan URL Butir, bukannya URL Daftar Putar</string>
|
||||
<string name="use_item_url_not_playlist_summary">Berguna untuk daftar putar luring (offline) LibreTube yang tidak dikenali oleh yt-dlp. Metadata daftar putar tidak akan ditanamkan kalau preferensi ini diaktifkan</string>
|
||||
<string name="use_item_url_not_playlist_summary">Metadata daftar putar tidak akan ditanamkan kalau preferensi ini diaktifkan</string>
|
||||
<string name="recode_video_summary">Mengkodekan ulang file video ke format video yang ditentukan</string>
|
||||
<string name="recode_video">Rekodekan Video</string>
|
||||
</resources>
|
||||
|
|
@ -415,7 +415,7 @@
|
|||
<string name="location">Posizione</string>
|
||||
<string name="enable_alarm_permission">È necessario abilitare l\'autorizzazione SCHEDULE_EXACT_ALARM nelle impostazioni dell\'app.</string>
|
||||
<string name="use_item_url_not_playlist">Usa l\'URL dell\'elemento invece dell\'URL della playlist</string>
|
||||
<string name="use_item_url_not_playlist_summary">Utile per le playlist offline di Libretube che non sono riconosciute da yt-dlp. I metadati della playlist non saranno incorporati se questa opzione è abilitata</string>
|
||||
<string name="use_item_url_not_playlist_summary">I metadati della playlist non saranno incorporati se questa opzione è abilitata</string>
|
||||
<string name="recode_video">Ricodifica Video</string>
|
||||
<string name="recode_video_summary">Ricodifica il file video nel formato video specificato</string>
|
||||
<string name="process_downloads_background">"I download sono ancora in fase di caricamento. Continuare a elaborarli in background e iniziare il download? "</string>
|
||||
|
|
|
|||
|
|
@ -357,7 +357,7 @@
|
|||
<string name="save_auto_subs">שמור כתוביות אוטומטיות</string>
|
||||
<string name="display_over_apps_summary">הפוך את כרטיס ההורדה תמיד להופיע למעלה. הפעל זאת אם האפליקציה הפועלת כעת נסגרת כאשר כרטיס ההורדה מופיע</string>
|
||||
<string name="no_audio">וידאו ללא שמע</string>
|
||||
<string name="use_item_url_not_playlist_summary">שימושי עבור רשימות השמעה לא מקוונות של Libretube שאינן מזוהות על ידי yt-dlp. מטא נתונים של רשימת השמעה לא יוטמעו כאשר זה מופעל</string>
|
||||
<string name="use_item_url_not_playlist_summary"> מטא נתונים של רשימת השמעה לא יוטמעו כאשר זה מופעל</string>
|
||||
<string name="no_download_fragments">אל תוריד כפרגמנטים</string>
|
||||
<string name="no_download_fragments_summary">אל תשתמש בקבצי part. ותכתוב ישירות לקובץ הפלט</string>
|
||||
<string name="swipe_gestures_download_card">החלק תנועות בכרטיס ההורדה</string>
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@
|
|||
<string name="use_alarm_manager">時間管理に WorkManager でなく AlarmManager を使う</string>
|
||||
<string name="use_alarm_manager_summary">WorkManager が提供者によりに制限されていたり、時間管理されたジョブの精度が良くないなら、これを有効にします</string>
|
||||
<string name="queue">キュー</string>
|
||||
<string name="use_item_url_not_playlist_summary">Libretube のオフライン再生リストは yt-dlp が認識できないため有用です。有効にすると、再生リストのメタデータは埋め込まれません</string>
|
||||
<string name="use_item_url_not_playlist_summary">有効にすると、再生リストのメタデータは埋め込まれません</string>
|
||||
<string name="use_item_url_not_playlist">再生リストのURLの代わりに個々の項目のURLを使用</string>
|
||||
<string name="restore_info">復元は、保存済みデータと現在のデータを統合します。
|
||||
\n初期化は、消去しファイル中の保存済みデータのみを使用します。</string>
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@
|
|||
<string name="use_alarm_manager">AlarmManager in plaats van WorkManager gebruiken voor planning</string>
|
||||
<string name="use_alarm_manager_summary">Schakel dit in als WorkManager beperkt is door de leverancier van uw apparaat of als geplande taken niet al te nauwkeurig zijn</string>
|
||||
<string name="use_item_url_not_playlist">Item-URL gebruiken in plaats van afspeellijst-URL</string>
|
||||
<string name="use_item_url_not_playlist_summary">Handig voor offline afspeellijsten van LibreTube die niet worden herkend door yt-dlp. Metagegevens van de afspeellijst worden niet ingesloten als dit is ingeschakeld</string>
|
||||
<string name="use_item_url_not_playlist_summary">Metagegevens van de afspeellijst worden niet ingesloten als dit is ingeschakeld</string>
|
||||
<string name="recode_video">Video hercoderen</string>
|
||||
<string name="recode_video_summary">Hercodeert het videobestand naar het opgegeven videoformaat</string>
|
||||
<string name="cleanup_leftover_downloads">Overgebleven downloads opschonen (geannuleerd, foutief)</string>
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@
|
|||
<string name="use_alarm_manager">ਸਮਾਂ-ਤਹਿ ਕਰਨ ਲਈ WorkManager ਦੀ ਬਜਾਏ AlarmManager ਦੀ ਵਰਤੋਂ ਕਰੋ</string>
|
||||
<string name="use_alarm_manager_summary">ਇਸ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ ਜੇਕਰ ਤੁਹਾਡੇ ਡਿਵਾਈਸ ਵਿਕਰੇਤਾ ਦੁਆਰਾ WorkManager ਨੂੰ ਪ੍ਰਤਿਬੰਧਿਤ ਕੀਤਾ ਗਿਆ ਹੈ ਜਾਂ ਸ਼ਡਿਊਲ ਕੀਤੇ ਜੌਬ ਬਹੁਤ ਸਟੀਕ ਨਹੀਂ ਹਨ</string>
|
||||
<string name="use_item_url_not_playlist">ਪਲੇਲਿਸਟ URL ਦੀ ਬਜਾਏ ਆਈਟਮ URL ਦੀ ਵਰਤੋਂ ਕਰੋ</string>
|
||||
<string name="use_item_url_not_playlist_summary">Libretube ਆਫਲਾਈਨ ਪਲੇਲਿਸਟਾਂ ਲਈ ਉਪਯੋਗੀ ਜੋ yt-dlp ਦੁਆਰਾ ਮਾਨਤਾ ਪ੍ਰਾਪਤ ਨਹੀਂ ਹਨ। ਇਸਨੂੰ ਸਮਰੱਥ ਕਰਨ ਨਾਲ ਪਲੇਲਿਸਟ ਮੈਟਾਡੇਟਾ ਏਮਬੇਡ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ</string>
|
||||
<string name="use_item_url_not_playlist_summary">ਦੁਆਰਾ ਮਾਨਤਾ ਪ੍ਰਾਪਤ ਨਹੀਂ ਹਨ। ਇਸਨੂੰ ਸਮਰੱਥ ਕਰਨ ਨਾਲ ਪਲੇਲਿਸਟ ਮੈਟਾਡੇਟਾ ਏਮਬੇਡ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ</string>
|
||||
<string name="recode_video">ਵੀਡੀਓ ਰੀਕੋਡ ਕਰੋ</string>
|
||||
<string name="recode_video_summary">ਵੀਡੀਓ ਫਾਈਲ ਨੂੰ ਨਿਸ਼ਚਿਤ ਵੀਡੀਓ ਫਾਰਮੈਟ ਵਿੱਚ ਰੀਕੋਡ ਕਰਦਾ ਹੈ</string>
|
||||
<string name="data_fetching_extractor_youtube">ਡਾਟਾ ਪ੍ਰਾਪਤੀ ਐਕਸਟਰੈਕਟਰ (ਯੂਟਿਊਬ)</string>
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@
|
|||
<string name="monthly">Co miesiąc</string>
|
||||
<string name="continue_anyway">Tak czy inaczej, kontynuuj</string>
|
||||
<string name="use_item_url_not_playlist">Użyj adresu URL elementu zamiast adresu URL listy odtwarzania</string>
|
||||
<string name="use_item_url_not_playlist_summary">Przydatne dla list odtwarzania offline Libretube, które nie są rozpoznawane przez yt-dlp. Metadane listy odtwarzania nie zostaną osadzone po włączeniu tej opcji</string>
|
||||
<string name="use_item_url_not_playlist_summary">Metadane listy odtwarzania nie zostaną osadzone po włączeniu tej opcji</string>
|
||||
<string name="recode_video_summary">Przekodowuje plik wideo do określonego formatu wideo</string>
|
||||
<string name="recode_video">Przekoduj Video</string>
|
||||
</resources>
|
||||
|
|
@ -409,7 +409,7 @@
|
|||
<string name="use_alarm_manager">Usar \'AlarmManager\' em vez de \'WorkManager\' para agendamento</string>
|
||||
<string name="use_alarm_manager_summary">Habilite isto se o \"WorkManager\" for restrito pelo fornecedor do seu dispositivo ou se as tarefas agendadas não forem muito precisas</string>
|
||||
<string name="use_item_url_not_playlist">Usar URL do item em vez do URL da playlist</string>
|
||||
<string name="use_item_url_not_playlist_summary">Útil para playlists offline do LibreTube que não são reconhecidas pelo yt-dlp. Os metadados da playlist não serão adicionados com esta opção ativada</string>
|
||||
<string name="use_item_url_not_playlist_summary">Os metadados da playlist não serão adicionados com esta opção ativada</string>
|
||||
<string name="recode_video_summary">Recodifica o arquivo de vídeo para o formato especificado</string>
|
||||
<string name="recode_video">Recodificar vídeo</string>
|
||||
<string name="daily">Diariamente</string>
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@
|
|||
<string name="use_alarm_manager">Используйте AlarmManager вместо WorkManager для планирования</string>
|
||||
<string name="use_alarm_manager_summary">Включите это, если WorkManager ограничен поставщиком вашего устройства или запланированные задания не слишком точны</string>
|
||||
<string name="use_item_url_not_playlist">Используйте URL-адрес элемента вместо URL-адреса плейлиста</string>
|
||||
<string name="use_item_url_not_playlist_summary">Полезно для автономных плейлистов Libretube, которые не распознаются yt-dlp. Метаданные плейлиста не будут встроены, если эта функция включена</string>
|
||||
<string name="use_item_url_not_playlist_summary">Метаданные плейлиста не будут встроены, если эта функция включена</string>
|
||||
<string name="recode_video">Перекодировать видео</string>
|
||||
<string name="recode_video_summary">Перекодирует видеофайл в указанный видеоформат</string>
|
||||
<string name="daily">Ежедневно</string>
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@
|
|||
<string name="queue">Pásmo</string>
|
||||
<string name="use_alarm_manager">Použiť AlarmManager namiesto WorkManageru na plánovanie</string>
|
||||
<string name="use_alarm_manager_summary">Zapnite túto funkciu, ak je WorkManager obmedzený výrobcom zariadenia alebo ak naplánované úlohy nie sú príliš presné</string>
|
||||
<string name="use_item_url_not_playlist_summary">Užitočné pre offline zoznamy skladieb Libretube, ktoré yt-dlp nerozpoznáva. Metadáta playlistu nebudú vložené, ak je táto funkcia zapnutá</string>
|
||||
<string name="use_item_url_not_playlist_summary">Metadáta playlistu nebudú vložené, ak je táto funkcia zapnutá</string>
|
||||
<string name="use_item_url_not_playlist">Použiť URL položky namiesto URL playlistu</string>
|
||||
<string name="recode_video">Prekódovať video</string>
|
||||
<string name="recode_video_summary">Prekóduje videosúbor do určeného formátu videa</string>
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@
|
|||
<string name="use_alarm_manager">Përdor AlarmManager në vend të WorkManager për Skedulim</string>
|
||||
<string name="use_alarm_manager_summary">Aktivizo këtë ku WorkManager është i limituar në paisje ose punët e skeduluara nuk ekzekutohen në kohë</string>
|
||||
<string name="use_item_url_not_playlist">Përdor URL e videos në vend të URL së playlist</string>
|
||||
<string name="use_item_url_not_playlist_summary">E dobishme për playlistet Libretube qe nuk njihen nga yt-dlp. Metadata e playlist nuk do te shtohen dot kur ky opsion është i aktivizuar</string>
|
||||
<string name="use_item_url_not_playlist_summary">Metadata e playlist nuk do te shtohen dot kur ky opsion është i aktivizuar</string>
|
||||
<string name="recode_video">Rikodo Videon</string>
|
||||
<string name="recode_video_summary">Rikodon skedarin e videos sipas formatit të cilësuar nga përdoruesi</string>
|
||||
<string name="restore_info">Shtypni \"Rivendosni\" për të bashkuar të dhënat e ruajtura me të dhënat tuaja aktuale.
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@
|
|||
<string name="use_alarm_manager">Користите AlarmManager уместо WorkManager за планирање</string>
|
||||
<string name="use_alarm_manager_summary">Омогућите ово ако је WorkManager ограничен од стране продавца уређаја или заказани послови нису превише прецизни</string>
|
||||
<string name="use_item_url_not_playlist">Користи URL адресу предмета уместо URL адресе плејлисте</string>
|
||||
<string name="use_item_url_not_playlist_summary">Корисно за Libretube офлајн плејлисте које yt-dlp не препознаје. Метаподаци плејлисте неће бити уграђени, ако је ово омогућено</string>
|
||||
<string name="use_item_url_not_playlist_summary">Метаподаци плејлисте неће бити уграђени, ако је ово омогућено</string>
|
||||
<string name="recode_video">Рекодирај видео снимак</string>
|
||||
<string name="recode_video_summary">Рекодира фајл видео снимка у наведени формат видео снимка</string>
|
||||
<string name="daily">Дневно</string>
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@
|
|||
<string name="monthly">Aylık</string>
|
||||
<string name="cleanup_leftover_downloads">Artık indirmeleri temizleme (iptal edildi, hatalı)</string>
|
||||
<string name="use_item_url_not_playlist">Çalma Listesi URL\'si yerine Öge URL\'sini kullanın</string>
|
||||
<string name="use_item_url_not_playlist_summary">yt-dlp tarafından tanınmayan Libretube çevrimdışı çalma listeleri için kullanışlıdır. Bu etkinleştirildiğinde çalma listesi meta verileri gömülmeyecektir</string>
|
||||
<string name="use_item_url_not_playlist_summary">Bu etkinleştirildiğinde çalma listesi meta verileri gömülmeyecektir</string>
|
||||
<string name="recode_video">Videoyu tekrar kodla</string>
|
||||
<string name="recode_video_summary">Video dosyasını belirtilen video formatına yeniden kodlar</string>
|
||||
<string name="continue_anyway">Her Neyse Devam Et</string>
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@
|
|||
<string name="use_alarm_manager">Використовуйте AlarmManager замість WorkManager для планування</string>
|
||||
<string name="use_alarm_manager_summary">Увімкніть це, якщо WorkManager обмежено постачальником вашого пристрою або заплановані завдання не надто точні</string>
|
||||
<string name="use_item_url_not_playlist">Використовуйте URL елемента замість URL списку відтворення</string>
|
||||
<string name="use_item_url_not_playlist_summary">Корисно для списків відтворення Libretube без мережі, які не розпізнаються yt-dlp. Метадані списку відтворення не буде вбудовано, якщо увімкнено цей параметр</string>
|
||||
<string name="use_item_url_not_playlist_summary">Метадані списку відтворення не буде вбудовано, якщо увімкнено цей параметр</string>
|
||||
<string name="recode_video">Перекодувати відео</string>
|
||||
<string name="recode_video_summary">Перекодує відеофайл у вказаний відеоформат</string>
|
||||
<string name="daily">Щоденно</string>
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@
|
|||
<string name="use_alarm_manager">Sử dụng AlarmManager thay cho WorkManager trong phần Lên lịch để tải xuống</string>
|
||||
<string name="use_alarm_manager_summary">Hãy bật nếu WorkManager bị hạn chế bởi Nhà cung cấp thiết bị hoặc các công việc không được lên lịch chính xác</string>
|
||||
<string name="use_item_url_not_playlist">Dùng URL mục thay cho URL danh sách phát</string>
|
||||
<string name="use_item_url_not_playlist_summary">Dùng cho danh sách phát ngoại tuyến Libretube không được yt-dlp nhận dạng. Nếu bật thì metadata của danh sách phát sẽ không được thêm vào tệp</string>
|
||||
<string name="use_item_url_not_playlist_summary">Nếu bật thì metadata của danh sách phát sẽ không được thêm vào tệp</string>
|
||||
<string name="recode_video_summary">Mã hóa tệp video thành định dạng được chỉ định</string>
|
||||
<string name="recode_video">Mã hóa Video</string>
|
||||
</resources>
|
||||
|
|
@ -409,7 +409,7 @@
|
|||
<string name="use_alarm_manager">使用闹铃管理器而非工作管理器安排任务</string>
|
||||
<string name="use_alarm_manager_summary">如果工作管理器被设备厂商限制或安排好时间的任务不太精确,请启用这个</string>
|
||||
<string name="use_item_url_not_playlist">使用项目 URL 而非播放列表 URL</string>
|
||||
<string name="use_item_url_not_playlist_summary">对于未被 yt-dlp 识别的 Libretube 离线播放列表有用。启用此选项后不会内嵌播放列表元数据</string>
|
||||
<string name="use_item_url_not_playlist_summary">启用此选项后不会内嵌播放列表元数据</string>
|
||||
<string name="recode_video_summary">重编码视频文件到指定的视频格式</string>
|
||||
<string name="recode_video">重新编码视频</string>
|
||||
<string name="daily">每天</string>
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@
|
|||
<string name="monthly">每月</string>
|
||||
<string name="cleanup_leftover_downloads">清理殘留的下載(取消或錯誤的下載)</string>
|
||||
<string name="use_item_url_not_playlist">使用項目 URL 而非播放清單 URL</string>
|
||||
<string name="use_item_url_not_playlist_summary">此功能適用於 Libretube 離線播放清單,這些清單無法被 yt-dlp 認識。啟用此選項後,播放清單的中繼資料將不會嵌入</string>
|
||||
<string name="use_item_url_not_playlist_summary">啟用此選項後,播放清單的中繼資料將不會嵌入</string>
|
||||
<string name="recode_video">重新編碼影片</string>
|
||||
<string name="recode_video_summary">將影片檔案重新編碼為指定的影片格式</string>
|
||||
<string name="data_fetching_extractor_youtube">資料擷取提取器(YouTube)</string>
|
||||
|
|
|
|||
|
|
@ -1495,6 +1495,11 @@
|
|||
</string-array>
|
||||
|
||||
<string-array name="data_fetching_extractor_youtube">
|
||||
<item>yt-dlp</item>
|
||||
<item>NewPipe</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="data_fetching_extractor_youtube_values">
|
||||
<item>YT_DLP</item>
|
||||
<item>NEWPIPE</item>
|
||||
</string-array>
|
||||
|
|
|
|||
|
|
@ -430,4 +430,7 @@
|
|||
<string name="deleted">Deleted</string>
|
||||
<string name="websites">Websites</string>
|
||||
<string name="other_youtube_extractor_args">Other YouTube Extractor Arguments</string>
|
||||
<string name="items">item(s)</string>
|
||||
<string name="socket_timeout">Socket Timeout</string>
|
||||
<string name="socket_timeout_description">Time to wait before giving up, in seconds</string>
|
||||
</resources>
|
||||
|
|
@ -128,6 +128,12 @@
|
|||
app:summary="@string/buffer_size_summary"
|
||||
app:title="@string/buffer_size" />
|
||||
|
||||
<EditTextPreference
|
||||
android:icon="@drawable/ic_clock"
|
||||
app:key="socket_timeout"
|
||||
android:summary="@string/socket_timeout_description"
|
||||
app:title="@string/socket_timeout"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@
|
|||
<ListPreference
|
||||
android:defaultValue="NEWPIPE"
|
||||
android:entries="@array/data_fetching_extractor_youtube"
|
||||
android:entryValues="@array/data_fetching_extractor_youtube"
|
||||
android:entryValues="@array/data_fetching_extractor_youtube_values"
|
||||
android:icon="@drawable/baseline_manage_search_24"
|
||||
app:key="youtube_data_fetching_extractor"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
|
|
|
|||
Loading…
Reference in a new issue