stuff
Fix format details fps in arabic being rtl Removed h264 from codec Fixed Search engine not getting updated in home when changing in settings fragment. Added language preference in android 13 and up Added multiple selection for command templates Fix issue when app crashes when creating config files for items with weird titles Fix auto preferred download type not working correctly in yt music
This commit is contained in:
parent
25f53aeb87
commit
2d08d2f643
30 changed files with 422 additions and 304 deletions
|
|
@ -10,7 +10,7 @@ def properties = new Properties()
|
|||
def versionMajor = 1
|
||||
def versionMinor = 6
|
||||
def versionPatch = 6
|
||||
def versionBuild = 2 // bump for dogfood builds, public betas, etc.
|
||||
def versionBuild = 3 // bump for dogfood builds, public betas, etc.
|
||||
def versionExt = ""
|
||||
|
||||
if (versionBuild > 0){
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.squareup.picasso.Picasso
|
||||
|
||||
class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : PagingDataAdapter<DownloadItem, GenericDownloadAdapter.ViewHolder>(DIFF_CALLBACK) {
|
||||
class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : PagingDataAdapter<DownloadItemSimple, GenericDownloadAdapter.ViewHolder>(DIFF_CALLBACK) {
|
||||
private val onItemClickListener: OnItemClickListener
|
||||
private val activity: Activity
|
||||
val checkedItems: ArrayList<Long>
|
||||
|
|
@ -73,7 +74,7 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
}
|
||||
|
||||
val duration = card.findViewById<TextView>(R.id.duration)
|
||||
duration.text = item!!.duration
|
||||
duration.text = item.duration
|
||||
|
||||
// TITLE ----------------------------------
|
||||
val itemTitle = card.findViewById<TextView>(R.id.title)
|
||||
|
|
@ -204,13 +205,13 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
}
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
|
||||
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItemSimple> = object : DiffUtil.ItemCallback<DownloadItemSimple>() {
|
||||
override fun areItemsTheSame(oldItem: DownloadItemSimple, newItem: DownloadItemSimple): Boolean {
|
||||
val ranged = arrayListOf(oldItem.id, newItem.id)
|
||||
return ranged[0] == ranged[1]
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||
override fun areContentsTheSame(oldItem: DownloadItemSimple, newItem: DownloadItemSimple): Boolean {
|
||||
return oldItem.id == newItem.id && oldItem.title == newItem.title && oldItem.author == newItem.author && oldItem.thumb == newItem.thumb
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.deniscerri.ytdlnis.database.dao
|
|||
import androidx.paging.PagingSource
|
||||
import androidx.room.*
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ interface DownloadDao {
|
|||
fun getActiveAndQueuedDownloads() : Flow<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Queued' or status='QueuedPaused' ORDER BY downloadStartTime, id")
|
||||
fun getQueuedDownloads() : PagingSource<Int, DownloadItem>
|
||||
fun getQueuedDownloads() : PagingSource<Int, DownloadItemSimple>
|
||||
|
||||
@Query("SELECT format FROM downloads WHERE status='Queued' or status='QueuedPaused'")
|
||||
fun getSelectedFormatFromQueued() : List<Format>
|
||||
|
|
@ -49,7 +50,7 @@ interface DownloadDao {
|
|||
fun getQueuedDownloadsList() : List<DownloadItem>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Cancelled' ORDER BY id DESC")
|
||||
fun getCancelledDownloads() : PagingSource<Int, DownloadItem>
|
||||
fun getCancelledDownloads() : PagingSource<Int, DownloadItemSimple>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Cancelled' ORDER BY id DESC")
|
||||
fun getCancelledDownloadsList() : List<DownloadItem>
|
||||
|
|
@ -58,13 +59,13 @@ interface DownloadDao {
|
|||
fun getPausedDownloadsList() : List<DownloadItem>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Error' ORDER BY id DESC")
|
||||
fun getErroredDownloads() : PagingSource<Int, DownloadItem>
|
||||
fun getErroredDownloads() : PagingSource<Int, DownloadItemSimple>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Error' ORDER BY id DESC")
|
||||
fun getErroredDownloadsList() : List<DownloadItem>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Saved' ORDER BY id DESC")
|
||||
fun getSavedDownloads() : PagingSource<Int, DownloadItem>
|
||||
fun getSavedDownloads() : PagingSource<Int, DownloadItemSimple>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Saved' ORDER BY id DESC")
|
||||
fun getSavedDownloadsList() : List<DownloadItem>
|
||||
|
|
@ -115,6 +116,9 @@ interface DownloadDao {
|
|||
@Query("DELETE FROM downloads WHERE status='Saved'")
|
||||
suspend fun deleteSaved()
|
||||
|
||||
@Query("DELETE FROM downloads WHERE id in (:list)")
|
||||
suspend fun deleteAllWithIDs(list: List<Long>)
|
||||
|
||||
@Query("UPDATE downloads SET status='Cancelled' WHERE status='Queued' or status='QueuedPaused'")
|
||||
suspend fun cancelQueued()
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
||||
@Entity(tableName = "downloads")
|
||||
data class DownloadItemSimple(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long,
|
||||
var url: String,
|
||||
var title: String,
|
||||
var author: String,
|
||||
var thumb: String,
|
||||
var duration: String,
|
||||
var format: Format,
|
||||
@ColumnInfo(defaultValue = "Queued")
|
||||
var status: String,
|
||||
var logID: Long?
|
||||
)
|
||||
|
|
@ -5,6 +5,7 @@ import androidx.paging.PagingConfig
|
|||
import com.deniscerri.ytdlnis.App
|
||||
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.io.File
|
||||
|
|
@ -16,19 +17,19 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
|
|||
pagingSourceFactory = {downloadDao.getAllDownloads()}
|
||||
)
|
||||
val activeDownloads : Flow<List<DownloadItem>> = downloadDao.getActiveDownloads()
|
||||
val queuedDownloads : Pager<Int, DownloadItem> = Pager(
|
||||
val queuedDownloads : Pager<Int, DownloadItemSimple> = Pager(
|
||||
config = PagingConfig(pageSize = 20, initialLoadSize = 20, prefetchDistance = 1),
|
||||
pagingSourceFactory = {downloadDao.getQueuedDownloads()}
|
||||
)
|
||||
val cancelledDownloads : Pager<Int, DownloadItem> = Pager(
|
||||
val cancelledDownloads : Pager<Int, DownloadItemSimple> = Pager(
|
||||
config = PagingConfig(pageSize = 20, initialLoadSize = 20, prefetchDistance = 1),
|
||||
pagingSourceFactory = {downloadDao.getCancelledDownloads()}
|
||||
)
|
||||
val erroredDownloads : Pager<Int, DownloadItem> = Pager(
|
||||
val erroredDownloads : Pager<Int, DownloadItemSimple> = Pager(
|
||||
config = PagingConfig(pageSize = 20, initialLoadSize = 20, prefetchDistance = 1),
|
||||
pagingSourceFactory = {downloadDao.getErroredDownloads()}
|
||||
)
|
||||
val savedDownloads : Pager<Int, DownloadItem> = Pager(
|
||||
val savedDownloads : Pager<Int, DownloadItemSimple> = Pager(
|
||||
config = PagingConfig(pageSize = 20, initialLoadSize = 20, prefetchDistance = 1),
|
||||
pagingSourceFactory = {downloadDao.getSavedDownloads()}
|
||||
)
|
||||
|
|
@ -114,6 +115,11 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
|
|||
downloadDao.deleteSaved()
|
||||
}
|
||||
|
||||
suspend fun deleteAllWithIDs(ids: List<Long>){
|
||||
downloadDao.deleteAllWithIDs(ids)
|
||||
|
||||
}
|
||||
|
||||
suspend fun cancelQueued(){
|
||||
downloadDao.cancelQueued()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.content.res.Resources
|
|||
import android.net.ConnectivityManager
|
||||
import android.os.Looper
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
|
|
@ -31,6 +32,7 @@ import com.deniscerri.ytdlnis.database.dao.ResultDao
|
|||
import com.deniscerri.ytdlnis.database.models.AudioPreferences
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
|
|
@ -62,12 +64,12 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
private val commandTemplateDao: CommandTemplateDao
|
||||
private val infoUtil : InfoUtil
|
||||
val allDownloads : Flow<PagingData<DownloadItem>>
|
||||
val queuedDownloads : Flow<PagingData<DownloadItem>>
|
||||
val queuedDownloads : Flow<PagingData<DownloadItemSimple>>
|
||||
val activeDownloads : LiveData<List<DownloadItem>>
|
||||
val activeDownloadsCount : LiveData<Int>
|
||||
val cancelledDownloads : Flow<PagingData<DownloadItem>>
|
||||
val erroredDownloads : Flow<PagingData<DownloadItem>>
|
||||
val savedDownloads : Flow<PagingData<DownloadItem>>
|
||||
val cancelledDownloads : Flow<PagingData<DownloadItemSimple>>
|
||||
val erroredDownloads : Flow<PagingData<DownloadItemSimple>>
|
||||
val savedDownloads : Flow<PagingData<DownloadItemSimple>>
|
||||
|
||||
private var bestVideoFormat : Format
|
||||
private var bestAudioFormat : Format
|
||||
|
|
@ -125,35 +127,8 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
resources = Resources(application.assets, metrics, confTmp)
|
||||
|
||||
|
||||
val videoFormatValues = resources.getStringArray(R.array.video_formats_values)
|
||||
videoContainer = sharedPreferences.getString("video_format", "Default")
|
||||
|
||||
defaultVideoFormats = mutableListOf()
|
||||
videoFormatValues.forEach {
|
||||
val tmp = Format(
|
||||
it,
|
||||
videoContainer!!,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
it
|
||||
)
|
||||
defaultVideoFormats.add(tmp)
|
||||
}
|
||||
formatIDPreference.reversed().forEach {
|
||||
val tmp = Format(
|
||||
it,
|
||||
videoContainer!!,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
it
|
||||
)
|
||||
defaultVideoFormats.add(tmp)
|
||||
}
|
||||
|
||||
defaultVideoFormats = getGenericVideoFormats()
|
||||
bestVideoFormat = defaultVideoFormats.last()
|
||||
|
||||
audioContainer = sharedPreferences.getString("audio_format", "mp3")
|
||||
|
|
@ -200,11 +175,17 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
return repository.getItemByID(id)
|
||||
}
|
||||
|
||||
private fun getSuitableDownloadType(url: String): Type{
|
||||
if (urlsForAudioType.any { url.contains(it) }){
|
||||
return Type.audio
|
||||
fun getDownloadType(t: Type, url: String) : Type {
|
||||
return when(t){
|
||||
Type.auto -> {
|
||||
if (urlsForAudioType.any { url.contains(it) }){
|
||||
Type.audio
|
||||
}else{
|
||||
Type.video
|
||||
}
|
||||
}
|
||||
else -> t
|
||||
}
|
||||
return Type.video
|
||||
}
|
||||
|
||||
fun createDownloadItemFromResult(resultItem: ResultItem, givenType: Type) : DownloadItem {
|
||||
|
|
@ -214,10 +195,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
val saveThumb = sharedPreferences.getBoolean("write_thumbnail", false)
|
||||
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
||||
|
||||
var type = givenType
|
||||
if (type == Type.auto){
|
||||
type = getSuitableDownloadType(resultItem.url)
|
||||
}
|
||||
var type = getDownloadType(givenType, resultItem.url)
|
||||
if(type == Type.command && commandTemplateDao.getTotalNumber() == 0) type = Type.video
|
||||
|
||||
val customFileNameTemplate = when(type) {
|
||||
|
|
@ -466,8 +444,8 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
val audioFormats = resources.getStringArray(R.array.audio_formats)
|
||||
val formats = mutableListOf<Format>()
|
||||
val containerPreference = sharedPreferences.getString("audio_format", "")
|
||||
audioFormatIDPreference.forEach { formats.add(Format(it, containerPreference!!,"","", "",0, it)) }
|
||||
audioFormats.forEach { formats.add(Format(it, containerPreference!!,"","", "",0, it)) }
|
||||
audioFormatIDPreference.forEach { formats.add(Format(it, containerPreference!!,"","", "",1, it)) }
|
||||
return formats
|
||||
}
|
||||
|
||||
|
|
@ -475,8 +453,8 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
val videoFormats = resources.getStringArray(R.array.video_formats_values)
|
||||
val formats = mutableListOf<Format>()
|
||||
val containerPreference = sharedPreferences.getString("video_format", "")
|
||||
formatIDPreference.forEach { formats.add(Format(it, containerPreference!!,"Default","", "",0, it)) }
|
||||
videoFormats.forEach { formats.add(Format(it, containerPreference!!,"Default","", "",0, it)) }
|
||||
formatIDPreference.forEach { formats.add(Format(it, containerPreference!!,"Default","", "",1, it)) }
|
||||
return formats
|
||||
}
|
||||
|
||||
|
|
@ -489,8 +467,8 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
val list : MutableList<DownloadItem> = mutableListOf()
|
||||
var preferredType = sharedPreferences.getString("preferred_download_type", "video")
|
||||
items.forEach {
|
||||
if (preferredType == Type.auto.toString()) preferredType = getSuitableDownloadType(it!!.url).toString()
|
||||
list.add(createDownloadItemFromResult(it!!, Type.valueOf(preferredType!!)))
|
||||
preferredType = getDownloadType(Type.valueOf(preferredType!!), it!!.url).toString()
|
||||
list.add(createDownloadItemFromResult(it, Type.valueOf(preferredType!!)))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
|
@ -525,6 +503,11 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
repository.deleteSaved()
|
||||
}
|
||||
|
||||
fun deleteAllWithID(ids: List<Long>) = viewModelScope.launch(Dispatchers.IO){
|
||||
Log.e("Aa", ids.size.toString())
|
||||
repository.deleteAllWithIDs(ids)
|
||||
}
|
||||
|
||||
fun cancelQueued() = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.cancelQueued()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ class ShareActivity : BaseActivity() {
|
|||
|
||||
private fun showDownloadSheet(it: ResultItem){
|
||||
if (sharedPreferences.getBoolean("download_card", true)){
|
||||
val bottomSheet = DownloadBottomSheetDialog(it, DownloadViewModel.Type.valueOf(sharedPreferences.getString("preferred_download_type", "video")!!), null, quickDownload)
|
||||
val bottomSheet = DownloadBottomSheetDialog(it,downloadViewModel.getDownloadType(DownloadViewModel.Type.valueOf(sharedPreferences.getString("preferred_download_type", "video")!!), it.url), null, quickDownload)
|
||||
bottomSheet.show(supportFragmentManager, "downloadSingleSheet")
|
||||
}else{
|
||||
lifecycleScope.launch(Dispatchers.IO){
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import androidx.constraintlayout.widget.ConstraintLayout
|
|||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.forEachIndexed
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.fragment.app.Fragment
|
||||
|
|
@ -283,7 +284,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
val providersChipGroup = searchView!!.findViewById<ChipGroup>(R.id.providers)
|
||||
val providers = resources.getStringArray(R.array.search_engines)
|
||||
val providersValues = resources.getStringArray(R.array.search_engines_values).toMutableList()
|
||||
val currentProvider = sharedPreferences?.getString("search_engine", "ytsearch")
|
||||
|
||||
for(i in providersValues.indices){
|
||||
val provider = providers[i]
|
||||
|
|
@ -291,8 +291,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
val tmp = layoutinflater!!.inflate(R.layout.filter_chip, providersChipGroup, false) as Chip
|
||||
tmp.text = provider
|
||||
tmp.id = i
|
||||
|
||||
if (currentProvider == providerValue) tmp.isChecked = true
|
||||
tmp.tag = providersValues[i]
|
||||
|
||||
tmp.setOnClickListener {
|
||||
val editor = sharedPreferences?.edit()
|
||||
|
|
@ -308,6 +307,15 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
infoUtil = InfoUtil(requireContext())
|
||||
searchView!!.addTransitionListener { _, _, newState ->
|
||||
if (newState == SearchView.TransitionState.SHOWN) {
|
||||
val currentProvider = sharedPreferences?.getString("search_engine", "ytsearch")
|
||||
providersChipGroup.children.forEach {
|
||||
val tmp = providersChipGroup.findViewById<Chip>(it.id)
|
||||
if (tmp.tag == currentProvider) {
|
||||
tmp.isChecked = true
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
val clipboard =
|
||||
requireContext().getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||
|
|
@ -596,7 +604,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
}
|
||||
|
||||
private fun showSingleDownloadSheet(resultItem : ResultItem, type: DownloadViewModel.Type, quickDownload: Boolean){
|
||||
val bottomSheet = DownloadBottomSheetDialog(resultItem, type, null, quickDownload)
|
||||
val bottomSheet = DownloadBottomSheetDialog(resultItem, downloadViewModel.getDownloadType(type, resultItem.url), null, quickDownload)
|
||||
bottomSheet.show(parentFragmentManager, "downloadSingleSheet")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -127,8 +127,10 @@ class AddExtraCommandsDialog(private val item: DownloadItem?, private val callba
|
|||
Toast.makeText(context, getString(R.string.add_template_first), Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
lifecycleScope.launch {
|
||||
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel){ template ->
|
||||
text.text.insert(text.selectionStart, "${template.content} ")
|
||||
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel){ templates ->
|
||||
templates.forEach {
|
||||
text.text.insert(text.selectionStart, "${it.content} ")
|
||||
}
|
||||
text.postDelayed({
|
||||
text.requestFocus()
|
||||
imm.showSoftInput(text, 0)
|
||||
|
|
|
|||
|
|
@ -132,16 +132,19 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
commandTemplateCard.setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel){
|
||||
chosenCommandView.editText!!.setText(it.content)
|
||||
populateCommandCard(commandTemplateCard, it)
|
||||
chosenCommandView.editText!!.text.clear()
|
||||
it.forEach { c ->
|
||||
chosenCommandView.editText!!.text.insert(chosenCommandView.editText!!.selectionStart, "${c.content} ")
|
||||
}
|
||||
populateCommandCard(commandTemplateCard, it.first())
|
||||
downloadItem.format = Format(
|
||||
it.title,
|
||||
it.first().title,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
it.content
|
||||
it.map { c -> c.content }.joinToString { " " }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import android.graphics.Color
|
|||
import android.os.Bundle
|
||||
import android.text.format.DateFormat
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
|
|
@ -328,7 +329,16 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
if (items.first().type == DownloadViewModel.Type.command){
|
||||
lifecycleScope.launch {
|
||||
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel) {
|
||||
val format = downloadViewModel.generateCommandFormat(it)
|
||||
val format = Format(
|
||||
it.first().title,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
it.joinToString(" ") { c -> c.content }
|
||||
)
|
||||
|
||||
items.forEach { f ->
|
||||
f.format = format
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,9 +202,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
}
|
||||
|
||||
adapter.clearCheckedItems()
|
||||
for (id in selectedObjects){
|
||||
downloadViewModel.deleteDownload(id)
|
||||
}
|
||||
downloadViewModel.deleteAllWithID(selectedObjects)
|
||||
actionMode?.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,9 +208,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
adapter.checkedItems.toList()
|
||||
}
|
||||
adapter.clearCheckedItems()
|
||||
for (id in selectedObjects){
|
||||
downloadViewModel.deleteDownload(id)
|
||||
}
|
||||
downloadViewModel.deleteAllWithID(selectedObjects)
|
||||
actionMode?.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -260,8 +260,8 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
YoutubeDL.getInstance().destroyProcessById(id.toInt().toString())
|
||||
WorkManager.getInstance(requireContext()).cancelAllWorkByTag(id.toInt().toString())
|
||||
notificationUtil.cancelDownloadNotification(id.toInt())
|
||||
downloadViewModel.deleteDownload(id)
|
||||
}
|
||||
downloadViewModel.deleteAllWithID(selectedObjects)
|
||||
actionMode?.finish()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -222,9 +222,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
adapter.checkedItems.toList()
|
||||
}
|
||||
adapter.clearCheckedItems()
|
||||
withContext(Dispatchers.IO) {
|
||||
downloadViewModel.reQueueDownloadItems(selectedObjects)
|
||||
}
|
||||
downloadViewModel.deleteAllWithID(selectedObjects)
|
||||
actionMode?.finish()
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.ui.more
|
||||
|
||||
import android.app.ActionBar.LayoutParams
|
||||
import android.app.Activity
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
|
|
@ -8,8 +9,8 @@ import android.content.SharedPreferences
|
|||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.FileObserver
|
||||
import android.os.PersistableBundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
|
|
@ -22,7 +23,6 @@ import android.widget.ScrollView
|
|||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.view.forEach
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
|
|
@ -62,8 +62,8 @@ class TerminalActivity : BaseActivity() {
|
|||
private lateinit var sharedPreferences: SharedPreferences
|
||||
private var downloadID by Delegates.notNull<Int>()
|
||||
private lateinit var downloadFile : File
|
||||
private lateinit var observer: FileObserver
|
||||
private lateinit var imm : InputMethodManager
|
||||
private lateinit var metrics: DisplayMetrics
|
||||
var context: Context? = null
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -82,6 +82,8 @@ class TerminalActivity : BaseActivity() {
|
|||
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
metrics = DisplayMetrics()
|
||||
windowManager.defaultDisplay.getMetrics(metrics)
|
||||
|
||||
|
||||
bottomAppBar = findViewById(R.id.bottomAppBar)
|
||||
|
|
@ -113,8 +115,10 @@ class TerminalActivity : BaseActivity() {
|
|||
Toast.makeText(context, getString(R.string.add_template_first), Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
lifecycleScope.launch {
|
||||
UiUtil.showCommandTemplates(this@TerminalActivity, commandTemplateViewModel){ template ->
|
||||
input!!.text.insert(input!!.selectionStart, template.content + " ")
|
||||
UiUtil.showCommandTemplates(this@TerminalActivity, commandTemplateViewModel){ templates ->
|
||||
templates.forEach {c ->
|
||||
input!!.text.insert(input!!.selectionStart, c.content + " ")
|
||||
}
|
||||
input!!.postDelayed({
|
||||
input!!.requestFocus()
|
||||
imm.showSoftInput(input!!, 0)
|
||||
|
|
@ -146,7 +150,7 @@ class TerminalActivity : BaseActivity() {
|
|||
|
||||
output = findViewById(R.id.custom_command_output)
|
||||
output!!.setTextIsSelectable(true)
|
||||
output!!.setHorizontallyScrolling(true)
|
||||
output!!.layoutParams!!.width = LayoutParams.WRAP_CONTENT
|
||||
input = findViewById(R.id.command_edittext)
|
||||
input!!.requestFocus()
|
||||
fab = findViewById(R.id.command_fab)
|
||||
|
|
@ -168,38 +172,6 @@ class TerminalActivity : BaseActivity() {
|
|||
notificationUtil = NotificationUtil(this)
|
||||
handleIntent(intent)
|
||||
|
||||
if(Build.VERSION.SDK_INT < 29){
|
||||
observer = object : FileObserver(downloadFile.absolutePath, MODIFY) {
|
||||
override fun onEvent(event: Int, p: String?) {
|
||||
runOnUiThread{
|
||||
try {
|
||||
val newText = downloadFile.readText()
|
||||
if (newText.isBlank()) return@runOnUiThread
|
||||
output!!.append(newText)
|
||||
output!!.scrollTo(0, output!!.height)
|
||||
scrollView!!.fullScroll(View.FOCUS_DOWN)
|
||||
}catch (ignored: Exception) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
observer.startWatching()
|
||||
}else{
|
||||
observer = object : FileObserver(downloadFile, MODIFY) {
|
||||
override fun onEvent(event: Int, p: String?) {
|
||||
runOnUiThread{
|
||||
try {
|
||||
val newText = downloadFile.readText()
|
||||
if (newText.isBlank()) return@runOnUiThread
|
||||
output!!.append(newText)
|
||||
output!!.scrollTo(0, output!!.height)
|
||||
scrollView!!.fullScroll(View.FOCUS_DOWN)
|
||||
}catch (ignored: Exception) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
observer.startWatching()
|
||||
}
|
||||
|
||||
WorkManager.getInstance(this)
|
||||
.getWorkInfosForUniqueWorkLiveData(downloadID.toString())
|
||||
.observe(this){ list ->
|
||||
|
|
@ -269,7 +241,6 @@ class TerminalActivity : BaseActivity() {
|
|||
scrollView.id = R.id.horizontalscroll_output
|
||||
parent.addView(scrollView, 0)
|
||||
}
|
||||
output?.setHorizontallyScrolling(output?.canScrollHorizontally(1) != true)
|
||||
}
|
||||
R.id.export_clipboard -> {
|
||||
lifecycleScope.launch(Dispatchers.IO){
|
||||
|
|
@ -317,12 +288,10 @@ class TerminalActivity : BaseActivity() {
|
|||
private fun hideCancelFab() {
|
||||
fab!!.text = getString(R.string.run_command)
|
||||
fab!!.setIconResource(R.drawable.ic_baseline_keyboard_arrow_right_24)
|
||||
topAppBar!!.menu.forEach { it.isEnabled = true }
|
||||
}
|
||||
private fun showCancelFab() {
|
||||
fab!!.text = getString(R.string.cancel_download)
|
||||
fab!!.setIconResource(R.drawable.ic_cancel)
|
||||
topAppBar!!.menu.forEach { it.isEnabled = false }
|
||||
}
|
||||
|
||||
private var commandPathResultLauncher = registerForActivityResult(
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
|
|||
override val title: Int = R.string.general
|
||||
|
||||
private var language: ListPreference? = null
|
||||
private var language13: Preference? = null
|
||||
private var theme: ListPreference? = null
|
||||
private var accent: ListPreference? = null
|
||||
private var highContrast: SwitchPreferenceCompat? = null
|
||||
|
|
@ -50,6 +51,7 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
|
|||
}
|
||||
|
||||
language = findPreference("app_language")
|
||||
language13 = findPreference("app_language_13")
|
||||
theme = findPreference("ytdlnis_theme")
|
||||
accent = findPreference("theme_accent")
|
||||
highContrast = findPreference("high_contrast")
|
||||
|
|
@ -63,18 +65,32 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
|
|||
entries.add(Locale(it).getDisplayName(Locale(it)))
|
||||
}
|
||||
language!!.entries = entries.toTypedArray()
|
||||
}else{
|
||||
language!!.isVisible = false
|
||||
}
|
||||
|
||||
if(language!!.value == null) language!!.value = Locale.getDefault().language
|
||||
language!!.summary = Locale(language!!.value).getDisplayLanguage(Locale(language!!.value))
|
||||
language!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
|
||||
language!!.summary = Locale(newValue.toString()).getDisplayLanguage(Locale(newValue.toString()))
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(newValue.toString()))
|
||||
if(language!!.value == null) language!!.value = Locale.getDefault().language
|
||||
language!!.summary = Locale(language!!.value).getDisplayLanguage(Locale(language!!.value))
|
||||
|
||||
language!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
|
||||
language!!.summary = Locale(newValue.toString()).getDisplayLanguage(Locale(newValue.toString()))
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(newValue.toString()))
|
||||
true
|
||||
}
|
||||
|
||||
language13?.isVisible = false
|
||||
}else{
|
||||
language?.isVisible = false
|
||||
language13?.isVisible = true
|
||||
language13?.summary = Locale.getDefault().displayLanguage
|
||||
|
||||
language13!!.setOnPreferenceClickListener {
|
||||
val intent = Intent(Settings.ACTION_APP_LOCALE_SETTINGS)
|
||||
intent.data = Uri.fromParts("package", requireActivity().packageName, null)
|
||||
requireActivity().startActivity(intent)
|
||||
requireActivity().finishAffinity()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
theme!!.summary = theme!!.entry
|
||||
theme!!.onPreferenceChangeListener =
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
val arr = JsonArray()
|
||||
historyItems.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
arr.add(JsonParser.parseString(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
|
@ -259,7 +259,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
arr.add(JsonParser.parseString(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
|
@ -273,7 +273,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
arr.add(JsonParser.parseString(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
|
@ -287,7 +287,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
arr.add(JsonParser.parseString(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
|
@ -301,7 +301,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
arr.add(JsonParser.parseString(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
|
@ -315,7 +315,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
arr.add(JsonParser.parseString(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
|
@ -330,7 +330,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
it.useAsExtraCommand = false
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
arr.add(JsonParser.parseString(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
|
@ -344,7 +344,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
arr.add(JsonParser.parseString(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
|
@ -358,7 +358,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
val arr = JsonArray()
|
||||
historyItems.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
arr.add(JsonParser.parseString(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
|
@ -380,7 +380,6 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
lifecycleScope.launch {
|
||||
val preferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val editor = preferences.edit()
|
||||
|
||||
runCatching {
|
||||
val ip = requireContext().contentResolver.openInputStream(result.data!!.data!!)
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ object FileUtil {
|
|||
}
|
||||
|
||||
fun convertFileSize(s: Long): String{
|
||||
if (s <= 0) return "?"
|
||||
if (s <= 1) return "?"
|
||||
val units = arrayOf("B", "kB", "MB", "GB", "TB")
|
||||
val digitGroups = (log10(s.toDouble()) / log10(1024.0)).toInt()
|
||||
val symbols = DecimalFormatSymbols(Locale.US)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.content.SharedPreferences
|
|||
import android.os.Looper
|
||||
import android.text.Html
|
||||
import android.util.Log
|
||||
import android.util.Patterns
|
||||
import android.widget.Toast
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
|
|
@ -547,7 +548,6 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
fun getFromYTDL(query: String): ArrayList<ResultItem?> {
|
||||
items = ArrayList()
|
||||
val webpage_urls = mutableListOf<String>()
|
||||
val searchEngine = sharedPreferences.getString("search_engine", "ytsearch")
|
||||
try {
|
||||
val request : YoutubeDLRequest
|
||||
|
|
@ -656,7 +656,11 @@ class InfoUtil(private val context: Context) {
|
|||
val url = if (jsonObject.has("url")){
|
||||
jsonObject.getString("url")
|
||||
}else{
|
||||
jsonObject.getString("webpage_url")
|
||||
if (Patterns.WEB_URL.matcher(query).matches()){
|
||||
query
|
||||
}else{
|
||||
jsonObject.getString("webpage_url")
|
||||
}
|
||||
}
|
||||
|
||||
items.add(ResultItem(0,
|
||||
|
|
@ -672,10 +676,6 @@ class InfoUtil(private val context: Context) {
|
|||
chapters
|
||||
)
|
||||
)
|
||||
webpage_urls.add(jsonObject.getString("webpage_url"))
|
||||
}
|
||||
if (items.size == 1){
|
||||
items[0]?.url = webpage_urls.first()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Looper.prepare().run {
|
||||
|
|
@ -970,20 +970,6 @@ class InfoUtil(private val context: Context) {
|
|||
downDir.mkdirs()
|
||||
}
|
||||
|
||||
if (downloadItem.playlistTitle.isNotBlank()){
|
||||
request.addOption("--parse-metadata","${downloadItem.playlistTitle.split("[")[0]}:%(playlist)s")
|
||||
runCatching {
|
||||
request.addOption("--parse-metadata",
|
||||
downloadItem.playlistTitle
|
||||
.substring(
|
||||
downloadItem.playlistTitle.indexOf("[") + 1,
|
||||
downloadItem.playlistTitle.indexOf("]"),
|
||||
) + ":%(playlist_index)s"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val aria2 = sharedPreferences.getBoolean("aria2", false)
|
||||
if (aria2) {
|
||||
request.addOption("--downloader", "libaria2c.so")
|
||||
|
|
@ -1001,6 +987,7 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
val limitRate = sharedPreferences.getString("limit_rate", "")
|
||||
if (limitRate != "") request.addOption("-r", limitRate!!)
|
||||
request.addOption("--trim-filenames", 120)
|
||||
if(downloadItem.type != DownloadViewModel.Type.command){
|
||||
if (downloadItem.SaveThumb) {
|
||||
request.addOption("--write-thumbnail")
|
||||
|
|
@ -1034,12 +1021,12 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
|
||||
if(downloadItem.title.isNotBlank()){
|
||||
request.addOption("--parse-metadata", downloadItem.title.take(200) + ":%(title)s")
|
||||
request.addCommands(listOf("--replace-in-metadata", "title", ".+", downloadItem.title))
|
||||
}
|
||||
if (downloadItem.author.isNotBlank()){
|
||||
request.addOption("--parse-metadata", downloadItem.author.take(25) + ":%(artist)s")
|
||||
request.addCommands(listOf("--replace-in-metadata", "uploader", ".+", downloadItem.author))
|
||||
request.addCommands(listOf("--replace-in-metadata","uploader"," - Topic$",""))
|
||||
}
|
||||
request.addCommands(listOf("--replace-in-metadata","artist"," - Topic$",""))
|
||||
|
||||
if (downloadItem.downloadSections.isNotBlank()){
|
||||
downloadItem.downloadSections.split(";").forEach {
|
||||
|
|
@ -1077,6 +1064,21 @@ class InfoUtil(private val context: Context) {
|
|||
if (sharedPreferences.getBoolean("write_description", false)){
|
||||
request.addOption("--write-description")
|
||||
}
|
||||
|
||||
if (downloadItem.playlistTitle.isNotBlank()){
|
||||
request.addOption("--parse-metadata","${downloadItem.playlistTitle.split("[")[0]}:%(playlist)s")
|
||||
runCatching {
|
||||
request.addOption("--parse-metadata",
|
||||
downloadItem.playlistTitle
|
||||
.substring(
|
||||
downloadItem.playlistTitle.indexOf("[") + 1,
|
||||
downloadItem.playlistTitle.indexOf("]"),
|
||||
) + ":%(playlist_index)s"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (sharedPreferences.getBoolean("restrict_filenames", true)) {
|
||||
|
|
@ -1144,7 +1146,7 @@ class InfoUtil(private val context: Context) {
|
|||
if (! request.hasOption("--convert-thumbnails")) request.addOption("--convert-thumbnails", "jpg")
|
||||
if (sharedPreferences.getBoolean("crop_thumbnail", true)){
|
||||
try {
|
||||
val config = File(context.cacheDir.absolutePath + "/config" + downloadItem.title + "##" + downloadItem.format.format_id + ".txt")
|
||||
val config = File(context.cacheDir.absolutePath + "/config" + downloadItem.id + "##ffmpegCrop.txt")
|
||||
val configData = "--ppa \"ffmpeg: -c:v mjpeg -vf crop=\\\"'if(gt(ih,iw),iw,ih)':'if(gt(iw,ih),ih,iw)'\\\"\""
|
||||
config.writeText(configData)
|
||||
request.addOption("--ppa", "ThumbnailsConvertor:-qmin 1 -q:v 1")
|
||||
|
|
@ -1156,7 +1158,7 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
|
||||
if (downloadItem.customFileNameTemplate.isNotBlank()){
|
||||
request.addOption("-o", "${downloadItem.customFileNameTemplate}.%(ext)s")
|
||||
request.addOption("-o", "${downloadItem.customFileNameTemplate.removeSuffix(".%(ext)s")}.%(ext)s")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1318,7 +1320,7 @@ class InfoUtil(private val context: Context) {
|
|||
request.addOption("-o", "chapter:%(section_title)s.%(ext)s")
|
||||
}else{
|
||||
if (downloadItem.customFileNameTemplate.isNotBlank()){
|
||||
request.addOption("-o", "${downloadItem.customFileNameTemplate}.%(ext)s")
|
||||
request.addOption("-o", "${downloadItem.customFileNameTemplate.removeSuffix(".%(ext)s")}.%(ext)s")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1351,10 +1353,16 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
var final = java.lang.String.join(" ", arr).replace("\"\"", "\" \"")
|
||||
val ppas = "--config(-locations)? \"(.*?)\"".toRegex().findAll(final)
|
||||
ppas.forEach {
|
||||
val path = "\"(.*?)\"".toRegex().find(it.value)?.value?.replace("\"", "")
|
||||
final = final.replace(it.value, "")
|
||||
final += " ${File(path ?: "").readText()}"
|
||||
ppas.forEach {res ->
|
||||
val path = "\"(.*?)\"".toRegex().find(res.value)?.value?.replace("\"", "")
|
||||
val newVal = runCatching {
|
||||
File(path ?: "").readText()
|
||||
}.onFailure {
|
||||
res.value
|
||||
}.getOrDefault("")
|
||||
|
||||
final = final.replace(res.value, newVal)
|
||||
|
||||
}
|
||||
|
||||
return final
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import android.widget.Toast
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.view.isVisible
|
||||
|
|
@ -543,14 +544,14 @@ object UiUtil {
|
|||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet.setContentView(R.layout.format_details_sheet)
|
||||
|
||||
val formatIdParent = bottomSheet.findViewById<LinearLayout>(R.id.format_id_parent)
|
||||
val formatURLParent = bottomSheet.findViewById<LinearLayout>(R.id.format_url_parent)
|
||||
val containerParent = bottomSheet.findViewById<LinearLayout>(R.id.container_parent)
|
||||
val codecParent = bottomSheet.findViewById<LinearLayout>(R.id.codec_parent)
|
||||
val filesizeParent = bottomSheet.findViewById<LinearLayout>(R.id.filesize_parent)
|
||||
val formatnoteParent = bottomSheet.findViewById<LinearLayout>(R.id.format_note_parent)
|
||||
val fpsParent = bottomSheet.findViewById<LinearLayout>(R.id.fps_parent)
|
||||
val asrParent = bottomSheet.findViewById<LinearLayout>(R.id.asr_parent)
|
||||
val formatIdParent = bottomSheet.findViewById<ConstraintLayout>(R.id.format_id_parent)
|
||||
val formatURLParent = bottomSheet.findViewById<ConstraintLayout>(R.id.format_url_parent)
|
||||
val containerParent = bottomSheet.findViewById<ConstraintLayout>(R.id.container_parent)
|
||||
val codecParent = bottomSheet.findViewById<ConstraintLayout>(R.id.codec_parent)
|
||||
val filesizeParent = bottomSheet.findViewById<ConstraintLayout>(R.id.filesize_parent)
|
||||
val formatnoteParent = bottomSheet.findViewById<ConstraintLayout>(R.id.format_note_parent)
|
||||
val fpsParent = bottomSheet.findViewById<ConstraintLayout>(R.id.fps_parent)
|
||||
val asrParent = bottomSheet.findViewById<ConstraintLayout>(R.id.asr_parent)
|
||||
|
||||
if (format.format_id.isBlank()) formatIdParent?.visibility = View.GONE
|
||||
else {
|
||||
|
|
@ -690,7 +691,7 @@ object UiUtil {
|
|||
}
|
||||
|
||||
|
||||
suspend fun showCommandTemplates(activity: Activity, commandTemplateViewModel: CommandTemplateViewModel, itemSelected: (itemSelected: CommandTemplate) -> Unit) {
|
||||
suspend fun showCommandTemplates(activity: Activity, commandTemplateViewModel: CommandTemplateViewModel, itemSelected: (itemSelected: List<CommandTemplate>) -> Unit) {
|
||||
val bottomSheet = BottomSheetDialog(activity)
|
||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet.setContentView(R.layout.command_template_list)
|
||||
|
|
@ -701,17 +702,33 @@ object UiUtil {
|
|||
}
|
||||
|
||||
linearLayout!!.removeAllViews()
|
||||
val selectedItems = mutableListOf<CommandTemplate>()
|
||||
val ok = bottomSheet.findViewById<MaterialButton>(R.id.command_ok)
|
||||
ok?.isEnabled = list.size == 1
|
||||
|
||||
list.forEach {template ->
|
||||
val item = activity.layoutInflater.inflate(R.layout.command_template_item, linearLayout, false) as MaterialCardView
|
||||
item.findViewById<TextView>(R.id.title).text = template.title
|
||||
item.findViewById<TextView>(R.id.content).text = template.content
|
||||
item.setOnClickListener {
|
||||
itemSelected(template)
|
||||
bottomSheet.cancel()
|
||||
if (selectedItems.contains(template)){
|
||||
selectedItems.remove(template)
|
||||
(it as MaterialCardView).isChecked = false
|
||||
}else{
|
||||
selectedItems.add(template)
|
||||
(it as MaterialCardView).isChecked = true
|
||||
}
|
||||
|
||||
ok?.isEnabled = selectedItems.isNotEmpty()
|
||||
}
|
||||
linearLayout.addView(item)
|
||||
}
|
||||
|
||||
ok?.setOnClickListener {
|
||||
itemSelected(selectedItems.ifEmpty { listOf(list.first()) })
|
||||
bottomSheet.cancel()
|
||||
}
|
||||
|
||||
bottomSheet.show()
|
||||
bottomSheet.window!!.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
|
|
@ -913,9 +930,6 @@ object UiUtil {
|
|||
) { _: DialogInterface?, _: Int -> }
|
||||
|
||||
val dialog = builder.create()
|
||||
editText.doOnTextChanged { _, _, _, _ ->
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
}
|
||||
dialog.show()
|
||||
val imm = context.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
editText!!.postDelayed({
|
||||
|
|
@ -1016,9 +1030,6 @@ object UiUtil {
|
|||
) { _: DialogInterface?, _: Int -> }
|
||||
|
||||
val dialog = builder.create()
|
||||
editText.doOnTextChanged { _, _, _, _ ->
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
}
|
||||
dialog.show()
|
||||
val imm = context.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
editText!!.postDelayed({
|
||||
|
|
|
|||
|
|
@ -116,11 +116,7 @@ class DownloadWorker(
|
|||
"Title: ${downloadItem.title}\n" +
|
||||
"URL: ${downloadItem.url}\n" +
|
||||
"Type: ${downloadItem.type}\n" +
|
||||
if (downloadItem.type != DownloadViewModel.Type.command){
|
||||
"Format: ${downloadItem.format}\n\n"
|
||||
}
|
||||
else { "" } +
|
||||
"Command:\n ${infoUtil.parseYTDLRequestString(request)} ${downloadItem.extraCommands}\n\n",
|
||||
"Command:\n ${infoUtil.parseYTDLRequestString(request)}\n\n",
|
||||
downloadItem.format,
|
||||
downloadItem.type,
|
||||
System.currentTimeMillis(),
|
||||
|
|
|
|||
|
|
@ -100,7 +100,13 @@ class TerminalDownloadWorker(
|
|||
}
|
||||
|
||||
YoutubeDL.getInstance().execute(request, itemId.toString()){ progress, _, line ->
|
||||
setProgressAsync(workDataOf("progress" to progress.toInt(), "output" to line.chunked(5000).first().toString(), "id" to itemId, "log" to logDownloads))
|
||||
runBlocking {
|
||||
line.chunked(10000).forEach {
|
||||
setProgress(workDataOf("progress" to progress.toInt(), "output" to it, "id" to itemId, "log" to logDownloads))
|
||||
Thread.sleep(100)
|
||||
}
|
||||
}
|
||||
|
||||
val title: String = command.take(65)
|
||||
notificationUtil.updateDownloadNotification(
|
||||
itemId,
|
||||
|
|
@ -128,32 +134,46 @@ class TerminalDownloadWorker(
|
|||
}
|
||||
}
|
||||
|
||||
outputFile.appendText("${it.out}\n")
|
||||
if (logDownloads){
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
logRepo.update(it.out, logItem.id)
|
||||
return runBlocking {
|
||||
it.out.chunked(10000).forEach {
|
||||
setProgress(workDataOf("progress" to 100, "output" to it, "id" to itemId, "log" to logDownloads))
|
||||
Thread.sleep(100)
|
||||
}
|
||||
}
|
||||
notificationUtil.cancelDownloadNotification(itemId)
|
||||
|
||||
if (logDownloads){
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
logRepo.update(it.out, logItem.id)
|
||||
}
|
||||
}
|
||||
notificationUtil.cancelDownloadNotification(itemId)
|
||||
return@runBlocking Result.success()
|
||||
}
|
||||
}.onFailure {
|
||||
if (it is YoutubeDL.CanceledException) {
|
||||
return Result.failure()
|
||||
}
|
||||
outputFile.appendText("\n${it.message}\n")
|
||||
if (logDownloads){
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
if (it.message != null){
|
||||
logRepo.update(it.message!!, logItem.id)
|
||||
|
||||
return runBlocking {
|
||||
it.message?.chunked(10000)?.forEach {
|
||||
setProgress(workDataOf("progress" to 100, "output" to it, "id" to itemId, "log" to logDownloads))
|
||||
Thread.sleep(100)
|
||||
}
|
||||
|
||||
if (logDownloads){
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
if (it.message != null){
|
||||
logRepo.update(it.message!!, logItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
File(FileUtil.getDefaultCommandPath() + "/" + itemId).deleteRecursively()
|
||||
Log.e(TAG, context.getString(R.string.failed_download), it)
|
||||
notificationUtil.cancelDownloadNotification(itemId)
|
||||
|
||||
return@runBlocking Result.failure()
|
||||
}
|
||||
File(FileUtil.getDefaultCommandPath() + "/" + itemId).deleteRecursively()
|
||||
|
||||
Log.e(TAG, context.getString(R.string.failed_download), it)
|
||||
notificationUtil.cancelDownloadNotification(itemId)
|
||||
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
return Result.success()
|
||||
|
|
|
|||
|
|
@ -24,8 +24,12 @@
|
|||
android:id="@+id/bottom_sheet_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="false"
|
||||
android:text="@string/command_templates"
|
||||
android:textSize="25sp"
|
||||
android:maxLines="2"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/command_ok"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
|
@ -39,6 +43,18 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/bottom_sheet_title" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/command_ok"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="all"
|
||||
android:text="@string/ok"
|
||||
app:icon="@drawable/ic_check"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
|
@ -15,37 +16,41 @@
|
|||
android:layout_margin="20dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/format_id_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:weightSum="100"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="30"
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:maxLines="2"
|
||||
android:text="@string/format_id"
|
||||
android:textSize="14sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/format_id_value"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/format_id_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="70"
|
||||
android:textSize="14sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/format_url_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -56,29 +61,35 @@
|
|||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="30"
|
||||
android:id="@+id/textView2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:maxLines="2"
|
||||
android:text="@string/url"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
android:textSize="14sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/format_url_value"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/format_url_value"
|
||||
android:layout_width="0dp"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="end"
|
||||
android:layout_weight="70"
|
||||
android:textSize="14sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:maxLines="3"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/container_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -89,26 +100,32 @@
|
|||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="30"
|
||||
android:maxLines="2"
|
||||
android:textSize="14sp"
|
||||
android:text="@string/container"
|
||||
android:id="@+id/textView3"
|
||||
android:layout_width="wrap_content"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:maxLines="2"
|
||||
android:text="@string/container"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/container_value"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/container_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="70"
|
||||
android:textSize="14sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/codec_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -119,25 +136,31 @@
|
|||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="30"
|
||||
android:textSize="14sp"
|
||||
android:text="@string/codec"
|
||||
android:id="@+id/textView4"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:text="@string/codec"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/codec_value"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/codec_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="70"
|
||||
android:textSize="14sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/filesize_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -148,25 +171,31 @@
|
|||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="30"
|
||||
android:id="@+id/textView5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:text="@string/file_size"
|
||||
android:textSize="14sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintEnd_toStartOf="@+id/filesize_value"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/filesize_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="70"
|
||||
android:textSize="14sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/format_note_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -177,25 +206,30 @@
|
|||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:text="@string/quality"
|
||||
android:layout_weight="30"
|
||||
android:textSize="14sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:text="@string/quality"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/format_note_value"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/format_note_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="70"
|
||||
android:textSize="14sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/fps_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -206,25 +240,31 @@
|
|||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="30"
|
||||
android:id="@+id/textView6"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:text="FPS"
|
||||
android:textSize="14sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/fps_value"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fps_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="70"
|
||||
android:textSize="14sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/asr_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -235,23 +275,29 @@
|
|||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="30"
|
||||
android:id="@+id/textView7"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
android:text="@string/audio_samplerate"
|
||||
android:textSize="14sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/asr_value"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/asr_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="70"
|
||||
android:textSize="14sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/format"
|
||||
android:maxLines="2"
|
||||
android:singleLine="false"
|
||||
android:textSize="25sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
|
|
|||
|
|
@ -788,9 +788,8 @@
|
|||
<item>@string/defaultValue</item>
|
||||
<item tools:ignore="Typos">AV1</item>
|
||||
<item>VP9</item>
|
||||
<item tools:ignore="Typos">AVC</item>
|
||||
<item>H265</item>
|
||||
<item>H264</item>
|
||||
<item tools:ignore="Typos">AVC (H264)</item>
|
||||
<item>HEVC (H265)</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="video_codec_values">
|
||||
|
|
@ -799,8 +798,5 @@
|
|||
<item>vp</item>
|
||||
<item>avc</item>
|
||||
<item>hev</item>
|
||||
<item>h264</item>
|
||||
</string-array>
|
||||
|
||||
<string name="auto">Auto</string>
|
||||
</resources>
|
||||
|
|
@ -302,4 +302,5 @@
|
|||
<string name="use_scheduler">Download On Schedule</string>
|
||||
<string name="update_app_beta">Beta Releases</string>
|
||||
<string name="update_app_beta_summary">Enroll in the beta program. It may contain bugs.</string>
|
||||
<string name="auto">Auto</string>
|
||||
</resources>
|
||||
|
|
@ -11,6 +11,12 @@
|
|||
app:summary="en"
|
||||
app:title="@string/language" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/baseline_translate_24"
|
||||
app:key="app_language_13"
|
||||
app:summary="en"
|
||||
app:title="@string/language" />
|
||||
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/themes"
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
|
||||
<EditTextPreference
|
||||
app:key="piped_instance"
|
||||
app:defaultValue="https://api.piped.projectsegfau.lt"
|
||||
app:defaultValue=""
|
||||
android:summary="@string/piped_instance_summary"
|
||||
app:title="@string/piped_instance" />
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue