From 2d08d2f6430169c75c24ddd277536065fafd2413 Mon Sep 17 00:00:00 2001 From: deniscerri <64997243+deniscerri@users.noreply.github.com> Date: Sat, 16 Sep 2023 14:22:01 +0200 Subject: [PATCH] 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 --- app/build.gradle | 2 +- .../ytdlnis/adapter/GenericDownloadAdapter.kt | 11 +- .../ytdlnis/database/dao/DownloadDao.kt | 12 +- .../database/models/DownloadItemSimple.kt | 21 ++ .../database/repository/DownloadRepository.kt | 14 +- .../database/viewmodel/DownloadViewModel.kt | 71 +++--- .../ytdlnis/receiver/ShareActivity.kt | 2 +- .../com/deniscerri/ytdlnis/ui/HomeFragment.kt | 16 +- .../ui/downloadcard/AddExtraCommandsDialog.kt | 6 +- .../downloadcard/DownloadCommandFragment.kt | 11 +- .../DownloadMultipleBottomSheetDialog.kt | 12 +- .../downloads/CancelledDownloadsFragment.kt | 4 +- .../ui/downloads/ErroredDownloadsFragment.kt | 4 +- .../ui/downloads/QueuedDownloadsFragment.kt | 2 +- .../ui/downloads/SavedDownloadsFragment.kt | 4 +- .../ytdlnis/ui/more/TerminalActivity.kt | 51 +--- .../more/settings/GeneralSettingsFragment.kt | 34 ++- .../ui/more/settings/MainSettingsFragment.kt | 19 +- .../com/deniscerri/ytdlnis/util/FileUtil.kt | 2 +- .../com/deniscerri/ytdlnis/util/InfoUtil.kt | 68 +++--- .../com/deniscerri/ytdlnis/util/UiUtil.kt | 45 ++-- .../deniscerri/ytdlnis/work/DownloadWorker.kt | 6 +- .../ytdlnis/work/TerminalDownloadWorker.kt | 52 ++-- .../main/res/layout/command_template_list.xml | 16 ++ .../main/res/layout/format_details_sheet.xml | 222 +++++++++++------- .../res/layout/format_select_bottom_sheet.xml | 2 + app/src/main/res/values/arrays.xml | 8 +- app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/general_preferences.xml | 6 + app/src/main/res/xml/updating_preferences.xml | 2 +- 30 files changed, 422 insertions(+), 304 deletions(-) create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItemSimple.kt diff --git a/app/build.gradle b/app/build.gradle index 50cb1cf4..3e9fb912 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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){ diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/GenericDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/GenericDownloadAdapter.kt index aa59eaad..16518b30 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/GenericDownloadAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/GenericDownloadAdapter.kt @@ -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(DIFF_CALLBACK) { +class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : PagingDataAdapter(DIFF_CALLBACK) { private val onItemClickListener: OnItemClickListener private val activity: Activity val checkedItems: ArrayList @@ -73,7 +74,7 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: } val duration = card.findViewById(R.id.duration) - duration.text = item!!.duration + duration.text = item.duration // TITLE ---------------------------------- val itemTitle = card.findViewById(R.id.title) @@ -204,13 +205,13 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: } companion object { - private val DIFF_CALLBACK: DiffUtil.ItemCallback = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean { + private val DIFF_CALLBACK: DiffUtil.ItemCallback = object : DiffUtil.ItemCallback() { + 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 } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt index fcbcb661..eabfa80b 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt @@ -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> @Query("SELECT * FROM downloads WHERE status='Queued' or status='QueuedPaused' ORDER BY downloadStartTime, id") - fun getQueuedDownloads() : PagingSource + fun getQueuedDownloads() : PagingSource @Query("SELECT format FROM downloads WHERE status='Queued' or status='QueuedPaused'") fun getSelectedFormatFromQueued() : List @@ -49,7 +50,7 @@ interface DownloadDao { fun getQueuedDownloadsList() : List @Query("SELECT * FROM downloads WHERE status='Cancelled' ORDER BY id DESC") - fun getCancelledDownloads() : PagingSource + fun getCancelledDownloads() : PagingSource @Query("SELECT * FROM downloads WHERE status='Cancelled' ORDER BY id DESC") fun getCancelledDownloadsList() : List @@ -58,13 +59,13 @@ interface DownloadDao { fun getPausedDownloadsList() : List @Query("SELECT * FROM downloads WHERE status='Error' ORDER BY id DESC") - fun getErroredDownloads() : PagingSource + fun getErroredDownloads() : PagingSource @Query("SELECT * FROM downloads WHERE status='Error' ORDER BY id DESC") fun getErroredDownloadsList() : List @Query("SELECT * FROM downloads WHERE status='Saved' ORDER BY id DESC") - fun getSavedDownloads() : PagingSource + fun getSavedDownloads() : PagingSource @Query("SELECT * FROM downloads WHERE status='Saved' ORDER BY id DESC") fun getSavedDownloadsList() : List @@ -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) + @Query("UPDATE downloads SET status='Cancelled' WHERE status='Queued' or status='QueuedPaused'") suspend fun cancelQueued() diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItemSimple.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItemSimple.kt new file mode 100644 index 00000000..638b3d4f --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItemSimple.kt @@ -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? +) \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt index e32cce30..1a536f01 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt @@ -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> = downloadDao.getActiveDownloads() - val queuedDownloads : Pager = Pager( + val queuedDownloads : Pager = Pager( config = PagingConfig(pageSize = 20, initialLoadSize = 20, prefetchDistance = 1), pagingSourceFactory = {downloadDao.getQueuedDownloads()} ) - val cancelledDownloads : Pager = Pager( + val cancelledDownloads : Pager = Pager( config = PagingConfig(pageSize = 20, initialLoadSize = 20, prefetchDistance = 1), pagingSourceFactory = {downloadDao.getCancelledDownloads()} ) - val erroredDownloads : Pager = Pager( + val erroredDownloads : Pager = Pager( config = PagingConfig(pageSize = 20, initialLoadSize = 20, prefetchDistance = 1), pagingSourceFactory = {downloadDao.getErroredDownloads()} ) - val savedDownloads : Pager = Pager( + val savedDownloads : Pager = 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){ + downloadDao.deleteAllWithIDs(ids) + + } + suspend fun cancelQueued(){ downloadDao.cancelQueued() } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt index 8deab4ea..08f69d59 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt @@ -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> - val queuedDownloads : Flow> + val queuedDownloads : Flow> val activeDownloads : LiveData> val activeDownloadsCount : LiveData - val cancelledDownloads : Flow> - val erroredDownloads : Flow> - val savedDownloads : Flow> + val cancelledDownloads : Flow> + val erroredDownloads : Flow> + val savedDownloads : Flow> 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() 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() 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 = 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) = viewModelScope.launch(Dispatchers.IO){ + Log.e("Aa", ids.size.toString()) + repository.deleteAllWithIDs(ids) + } + fun cancelQueued() = viewModelScope.launch(Dispatchers.IO) { repository.cancelQueued() } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt index ebb809dc..aae9bdf3 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt @@ -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){ diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt index cfe0b4fa..c52b11cf 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt @@ -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(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(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") } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/AddExtraCommandsDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/AddExtraCommandsDialog.kt index 08f2e02a..fbcce7b7 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/AddExtraCommandsDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/AddExtraCommandsDialog.kt @@ -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) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt index 28f90922..94058679 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt @@ -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 { " " } ) } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt index 59de8e05..1a948230 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt @@ -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 c.content } + ) + items.forEach { f -> f.format = format } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/CancelledDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/CancelledDownloadsFragment.kt index b51d2f89..7587f8ae 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/CancelledDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/CancelledDownloadsFragment.kt @@ -202,9 +202,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic } adapter.clearCheckedItems() - for (id in selectedObjects){ - downloadViewModel.deleteDownload(id) - } + downloadViewModel.deleteAllWithID(selectedObjects) actionMode?.finish() } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ErroredDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ErroredDownloadsFragment.kt index 9068aa8e..12cb091f 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ErroredDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ErroredDownloadsFragment.kt @@ -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() } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt index 85c7a64e..2ca78f45 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt @@ -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() } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/SavedDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/SavedDownloadsFragment.kt index 259f2507..a4df73d0 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/SavedDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/SavedDownloadsFragment.kt @@ -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() } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/TerminalActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/TerminalActivity.kt index 0ca74e42..06b75552 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/TerminalActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/TerminalActivity.kt @@ -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() 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( diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt index 999a459c..518e1fd2 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt @@ -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 = diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/MainSettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/MainSettingsFragment.kt index 41a9274d..b0815c6c 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/MainSettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/MainSettingsFragment.kt @@ -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!!) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/FileUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/FileUtil.kt index 55d4ad4a..c8fb3a4d 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/FileUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/FileUtil.kt @@ -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) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt index 2a3075f6..3f3ccff0 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt @@ -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 { items = ArrayList() - val webpage_urls = mutableListOf() 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 diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt index d0bfbdd0..556d9212 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt @@ -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(R.id.format_id_parent) - val formatURLParent = bottomSheet.findViewById(R.id.format_url_parent) - val containerParent = bottomSheet.findViewById(R.id.container_parent) - val codecParent = bottomSheet.findViewById(R.id.codec_parent) - val filesizeParent = bottomSheet.findViewById(R.id.filesize_parent) - val formatnoteParent = bottomSheet.findViewById(R.id.format_note_parent) - val fpsParent = bottomSheet.findViewById(R.id.fps_parent) - val asrParent = bottomSheet.findViewById(R.id.asr_parent) + val formatIdParent = bottomSheet.findViewById(R.id.format_id_parent) + val formatURLParent = bottomSheet.findViewById(R.id.format_url_parent) + val containerParent = bottomSheet.findViewById(R.id.container_parent) + val codecParent = bottomSheet.findViewById(R.id.codec_parent) + val filesizeParent = bottomSheet.findViewById(R.id.filesize_parent) + val formatnoteParent = bottomSheet.findViewById(R.id.format_note_parent) + val fpsParent = bottomSheet.findViewById(R.id.fps_parent) + val asrParent = bottomSheet.findViewById(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) -> 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() + val ok = bottomSheet.findViewById(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(R.id.title).text = template.title item.findViewById(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({ diff --git a/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt b/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt index ba34dd2b..4b33d3fc 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt @@ -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(), diff --git a/app/src/main/java/com/deniscerri/ytdlnis/work/TerminalDownloadWorker.kt b/app/src/main/java/com/deniscerri/ytdlnis/work/TerminalDownloadWorker.kt index 8b8170bd..f128204f 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/work/TerminalDownloadWorker.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/work/TerminalDownloadWorker.kt @@ -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() diff --git a/app/src/main/res/layout/command_template_list.xml b/app/src/main/res/layout/command_template_list.xml index 6e54e834..022d0c8b 100644 --- a/app/src/main/res/layout/command_template_list.xml +++ b/app/src/main/res/layout/command_template_list.xml @@ -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" /> +