Compare commits

...

5 Commits

Author SHA1 Message Date
deniscerri d0be97dc34
fx 1 week ago
deniscerri a825321abc
bfix 1 week ago
deniscerri b727be0076
small design tinkering 1 week ago
deniscerri 56976125cf
more stuff 1 week ago
deniscerri 84f13b1c86
add no free space warning 1 week ago

@ -937,7 +937,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
}else {
it.status = DownloadRepository.Status.Queued.toString()
}
if (it.rowNumber == 0) {
if (it.rowNumber == 0 && items.size > 1) {
it.rowNumber = idx + 1
}

@ -22,6 +22,7 @@ import com.deniscerri.ytdl.ui.downloadcard.FormatSelectionBottomSheetDialog.Form
import com.deniscerri.ytdl.ui.downloadcard.FormatTuple
import com.deniscerri.ytdl.ui.downloadcard.MultipleItemFormatTuple
import com.deniscerri.ytdl.util.Extensions.isYoutubeURL
import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.FormatUtil
import com.deniscerri.ytdl.util.UiUtil
import com.google.android.material.snackbar.Snackbar
@ -30,19 +31,22 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.text.Normalizer.Form
import kotlin.text.compareTo
class FormatViewModel(private val application: Application) : AndroidViewModel(application) {
private val downloadRepository: DownloadRepository
val selectedItems = MutableStateFlow(listOf<DownloadItem>())
val selectedItemsSharedFlow = MutableSharedFlow<List<DownloadItem>>(replay = 1)
var formats : Flow<List<FormatRecyclerView>>
var showFilterBtn = MutableStateFlow(false)
var showRefreshBtn = MutableStateFlow(false)
var showFilterBtn = MutableSharedFlow<Boolean>(1)
var showRefreshBtn = MutableSharedFlow<Boolean>(1)
private var canUpdate = true
var canMultiSelectAudio = MutableStateFlow(false)
var isMissingFormats = MutableStateFlow(false)
@ -56,6 +60,9 @@ class FormatViewModel(private val application: Application) : AndroidViewModel(a
var sortBy = FormatSorting.valueOf(sharedPreferences.getString("format_order", "filesize")!!)
var filterBy = MutableStateFlow(FormatCategory.valueOf(sharedPreferences.getString("format_filter", "ALL")!!))
private val _noFreeSpace = MutableSharedFlow<String?>()
val noFreeSpace = _noFreeSpace.asSharedFlow()
init {
downloadRepository = DownloadRepository(DBManager.getInstance(application).downloadDao)
formats = combine(listOf(selectedItemsSharedFlow, filterBy)) { f ->
@ -107,12 +114,10 @@ class FormatViewModel(private val application: Application) : AndroidViewModel(a
showFilterBtn.apply {
val vl = chosenFormats.isNotEmpty() || items.all { it.url.isYoutubeURL() }
value = vl
emit(vl)
}
showRefreshBtn.apply {
val vl = (isMissingFormats.value || items.isEmpty() || items.first().url.isEmpty()) && canUpdate
value = vl
emit(vl)
}
@ -207,21 +212,21 @@ class FormatViewModel(private val application: Application) : AndroidViewModel(a
}
fun setItems(list: List<DownloadItem>, updateFormats: Boolean? = null) = viewModelScope.launch {
canUpdate = updateFormats ?: canUpdate
selectedItems.apply {
value = list
emit(list)
}
selectedItemsSharedFlow.emit(list)
canUpdate = updateFormats ?: canUpdate
}
fun setItem(item: DownloadItem, updateFormats: Boolean? = null) = viewModelScope.launch {
canUpdate = updateFormats ?: canUpdate
selectedItems.apply {
value = listOf(item)
emit(listOf(item))
}
selectedItemsSharedFlow.emit(listOf(item))
canUpdate = updateFormats ?: canUpdate
}
@ -245,4 +250,19 @@ class FormatViewModel(private val application: Application) : AndroidViewModel(a
return formatsToReturn
}
fun checkFreeSpace(size: Long, path: String) = viewModelScope.launch {
_noFreeSpace.emit(null)
if (size > 10L) {
File(FileUtil.formatPath(path)).apply {
if (size > this.freeSpace) {
val warningTxt = application.getString(R.string.no_free_space_warning) +
"\n" + "${application.getString(R.string.file_size)}:\t${FileUtil.convertFileSize(size)}" +
"\n" + "${application.getString(R.string.freespace)}:\t${FileUtil.convertFileSize(this.freeSpace)}"
_noFreeSpace.emit(warningTxt)
}
}
}
}
}

@ -138,11 +138,11 @@ class FormatAdapter(onItemClickListener: OnItemClickListener, activity: Activity
companion object {
private val DIFF_CALLBACK: DiffUtil.ItemCallback<FormatRecyclerView> = object : DiffUtil.ItemCallback<FormatRecyclerView>() {
override fun areItemsTheSame(oldItem: FormatRecyclerView, newItem: FormatRecyclerView): Boolean {
return oldItem.label == newItem.label && oldItem.format?.format_id == newItem.format?.format_id
return oldItem.label == newItem.label && oldItem.format?.format_id == newItem.format?.format_id && oldItem.format?.format_note == newItem.format?.format_note
}
override fun areContentsTheSame(oldItem: FormatRecyclerView, newItem: FormatRecyclerView): Boolean {
return oldItem.label == newItem.label && oldItem.format?.format_id == newItem.format?.format_id
return oldItem.label == newItem.label && oldItem.format?.format_id == newItem.format?.format_id && oldItem.format?.format_note == newItem.format?.format_note
}
}
}

@ -45,6 +45,8 @@ import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
@ -227,12 +229,14 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
val formatCard = view.findViewById<MaterialCardView>(R.id.format_card_constraintLayout)
val chosenFormat = downloadItem.format
UiUtil.populateFormatCard(requireContext(), formatCard, chosenFormat, null, showSize = downloadItem.downloadSections.isEmpty())
val filesize = UiUtil.populateFormatCard(requireContext(), formatCard, chosenFormat, null, showSize = downloadItem.downloadSections.isEmpty())
formatViewModel.checkFreeSpace(filesize, downloadItem.downloadPath)
val listener = object : OnFormatClickListener {
override fun onFormatClick(formatTuple: FormatTuple) {
formatTuple.format?.apply {
downloadItem.format = this
UiUtil.populateFormatCard(requireContext(), formatCard, this, null, showSize = downloadItem.downloadSections.isEmpty())
val filesize = UiUtil.populateFormatCard(requireContext(), formatCard, this, null, showSize = downloadItem.downloadSections.isEmpty())
formatViewModel.checkFreeSpace(filesize, downloadItem.downloadPath)
}
}
@ -253,7 +257,8 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
val preferredFormat = downloadViewModel.getFormat(formats, Type.audio)
downloadItem.format = preferredFormat
downloadItem.allFormats = formats
UiUtil.populateFormatCard(requireContext(), formatCard, preferredFormat, null, showSize = downloadItem.downloadSections.isEmpty())
val filesize = UiUtil.populateFormatCard(requireContext(), formatCard, preferredFormat, null, showSize = downloadItem.downloadSections.isEmpty())
formatViewModel.checkFreeSpace(filesize, downloadItem.downloadPath)
}
}
formatCard.setOnClickListener{
@ -359,7 +364,8 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
},
cutValueChanged = {
downloadItem.downloadSections = it
UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format, showSize = downloadItem.downloadSections.isEmpty())
val filesize = UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format, showSize = downloadItem.downloadSections.isEmpty())
formatViewModel.checkFreeSpace(filesize, downloadItem.downloadPath)
if (it.isNotBlank()){
downloadItem.customFileNameTemplate = downloadItem.customFileNameTemplate.applyFilenameTemplateForCuts()
@ -392,6 +398,16 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
}
}
}
lifecycleScope.launch {
formatViewModel.noFreeSpace.collectLatest {
if (it != null) {
val snack = Snackbar.make(view, it, Snackbar.LENGTH_INDEFINITE)
snack.setTextMaxLines(10)
snack.show()
}
}
}
}
@SuppressLint("RestrictedApi")
@ -400,7 +416,8 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
formats.find { it.format_id == formatID }?.apply {
downloadItem.format = this
val formatCard = requireView().findViewById<MaterialCardView>(R.id.format_card_constraintLayout)
UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format, listOf(), showSize = downloadItem.downloadSections.isEmpty())
val filesize = UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format, listOf(), showSize = downloadItem.downloadSections.isEmpty())
formatViewModel.checkFreeSpace(filesize, downloadItem.downloadPath)
}
}

@ -11,6 +11,7 @@ import android.graphics.Canvas
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.MenuItem
@ -71,6 +72,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.math.abs
@ -196,6 +198,16 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
}
}
lifecycleScope.launch {
formatViewModel.noFreeSpace.collectLatest {
if (it != null) {
val snack = Snackbar.make(view, it, Snackbar.LENGTH_INDEFINITE)
snack.setTextMaxLines(10)
snack.show()
}
}
}
lifecycleScope.launch {
downloadViewModel.processingDownloads.collectLatest { items ->
processingItemsCount = items.size
@ -1013,10 +1025,12 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
}
if (fileSizes.all { it > 5L }){
val size = FileUtil.convertFileSize(fileSizes.sum())
val filesizeRaw = fileSizes.sum()
val size = FileUtil.convertFileSize(filesizeRaw)
itemsFileSize = fileSizes.sum()
filesize.isVisible = size != "?" && !listAdapter.isCheckingItems()
filesize.text = "${getString(R.string.file_size)}: >~ $size"
formatViewModel.checkFreeSpace(filesizeRaw, Environment.getExternalStorageDirectory().path)
}else{
filesize.visibility = View.GONE
}

@ -46,6 +46,8 @@ import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
@ -244,14 +246,15 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
val formatCard = view.findViewById<MaterialCardView>(R.id.format_card_constraintLayout)
val chosenFormat = downloadItem.format
UiUtil.populateFormatCard(
val chosenAudioFormats = downloadItem.allFormats.filter { downloadItem.videoPreferences.audioFormatIDs.contains(it.format_id) }
val filesize = UiUtil.populateFormatCard(
requireContext(),
formatCard,
chosenFormat,
downloadItem.allFormats.filter { downloadItem.videoPreferences.audioFormatIDs.contains(it.format_id) },
chosenAudioFormats,
showSize = downloadItem.downloadSections.isEmpty()
)
formatViewModel.checkFreeSpace(filesize, downloadItem.downloadPath)
val listener = object : OnFormatClickListener {
override fun onFormatClick(formatTuple: FormatTuple) {
@ -262,10 +265,11 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
formatTuple.audioFormats?.map { it.format_id }?.let {
downloadItem.videoPreferences.audioFormatIDs.addAll(it)
}
UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format,
val filesize = UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format,
if(downloadItem.videoPreferences.removeAudio) listOf() else formatTuple.audioFormats,
showSize = downloadItem.downloadSections.isEmpty()
)
formatViewModel.checkFreeSpace(filesize, downloadItem.downloadPath)
}
override fun onFormatsUpdated(allFormats: List<Format>) {
@ -287,10 +291,11 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
val preferredAudioFormats = downloadViewModel.getPreferredAudioFormats(formats)
downloadItem.format = preferredFormat
downloadItem.allFormats = formats
UiUtil.populateFormatCard(requireContext(), formatCard, preferredFormat,
val filesize = UiUtil.populateFormatCard(requireContext(), formatCard, preferredFormat,
if(downloadItem.videoPreferences.removeAudio) listOf() else formats.filter { preferredAudioFormats.contains(it.format_id) },
showSize = downloadItem.downloadSections.isEmpty()
)
formatViewModel.checkFreeSpace(filesize, downloadItem.downloadPath)
}
}
@ -399,7 +404,7 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
},
cutValueChanged = {
downloadItem.downloadSections = it
UiUtil.populateFormatCard(
val filesize = UiUtil.populateFormatCard(
requireContext(),
formatCard,
downloadItem.format,
@ -407,6 +412,7 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
else downloadItem.allFormats.filter { f -> downloadItem.videoPreferences.audioFormatIDs.contains(f.format_id) },
showSize = downloadItem.downloadSections.isEmpty()
)
formatViewModel.checkFreeSpace(filesize, downloadItem.downloadPath)
if (it.isNotBlank()){
downloadItem.customFileNameTemplate = downloadItem.customFileNameTemplate.applyFilenameTemplateForCuts()
@ -428,13 +434,14 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
},
removeAudioClicked = {
downloadItem.videoPreferences.removeAudio = it
UiUtil.populateFormatCard(
val filesize = UiUtil.populateFormatCard(
requireContext(),
formatCard,
downloadItem.format,
if (it) listOf() else downloadItem.allFormats.filter { downloadItem.videoPreferences.audioFormatIDs.contains(it.format_id) },
showSize = downloadItem.downloadSections.isEmpty()
)
formatViewModel.checkFreeSpace(filesize, downloadItem.downloadPath)
},
recodeVideoClicked = {
downloadItem.videoPreferences.recodeVideo = it
@ -479,6 +486,16 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
}
}
}
lifecycleScope.launch {
formatViewModel.noFreeSpace.collectLatest {
if (it != null) {
val snack = Snackbar.make(view, it, Snackbar.LENGTH_INDEFINITE)
snack.setTextMaxLines(10)
snack.show()
}
}
}
}
override fun updateTitleAuthor(t: String, a: String){
@ -510,10 +527,11 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
downloadItem.videoPreferences.audioFormatIDs.clear()
downloadItem.videoPreferences.audioFormatIDs.addAll(arrayListOf(format.format_id))
val formatCard = requireView().findViewById<MaterialCardView>(R.id.format_card_constraintLayout)
UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format,
val filesize = UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format,
if(downloadItem.videoPreferences.removeAudio) listOf() else listOf(format),
showSize = downloadItem.downloadSections.isEmpty()
)
formatViewModel.checkFreeSpace(filesize, downloadItem.downloadPath)
}
private var pathResultLauncher = registerForActivityResult(

@ -225,7 +225,7 @@ class FormatSelectionBottomSheetDialog(
items.first().allFormats.addAll(chosenFormats)
withContext(Dispatchers.Main){
formatViewModel.setItem(items.first())
formatViewModel.setItem(items.first(), false)
listener.onFormatsUpdated(res)
}
}.onFailure { err ->
@ -269,12 +269,13 @@ class FormatSelectionBottomSheetDialog(
}
}
formatViewModel.setItems(items)
formatViewModel.setItems(items, false)
}
withContext(Dispatchers.Main){
filterBtn.isEnabled = true
okBtn.isEnabled = true
refreshBtn.isEnabled = true
}
}catch (e: Exception){
withContext(Dispatchers.Main) {

@ -190,7 +190,12 @@ class FolderSettingsFragment : BaseSettingsFragment() {
}
var cacheSize = File(FileUtil.getCachePath(requireContext())).walkBottomUp().fold(0L) { acc, file -> acc + file.length() }
clearCache!!.summary = "(${FileUtil.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}"
val filesize = if (cacheSize < 10000) {
"0B"
}else {
FileUtil.convertFileSize(cacheSize)
}
clearCache!!.summary = "(${filesize}) ${resources.getString(R.string.clear_temporary_files_summary)}"
clearCache!!.onPreferenceClickListener =
Preference.OnPreferenceClickListener {
lifecycleScope.launch {
@ -214,7 +219,12 @@ class FolderSettingsFragment : BaseSettingsFragment() {
Snackbar.make(requireView(), getString(R.string.cache_cleared), Snackbar.LENGTH_SHORT).show()
cacheSize = File(FileUtil.getCachePath(requireContext())).walkBottomUp().fold(0L) { acc, file -> acc + file.length() }
clearCache!!.summary = "(${FileUtil.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}"
val filesize = if (cacheSize < 10000) {
"0B"
}else {
FileUtil.convertFileSize(cacheSize)
}
clearCache!!.summary = "(${filesize}) ${resources.getString(R.string.clear_temporary_files_summary)}"
}else{
Snackbar.make(requireView(), getString(R.string.downloads_running_try_later), Snackbar.LENGTH_SHORT).show()
}

@ -320,7 +320,7 @@ object Extensions {
Picasso.get()
.load(imageURL)
.resize(1280, 0)
.transform(BlurTransformation(context, 7, 1))
.transform(BlurTransformation(context, 1, 1))
.onlyScaleDown()
.into(this)

@ -27,15 +27,15 @@ class FormatUtil(private var context: Context) {
this.reverse()
}
private val preferSmallerFormats = sharedPreferences.getBoolean("prefer_smaller_formats", false)
@SuppressLint("RestrictedApi")
fun getAudioFormatImportance() : List<String> {
val preferredFormatSize = sharedPreferences.getString("preferred_format_size", "")
if (sharedPreferences.getBoolean("use_format_sorting", false)) {
val itemValues = context.getStringArray(R.array.format_importance_audio_values).toMutableList()
val orderPreferences = sharedPreferences.getString("format_importance_audio", itemValues.joinToString(","))!!.split(",").toMutableList()
if (preferSmallerFormats) {
if (preferredFormatSize == "smallest") {
orderPreferences.remove("file_size")
orderPreferences.add(0,"smallsize")
}
@ -47,10 +47,11 @@ class FormatUtil(private var context: Context) {
return orderPreferences
}else {
val formatImportance = mutableListOf("id","codec", "container", "language", "file_size")
if (sharedPreferences.getBoolean("prefer_smaller_formats", false)) {
formatImportance.add(0, "smallsize")
formatImportance.remove("file_size")
val formatImportance = mutableListOf("id","codec", "container", "language")
if (preferredFormatSize == "smallest") {
formatImportance.add("smallsize")
}else if (preferredFormatSize == "largest") {
formatImportance.add("file_size")
}
val preferContainerOverCodec = sharedPreferences.getBoolean("prefer_container_over_codec_audio", false)
@ -64,20 +65,24 @@ class FormatUtil(private var context: Context) {
@SuppressLint("RestrictedApi")
fun getVideoFormatImportance() : List<String> {
val preferredFormatSize = sharedPreferences.getString("preferred_format_size", "")
if (sharedPreferences.getBoolean("use_format_sorting", false)) {
val itemValues = context.getStringArray(R.array.format_importance_video_values).toList()
val orderPreferences = sharedPreferences.getString("format_importance_video", itemValues.joinToString(","))!!.split(",").toMutableList()
if (preferSmallerFormats) {
if (preferredFormatSize == "smallest") {
orderPreferences.remove("file_size")
orderPreferences.add("smallsize")
}
return orderPreferences
}else {
val formatImportance = mutableListOf("id","resolution", "codec", "container", "file_size")
if (sharedPreferences.getBoolean("prefer_smaller_formats", false)) {
val formatImportance = mutableListOf("id","resolution", "codec", "container")
if (preferredFormatSize == "smallest") {
formatImportance.add("smallsize")
formatImportance.remove("file_size")
}else if (preferredFormatSize == "largest") {
formatImportance.add("file_size")
}
return formatImportance
@ -101,9 +106,13 @@ class FormatUtil(private var context: Context) {
result
}
"id" -> {
(audioFormatIDPreference.contains(b.format_id)).compareTo(
audioFormatIDPreference.contains(a.format_id)
)
if (audioFormatIDPreference.isEmpty()) {
0
}else {
(audioFormatIDPreference.contains(b.format_id)).compareTo(
audioFormatIDPreference.contains(a.format_id)
)
}
}
"language" -> {
@ -119,18 +128,27 @@ class FormatUtil(private var context: Context) {
}
"codec" -> {
("^(${audioCodecPreference}).*$".toRegex(RegexOption.IGNORE_CASE)
if (audioCodecPreference.isBlank()) {
0
}else {
("^(${audioCodecPreference}).*$".toRegex(RegexOption.IGNORE_CASE)
.matches(b.acodec))
.compareTo(
"^(${audioCodecPreference}).*$".toRegex(RegexOption.IGNORE_CASE)
.matches(a.acodec)
)
}
}
"container" -> {
(audioContainerPreference == b.container).compareTo(
audioContainerPreference == a.container
)
if (audioContainerPreference.isBlank()) {
0
}else {
(audioContainerPreference == b.container).compareTo(
audioContainerPreference == a.container
)
}
}
else -> 0
@ -160,12 +178,20 @@ class FormatUtil(private var context: Context) {
result
}
"id" -> {
videoFormatIDPreference.contains(b.format_id).compareTo(videoFormatIDPreference.contains(a.format_id))
if (videoFormatIDPreference.isEmpty()) {
0
}else {
videoFormatIDPreference.contains(b.format_id).compareTo(videoFormatIDPreference.contains(a.format_id))
}
}
"codec" -> {
val first = videoCodecPreference.toRegex(RegexOption.IGNORE_CASE).containsMatchIn(b.vcodec.uppercase())
val second = videoCodecPreference.toRegex(RegexOption.IGNORE_CASE).containsMatchIn(a.vcodec.uppercase())
first.compareTo(second)
if (videoCodecPreference.isBlank()) {
0
}else {
val first = videoCodecPreference.toRegex(RegexOption.IGNORE_CASE).containsMatchIn(b.vcodec.uppercase())
val second = videoCodecPreference.toRegex(RegexOption.IGNORE_CASE).containsMatchIn(a.vcodec.uppercase())
first.compareTo(second)
}
}
"resolution" -> {
when (videoQualityPreference) {
@ -201,8 +227,12 @@ class FormatUtil(private var context: Context) {
(b.acodec == "none" || b.acodec == "").compareTo(a.acodec == "none" || a.acodec == "")
}
"container" -> {
videoContainerPreference.equals(b.container, ignoreCase = true)
.compareTo(videoContainerPreference.equals(a.container, ignoreCase = true))
if (videoContainerPreference.isBlank()) {
0
}else {
videoContainerPreference.equals(b.container, ignoreCase = true)
.compareTo(videoContainerPreference.equals(a.container, ignoreCase = true))
}
}
else -> 0
}

@ -108,7 +108,8 @@ import java.util.Locale
object UiUtil {
@SuppressLint("SetTextI18n")
fun populateFormatCard(context: Context, formatCard : MaterialCardView, chosenFormat: Format, audioFormats: List<Format>? = null, showSize: Boolean = true){
//return filesize
fun populateFormatCard(context: Context, formatCard : MaterialCardView, chosenFormat: Format, audioFormats: List<Format>? = null, showSize: Boolean = true) : Long {
var formatNote = chosenFormat.format_note
if (formatNote.isEmpty()) formatNote = context.getString(R.string.defaultValue)
else if (formatNote == "best") formatNote = context.getString(R.string.best_quality)
@ -185,6 +186,12 @@ object UiUtil {
}
}
if (showSize) {
return filesize
}else {
return 0
}
}
fun populateCommandCard(card: MaterialCardView, item: CommandTemplate){

@ -1288,7 +1288,7 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
"smallsize" -> {
formatSorting.add("+size")
}
"filesize" -> {
"file_size" -> {
formatSorting.add("size")
}
"no_audio" -> {

@ -339,6 +339,12 @@ class NewPipeUtil(context: Context) {
formats.add(formatObj)
}
val hasDefaultFormat = formats.firstOrNull { it.format_note.contains("ORIGINAL", true) }
if (hasDefaultFormat != null) {
formats.remove(hasDefaultFormat)
formats.add(0, hasDefaultFormat)
}
}
if (stream.videoStreams.isNotEmpty()){
@ -385,7 +391,6 @@ class NewPipeUtil(context: Context) {
defaultLang?.format_id = (defaultLang?.format_id?.split("-")?.get(0) ?: "") + "-${it.value.size-1}"
}
}
formats.sortByDescending { it.filesize }
}
val chapters = ArrayList<ChapterItem>()

@ -18,7 +18,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="20dp"
app:cardElevation="5dp"
app:cardElevation="0dp"
android:checkable="true"
app:strokeWidth="0dp"
app:cardPreventCornerOverlap="true"
@ -126,7 +126,6 @@
android:maxLines="2"
android:paddingStart="10dp"
android:paddingEnd="5dp"
android:shadowColor="@color/black"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="1"
@ -162,11 +161,10 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:animateLayoutChanges="true"
app:layout_constraintBottom_toTopOf="@+id/output"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="5dp"
app:layout_constraintTop_toBottomOf="@+id/linearlayout2_horizontalscrollview"
app:layout_constraintVertical_bias="0.51"
app:layout_constraintTop_toTopOf="parent"
>
<com.google.android.material.button.MaterialButton
@ -213,18 +211,21 @@
android:ellipsize="end"
android:focusable="true"
android:fontFamily="monospace"
android:maxLines="2"
android:gravity="bottom"
android:maxLines="2"
android:padding="10dp"
android:shadowColor="#000"
android:shadowDx="4"
android:shadowDy="4"
android:shadowRadius="2"
android:textStyle="bold"
android:textColor="#FFF"
android:textSize="11sp"
app:layout_constraintVertical_bias="1.0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/active_pause_cancel_btns" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -20,7 +20,7 @@
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="20dp"
app:cardElevation="10dp"
app:cardElevation="0dp"
app:cardMaxElevation="12dp"
android:checkable="true"
app:strokeWidth="0dp"

@ -29,6 +29,7 @@
style="@style/Widget.Material3.Chip.Filter.Elevated"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:outlineProvider="none"
android:checked="false"
android:text="@string/embed_thumb"/>
@ -38,6 +39,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:outlineProvider="none"
android:visibility="gone"
android:text="@string/crop_thumb"/>
@ -47,6 +49,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:outlineProvider="none"
android:text="@string/split_by_chapters"/>
</com.google.android.material.chip.ChipGroup>
@ -54,15 +57,15 @@
</HorizontalScrollView>
<HorizontalScrollView
android:scrollbars="none"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
android:layout_height="wrap_content"
android:scrollbars="none">
<com.google.android.material.chip.ChipGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipSpacingVertical="0dp"
app:singleLine="true"
android:layout_height="wrap_content">
app:singleLine="true">
<com.google.android.material.chip.Chip
@ -71,10 +74,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minWidth="30dp"
android:outlineProvider="none"
android:text="@string/sponsorblock"
app:chipIconVisible="true"
app:chipIcon="@drawable/ic_money"
android:minWidth="30dp"
app:chipIconVisible="true"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -86,10 +90,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minWidth="30dp"
android:outlineProvider="none"
android:text="@string/bitrate"
app:chipIconVisible="true"
app:chipIcon="@drawable/baseline_high_quality_24"
android:minWidth="30dp"
app:chipIconVisible="true"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -101,10 +106,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:outlineProvider="none"
android:minWidth="30dp"
android:text="@string/file_name_template"
app:chipIconVisible="true"
app:chipIcon="@drawable/ic_edit"
android:minWidth="30dp"
app:chipIconVisible="true"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -114,7 +120,7 @@
</com.google.android.material.chip.ChipGroup>
</HorizontalScrollView>
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="match_parent">
@ -130,6 +136,8 @@
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/use_extra_commands"
android:outlineProvider="none"
app:chipIconVisible="true"
app:chipIcon="@drawable/ic_terminal"
android:minWidth="30dp"
@ -145,6 +153,7 @@
android:layout_height="wrap_content"
android:gravity="center"
app:chipIconVisible="true"
android:outlineProvider="none"
app:chipIcon="@drawable/ic_cut"
android:text="@string/cut"
android:minWidth="30dp"

@ -31,6 +31,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:outlineProvider="none"
android:text="@string/save_thumb" />
<com.google.android.material.chip.Chip
@ -39,6 +40,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:outlineProvider="none"
android:text="@string/add_chapter" />
<com.google.android.material.chip.Chip
@ -47,6 +49,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:outlineProvider="none"
android:text="@string/split_by_chapters"/>
@ -76,6 +79,7 @@
app:chipIcon="@drawable/ic_subtitles"
android:minWidth="30dp"
app:cornerRadius="10dp"
android:outlineProvider="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -90,6 +94,7 @@
android:text="@string/remove_audio"
android:visibility="gone"
app:cornerRadius="10dp"
android:outlineProvider="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -105,6 +110,7 @@
app:chipIcon="@drawable/ic_music"
android:minWidth="30dp"
app:cornerRadius="10dp"
android:outlineProvider="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -116,6 +122,7 @@
android:layout_height="wrap_content"
android:checked="false"
app:chipIconVisible="true"
android:outlineProvider="none"
app:chipIcon="@drawable/baseline_video_metadata"
android:text="@string/recode_video" />
@ -130,6 +137,7 @@
app:chipIcon="@drawable/baseline_live_tv_24"
android:minWidth="30dp"
app:cornerRadius="10dp"
android:outlineProvider="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -160,6 +168,7 @@
app:chipIcon="@drawable/ic_money"
android:minWidth="30dp"
app:cornerRadius="10dp"
android:outlineProvider="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -175,6 +184,7 @@
app:chipIcon="@drawable/ic_edit"
android:minWidth="30dp"
app:cornerRadius="10dp"
android:outlineProvider="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -204,6 +214,7 @@
app:chipIcon="@drawable/ic_terminal"
android:minWidth="30dp"
app:cornerRadius="10dp"
android:outlineProvider="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -219,6 +230,7 @@
android:minWidth="30dp"
android:text="@string/cut"
app:cornerRadius="10dp"
android:outlineProvider="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

@ -281,6 +281,7 @@
android:layout_marginEnd="10dp"
android:layout_height="wrap_content"
android:text="@string/cancel"
android:outlineProvider="none"
app:icon="@drawable/ic_baseline_delete_outline_24"/>
<Button
@ -289,6 +290,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cut"
android:outlineProvider="none"
app:icon="@drawable/ic_check"/>
</LinearLayout>

@ -119,6 +119,7 @@
android:layout_margin="20dp"
android:text="@string/ok"
app:icon="@drawable/ic_check"
android:outlineProvider="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

@ -118,6 +118,7 @@
android:maxLength="17"
android:minWidth="30dp"
android:paddingHorizontal="5dp"
android:outlineProvider="none"
android:textStyle="bold"
app:cornerRadius="10dp"
app:drawableStartCompat="@drawable/ic_music_formatcard"
@ -136,6 +137,7 @@
android:backgroundTint="?attr/colorSecondary"
android:clickable="false"
android:gravity="center"
android:outlineProvider="none"
android:maxWidth="90dp"
android:maxLines="1"
android:minWidth="30dp"
@ -157,6 +159,7 @@
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:outlineProvider="none"
android:paddingHorizontal="5dp"
android:textStyle="bold"
app:cornerRadius="10dp"
@ -176,6 +179,7 @@
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="5dp"
android:outlineProvider="none"
android:textStyle="bold"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"

@ -64,6 +64,7 @@
android:id="@+id/format_filter"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:stateListAnimator="@null"
android:layout_height="wrap_content"
app:icon="@drawable/baseline_align_horizontal_left_24"
app:layout_constraintBottom_toBottomOf="@id/format_refresh"
@ -76,6 +77,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="all"
android:stateListAnimator="@null"
android:text="@string/update"
android:contentDescription="@string/update_formats"
android:layout_marginStart="10dp"

@ -17,7 +17,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="20dp"
app:cardElevation="5dp"
app:cardElevation="0dp"
app:checkedIcon="@null"
app:cardMaxElevation="12dp"
android:checkable="true"

@ -25,7 +25,7 @@
android:layout_marginVertical="5dp"
android:checkable="false"
app:cardCornerRadius="15dp"
app:cardElevation="5dp"
app:cardElevation="0dp"
app:cardMaxElevation="12dp"
app:cardPreventCornerOverlap="true"
app:checkedIcon="@null"
@ -39,7 +39,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="20dp"
app:cardElevation="5dp"
app:cardElevation="0dp"
app:checkedIcon="@null"
app:cardMaxElevation="12dp"
android:checkable="true"

@ -20,7 +20,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="20dp"
app:cardElevation="5dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorPrimary"
app:checkedIconTint="?attr/colorPrimary"
app:cardMaxElevation="12dp"

@ -20,7 +20,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="20dp"
app:cardElevation="5dp"
app:cardElevation="0dp"
app:cardBackgroundColor="?attr/colorSurfaceContainer"
app:strokeColor="?attr/colorPrimary"
app:checkedIconTint="?attr/colorPrimary"

@ -16,7 +16,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="20dp"
app:cardElevation="10dp"
app:cardElevation="0dp"
app:cardMaxElevation="12dp"
app:cardBackgroundColor="@color/grey"
app:cardPreventCornerOverlap="true"

@ -1574,4 +1574,16 @@
<item>64k</item>
</string-array>
<string-array name="preferred_format_size">
<item>@string/defaultValue</item>
<item>@string/smallest</item>
<item>@string/largest</item>
</string-array>
<string-array name="preferred_format_size_values">
<item></item>
<item>smallest</item>
<item>largest</item>
</string-array>
</resources>

@ -485,4 +485,8 @@
<string name="no_keep_subs_summary">When using both Embed Subtitles and Write Subtitles, don\'t keep the subtitle files after embedding</string>
<string name="video_compatible">Compatible Video</string>
<string name="video_compatible_summary">Recodes the video making it compatible with other apps</string>
<string name="no_free_space_warning">There is no free space for this configuration.</string>
<string name="preferred_format_size">Preferred Format Size</string>
<string name="smallest">Smallest</string>
<string name="largest">Largest</string>
</resources>

@ -283,13 +283,15 @@
<PreferenceCategory android:title="@string/format">
<SwitchPreferenceCompat
android:widgetLayout="@layout/preferece_material_switch"
app:defaultValue="false"
<ListPreference
app:icon="@drawable/ic_format"
app:key="prefer_smaller_formats"
app:title="@string/prefer_smaller_formats" />
app:dialogTitle="@string/preferred_format_size"
app:entries="@array/preferred_format_size"
app:entryValues="@array/preferred_format_size_values"
android:defaultValue=""
app:key="preferred_format_size"
app:useSimpleSummaryProvider="true"
app:title="@string/preferred_format_size" />
</PreferenceCategory>

Loading…
Cancel
Save