diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 808701eb..376d9f73 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
-
+
diff --git a/app/src/main/java/com/deniscerri/ytdl/database/dao/DownloadDao.kt b/app/src/main/java/com/deniscerri/ytdl/database/dao/DownloadDao.kt
index 8c522a42..dd71e4af 100644
--- a/app/src/main/java/com/deniscerri/ytdl/database/dao/DownloadDao.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/database/dao/DownloadDao.kt
@@ -153,6 +153,9 @@ interface DownloadDao {
@Query("SELECT * FROM downloads WHERE id=:id LIMIT 1")
fun getDownloadById(id: Long) : DownloadItem
+ @Query("SELECT * FROM downloads WHERE id=:id LIMIT 1")
+ fun getNullableDownloadById(id: Long) : DownloadItem?
+
@Query("SELECT * FROM downloads WHERE id IN (:ids)")
fun getDownloadsByIds(ids: List) : List
diff --git a/app/src/main/java/com/deniscerri/ytdl/database/repository/DownloadRepository.kt b/app/src/main/java/com/deniscerri/ytdl/database/repository/DownloadRepository.kt
index 63441716..7d704d99 100644
--- a/app/src/main/java/com/deniscerri/ytdl/database/repository/DownloadRepository.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/database/repository/DownloadRepository.kt
@@ -106,8 +106,8 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
}
}
- suspend fun update(item: DownloadItem){
- downloadDao.update(item)
+ suspend fun update(item: DownloadItem) : Long {
+ return downloadDao.update(item)
}
suspend fun updateAll(list: List) : List {
diff --git a/app/src/main/java/com/deniscerri/ytdl/database/repository/HistoryRepository.kt b/app/src/main/java/com/deniscerri/ytdl/database/repository/HistoryRepository.kt
index f9c3023a..077da7f6 100644
--- a/app/src/main/java/com/deniscerri/ytdl/database/repository/HistoryRepository.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/database/repository/HistoryRepository.kt
@@ -106,25 +106,37 @@ class HistoryRepository(private val historyDao: HistoryDao) {
suspend fun deleteAllWithIDs(ids: List, deleteFile: Boolean = false){
if (deleteFile){
- historyDao.getAllHistoryByIDs(ids).forEach { item ->
- item.downloadPath.forEach {
- FileUtil.deleteFile(it)
+ ids.chunked(500).forEach { chunks ->
+ historyDao.getAllHistoryByIDs(chunks).forEach { item ->
+ item.downloadPath.forEach {
+ FileUtil.deleteFile(it)
+ }
}
}
+
}
- historyDao.deleteAllByIDs(ids)
+ ids.chunked(500).forEach { chunks ->
+ historyDao.deleteAllByIDs(chunks)
+ }
+
}
suspend fun deleteAllWithIDsCheckFiles(ids: List){
val idsToDelete = mutableListOf()
- historyDao.getAllHistoryByIDs(ids).forEach { item ->
- val filesNotPresent = item.downloadPath.all { !File(it).exists() && it.isNotBlank()}
- if (filesNotPresent) {
- idsToDelete.add(item.id)
+ ids.chunked(500).forEach { chunks ->
+ historyDao.getAllHistoryByIDs(chunks).forEach { item ->
+ val filesNotPresent = item.downloadPath.all { !File(it).exists() && it.isNotBlank()}
+ if (filesNotPresent) {
+ idsToDelete.add(item.id)
+ }
}
}
+
if (idsToDelete.isNotEmpty()) {
- historyDao.deleteAllByIDs(idsToDelete)
+ idsToDelete.chunked(500).forEach { chunked ->
+ historyDao.deleteAllByIDs(chunked)
+ }
+
}
}
@@ -133,8 +145,12 @@ class HistoryRepository(private val historyDao: HistoryDao) {
)
fun getDownloadPathsFromIDs(ids: List) : List> {
- val res = historyDao.getDownloadPathsFromIDs(ids)
- return res.map { it.downloadPath }
+ val res : MutableList> = mutableListOf()
+ ids.chunked(500).forEach { chunks ->
+ val tmp = historyDao.getDownloadPathsFromIDs(chunks)
+ res.addAll(tmp.map { it.downloadPath })
+ }
+ return res
}
suspend fun deleteDuplicates(){
diff --git a/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt b/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt
index 81d1891e..0655b6c5 100644
--- a/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt
@@ -12,6 +12,7 @@ import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.util.Extensions.isYoutubeChannelURL
import com.deniscerri.ytdl.util.Extensions.isYoutubeURL
import com.deniscerri.ytdl.util.Extensions.isYoutubeWatchVideosURL
+import com.deniscerri.ytdl.util.Extensions.needsDataUpdating
import com.deniscerri.ytdl.util.extractors.GoogleApiUtil
import com.deniscerri.ytdl.util.extractors.newpipe.NewPipeUtil
import com.deniscerri.ytdl.util.extractors.YTDLPUtil
@@ -414,7 +415,7 @@ class ResultRepository(private val resultDao: ResultDao, private val context: Co
suspend fun updateDownloadItem(
downloadItem: DownloadItem
) : DownloadItem? {
- if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){
+ if (downloadItem.needsDataUpdating()){
runCatching {
val info = getResultsFromSource(downloadItem.url, resetResults = false, addToResults = false, singleItem = true).first()
if (downloadItem.title.isEmpty()) downloadItem.title = info.title
diff --git a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt
index 68956377..880af2df 100644
--- a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt
@@ -39,12 +39,14 @@ import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.database.repository.HistoryRepository
import com.deniscerri.ytdl.database.repository.ResultRepository
import com.deniscerri.ytdl.ui.downloadcard.MultipleItemFormatTuple
+import com.deniscerri.ytdl.util.Extensions.needsDataUpdating
import com.deniscerri.ytdl.util.Extensions.toListString
import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.FormatUtil
import com.deniscerri.ytdl.util.NotificationUtil
import com.deniscerri.ytdl.util.extractors.YTDLPUtil
import com.deniscerri.ytdl.work.AlarmScheduler
+import com.deniscerri.ytdl.work.UpdateMultipleDownloadsDataWorker
import com.deniscerri.ytdl.work.UpdateMultipleDownloadsFormatsWorker
import com.google.gson.Gson
import com.yausername.youtubedl_android.YoutubeDL
@@ -217,6 +219,14 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
repository.update(item)
}
+ suspend fun putToSaved(item: DownloadItem) {
+ item.status = DownloadRepository.Status.Saved.toString()
+ val id = repository.update(item)
+ if (item.needsDataUpdating()) {
+ continueUpdatingDataInBackground(listOf(id))
+ }
+ }
+
fun getItemByID(id: Long) : DownloadItem {
return repository.getItemByID(id)
}
@@ -641,7 +651,10 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
//repository.insert(downloadItem)
}
}
- repository.insertAll(toInsert)
+ toInsert.chunked(500).forEach { chunked ->
+ repository.insertAll(chunked)
+ }
+
processingItems.emit(false)
} catch (e: Exception) {
deleteProcessing()
@@ -678,7 +691,9 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
//repository.insert(downloadItem)
}
}
- repository.insertAll(toInsert)
+ toInsert.chunked(500).forEach { chunked ->
+ repository.insertAll(chunked)
+ }
processingItems.emit(false)
}catch (e: Exception) {
deleteProcessing()
@@ -1031,27 +1046,8 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
result.message = repository.startDownloadWorker(queued, context).getOrElse { "" }
- if(!useScheduler){
- CoroutineScope(Dispatchers.IO).launch {
- queued.filter { it.downloadStartTime != 0L && (it.title.isEmpty() || it.author.isEmpty() || it.thumb.isEmpty()) }.forEach {
- kotlin.runCatching {
- resultRepository.updateDownloadItem(it)?.apply {
- repository.updateWithoutUpsert(this)
- }
- }
- }
- }
- }else{
- CoroutineScope(Dispatchers.IO).launch {
- queued.filter { it.title.isEmpty() || it.author.isEmpty() || it.thumb.isEmpty() }.forEach {
- kotlin.runCatching {
- resultRepository.updateDownloadItem(it)?.apply {
- repository.updateWithoutUpsert(this)
- }
- }
- }
- }
- }
+ val ids = queued.filter { it.needsDataUpdating() }.map { it.id }
+ continueUpdatingDataInBackground(ids)
}
@@ -1188,6 +1184,25 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
}
+ private fun continueUpdatingDataInBackground(ids: List){
+ val id = System.currentTimeMillis().toInt()
+ val workRequest = OneTimeWorkRequestBuilder()
+ .setInputData(
+ Data.Builder()
+ .putLongArray("ids", ids.toLongArray())
+ .putInt("id", id)
+ .build())
+ .addTag("updateData")
+ .build()
+ val context = App.instance
+ WorkManager.getInstance(context).enqueueUniqueWork(
+ id.toString(),
+ ExistingWorkPolicy.REPLACE,
+ workRequest
+ )
+
+ }
+
suspend fun updateProcessingType(newType: Type) {
val processing = repository.getProcessingDownloads()
processing.apply {
diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/HomeFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/HomeFragment.kt
index 77af7b35..3f835e9f 100644
--- a/app/src/main/java/com/deniscerri/ytdl/ui/HomeFragment.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/ui/HomeFragment.kt
@@ -15,6 +15,7 @@ import android.view.*
import android.view.View.*
import android.widget.*
import androidx.activity.addCallback
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.constraintlayout.widget.ConstraintLayout
@@ -41,8 +42,10 @@ import com.deniscerri.ytdl.database.viewmodel.HistoryViewModel
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.ui.adapter.HomeAdapter
import com.deniscerri.ytdl.ui.adapter.SearchSuggestionsAdapter
+import com.deniscerri.ytdl.ui.more.WebViewActivity
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
import com.deniscerri.ytdl.util.Extensions.isURL
+import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.NotificationUtil
import com.deniscerri.ytdl.util.ThemeUtil
import com.deniscerri.ytdl.util.UiUtil
@@ -64,6 +67,8 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import java.io.File
+import java.net.URL
import kotlin.collections.ArrayList
@@ -263,25 +268,37 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
if (res.errorMessage != null){
val isSingleQueryAndURL = queryList.size == 1 && Patterns.WEB_URL.matcher(queryList.first()).matches()
- kotlin.runCatching { UiUtil.handleNoResults(requireActivity(), res.errorMessage!!, continueAnyway = isSingleQueryAndURL, continued = {
- lifecycleScope.launch {
- if (sharedPreferences!!.getBoolean("download_card", true)) {
- withContext(Dispatchers.Main){
- showSingleDownloadSheet(
- resultItem = downloadViewModel.createEmptyResultItem(queryList.first()),
- type = DownloadViewModel.Type.valueOf(sharedPreferences!!.getString("preferred_download_type", "video")!!),
- disableUpdateData = true
+ kotlin.runCatching {
+ UiUtil.handleNoResults(requireActivity(), res.errorMessage!!,
+ url = if (isSingleQueryAndURL) queryList.first() else null,
+ continueAnyway = isSingleQueryAndURL,
+ continued = {
+ lifecycleScope.launch {
+ if (sharedPreferences!!.getBoolean("download_card", true)) {
+ withContext(Dispatchers.Main){
+ showSingleDownloadSheet(
+ resultItem = downloadViewModel.createEmptyResultItem(queryList.first()),
+ type = DownloadViewModel.Type.valueOf(sharedPreferences!!.getString("preferred_download_type", "video")!!),
+ disableUpdateData = true
+ )
+ }
+ } else {
+ val downloadItem = downloadViewModel.createDownloadItemFromResult(
+ result = downloadViewModel.createEmptyResultItem(queryList.first()),
+ givenType = DownloadViewModel.Type.valueOf(sharedPreferences!!.getString("preferred_download_type", "video")!!)
)
+ downloadViewModel.queueDownloads(listOf(downloadItem))
}
- } else {
- val downloadItem = downloadViewModel.createDownloadItemFromResult(
- result = downloadViewModel.createEmptyResultItem(queryList.first()),
- givenType = DownloadViewModel.Type.valueOf(sharedPreferences!!.getString("preferred_download_type", "video")!!)
- )
- downloadViewModel.queueDownloads(listOf(downloadItem))
}
- }
- }, closed = {}) }
+ },
+ cookieFetch = {
+ val myIntent = Intent(requireContext(), WebViewActivity::class.java)
+ myIntent.putExtra("url", "https://${URL(queryList.first()).host}")
+ cookiesFetchedResultLauncher.launch(myIntent)
+ },
+ closed = {}
+ )
+ }
resultViewModel.uiState.update {it.copy(errorMessage = null) }
}
@@ -324,6 +341,15 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
}
+ private var cookiesFetchedResultLauncher = registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) { result ->
+ if (result.resultCode == Activity.RESULT_OK) {
+ sharedPreferences?.edit()?.putBoolean("use_cookies", true)?.apply()
+ startSearch()
+ }
+ }
+
override fun onResume() {
super.onResume()
if(arguments?.getString("url") == null){
@@ -653,6 +679,10 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
resultViewModel.addSearchQueryToHistory(q)
}
}
+ startSearch()
+ }
+
+ private fun startSearch() {
lifecycleScope.launch(Dispatchers.IO){
resultViewModel.deleteAll()
if(sharedPreferences!!.getBoolean("quick_download", false) || sharedPreferences!!.getString("preferred_download_type", "video") == "command"){
diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/HistoryPaginatedAdapter.kt b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/HistoryPaginatedAdapter.kt
index 449899de..32021430 100644
--- a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/HistoryPaginatedAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/HistoryPaginatedAdapter.kt
@@ -161,7 +161,7 @@ class HistoryPaginatedAdapter(onItemClickListener: OnItemClickListener, activity
true
}
card.setOnClickListener {
- if (checkedItems.size > 0) {
+ if (checkedItems.size > 0 || inverted) {
checkCard(card, item.id, position)
} else {
onItemClickListener.onCardClick(item.id, finalFilePresent)
diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadBottomSheetDialog.kt
index 8d791328..ac637ae6 100644
--- a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadBottomSheetDialog.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadBottomSheetDialog.kt
@@ -1,8 +1,10 @@
package com.deniscerri.ytdl.ui.downloadcard
import android.annotation.SuppressLint
+import android.app.Activity
import android.app.Dialog
import android.content.DialogInterface
+import android.content.Intent
import android.content.SharedPreferences
import android.content.res.Configuration
import android.os.Build
@@ -16,6 +18,7 @@ import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.edit
import androidx.core.os.bundleOf
import androidx.core.view.isVisible
@@ -39,6 +42,7 @@ import com.deniscerri.ytdl.database.viewmodel.HistoryViewModel
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.receiver.ShareActivity
import com.deniscerri.ytdl.ui.BaseActivity
+import com.deniscerri.ytdl.ui.more.WebViewActivity
import com.deniscerri.ytdl.util.UiUtil
import com.facebook.shimmer.ShimmerFrameLayout
import com.google.android.material.bottomsheet.BottomSheetBehavior
@@ -58,6 +62,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
+import java.net.URL
class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
@@ -397,9 +402,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
dd.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
dd.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
lifecycleScope.launch(Dispatchers.IO){
- val item = getDownloadItem()
- item.status = DownloadRepository.Status.Saved.toString()
- downloadViewModel.updateDownload(item)
+ downloadViewModel.putToSaved(getDownloadItem())
dismiss()
}
}
@@ -468,16 +471,25 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
}
}
-
-
-
-
lifecycleScope.launch {
resultViewModel.uiState.collectLatest { res ->
if (res.errorMessage != null){
- kotlin.runCatching { UiUtil.handleNoResults(requireActivity(), res.errorMessage!!, true, continued = {}, closed = {
- dismiss()
- }) }
+ kotlin.runCatching {
+ UiUtil.handleNoResults(requireActivity(), res.errorMessage!!,
+ url = result.url,
+ continueAnyway = true,
+ continued = {},
+ cookieFetch = {
+ val myIntent = Intent(requireContext(), WebViewActivity::class.java)
+ myIntent.putExtra("url", "https://${URL(result.url).host}")
+ cookiesFetchedResultLauncher.launch(myIntent)
+ },
+ closed = {
+ dismiss()
+ }
+ )
+ }
+
resultViewModel.uiState.update {it.copy(errorMessage = null) }
}
}
@@ -657,6 +669,16 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
}
}
+ private var cookiesFetchedResultLauncher = registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) { result ->
+ if (result.resultCode == Activity.RESULT_OK) {
+ sharedPreferences.edit().putBoolean("use_cookies", true).apply()
+ updateItem.isVisible = true
+ initUpdateData()
+ }
+ }
+
private fun getDownloadItem(selectedTabPosition: Int = tabLayout.selectedTabPosition) : DownloadItem {
return fragmentAdapter.getDownloadItem(selectedTabPosition)
}
diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/FormatSelectionBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/FormatSelectionBottomSheetDialog.kt
index f51a4121..51379c8a 100644
--- a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/FormatSelectionBottomSheetDialog.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/FormatSelectionBottomSheetDialog.kt
@@ -236,7 +236,7 @@ class FormatSelectionBottomSheetDialog(
}
}.onFailure { err ->
withContext(Dispatchers.Main){
- UiUtil.handleNoResults(requireActivity(), err.message.toString(), false, continued = {}, closed = {})
+ UiUtil.handleNoResults(requireActivity(), err.message.toString(), null, false, continued = {}, closed = {}, cookieFetch = {})
}
}
diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/WebViewActivity.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/WebViewActivity.kt
index ce0c9bd6..4fda23ec 100644
--- a/app/src/main/java/com/deniscerri/ytdl/ui/more/WebViewActivity.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/WebViewActivity.kt
@@ -98,7 +98,8 @@ class WebViewActivity : BaseActivity() {
}
cookieManager.removeAllCookies(null)
withContext(Dispatchers.Main) {
- onBackPressedDispatcher.onBackPressed()
+ this@WebViewActivity.setResult(RESULT_OK)
+ this@WebViewActivity.finish()
}
}
}
diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt
index a046b2ef..40287cb0 100644
--- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt
@@ -59,7 +59,8 @@ class ProcessingSettingsFragment : BaseSettingsFragment() {
setOnPreferenceClickListener {
val pref = prefs.getString("format_importance_audio", itemValues.joinToString(","))!!
- val itms = pref.split(",").map {
+ val prefArr = pref.split(",")
+ val itms = itemValues.sortedBy { prefArr.indexOf(it) }.map {
Pair(it, items[itemValues.indexOf(it)])
}.toMutableList()
@@ -80,7 +81,8 @@ class ProcessingSettingsFragment : BaseSettingsFragment() {
setOnPreferenceClickListener {
val pref = prefs.getString("format_importance_video", itemValues.joinToString(","))!!
- val itms = pref.split(",").map {
+ val prefArr = pref.split(",")
+ val itms = itemValues.sortedBy { prefArr.indexOf(it) }.map {
Pair(it, items[itemValues.indexOf(it)])
}.toMutableList()
diff --git a/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt b/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt
index 7be6db1f..ba166403 100644
--- a/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt
@@ -558,4 +558,9 @@ object Extensions {
t4.second
)
}
+
+
+ fun DownloadItem.needsDataUpdating() : Boolean {
+ return this.title.isBlank() || this.author.isBlank() || this.thumb.isBlank()
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdl/util/FormatUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/FormatUtil.kt
index 1bc3948e..9a546610 100644
--- a/app/src/main/java/com/deniscerri/ytdl/util/FormatUtil.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/util/FormatUtil.kt
@@ -35,6 +35,7 @@ class FormatUtil(private var context: Context) {
val orderPreferences = sharedPreferences.getString("format_importance_audio", itemValues.joinToString(","))!!.split(",").toMutableSet()
if (preferSmallerFormats) {
orderPreferences.add("smallsize")
+ orderPreferences.remove("file_size")
}
return orderPreferences
@@ -46,6 +47,7 @@ class FormatUtil(private var context: Context) {
val orderPreferences = sharedPreferences.getString("format_importance_video", itemValues.joinToString(","))!!.split(",").toMutableSet()
if (preferSmallerFormats) {
orderPreferences.add("smallsize")
+ orderPreferences.remove("file_size")
}
return orderPreferences
@@ -63,7 +65,10 @@ class FormatUtil(private var context: Context) {
"smallsize" -> {
(a.filesize).compareTo(b.filesize)
}
-
+ "file_size" -> {
+ val result = b.filesize.compareTo(a.filesize)
+ result
+ }
"id" -> {
(audioFormatIDPreference.contains(b.format_id)).compareTo(
audioFormatIDPreference.contains(a.format_id)
@@ -119,6 +124,10 @@ class FormatUtil(private var context: Context) {
val result = a.filesize.compareTo(b.filesize)
result
}
+ "file_size" -> {
+ val result = b.filesize.compareTo(a.filesize)
+ result
+ }
"id" -> {
videoFormatIDPreference.contains(b.format_id).compareTo(videoFormatIDPreference.contains(a.format_id))
}
diff --git a/app/src/main/java/com/deniscerri/ytdl/util/NotificationUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/NotificationUtil.kt
index 5393b26f..515144c9 100644
--- a/app/src/main/java/com/deniscerri/ytdl/util/NotificationUtil.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/util/NotificationUtil.kt
@@ -621,6 +621,63 @@ class NotificationUtil(var context: Context) {
}
+ fun createDataUpdateNotification(): Notification {
+ val notificationBuilder = getBuilder(DOWNLOAD_MISC_CHANNEL_ID)
+ return notificationBuilder
+ .setContentTitle(resources.getString(R.string.updating_download_data))
+ .setOngoing(true)
+ .setCategory(Notification.CATEGORY_PROGRESS)
+ .setSmallIcon(R.drawable.ic_launcher_foreground)
+ .setLargeIcon(
+ BitmapFactory.decodeResource(
+ resources,
+ R.drawable.ic_launcher_foreground_large
+ )
+ )
+ .setContentText("")
+ .setPriority(NotificationCompat.PRIORITY_LOW)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setProgress(PROGRESS_MAX, PROGRESS_CURR, false)
+ .setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
+ .clearActions()
+ .build()
+ }
+
+ @SuppressLint("MissingPermission")
+ fun updateDataUpdateNotification(
+ workID: Int,
+ workTag: String,
+ progress: Int,
+ queue: Int,
+ ) {
+
+ val notificationBuilder = getBuilder(DOWNLOAD_MISC_CHANNEL_ID)
+ val contentText = """${queue - progress} ${resources.getString(R.string.items_left)}"""
+
+
+ val cancelIntent = Intent(context, CancelWorkReceiver::class.java)
+ cancelIntent.putExtra("workTag", workTag)
+ val cancelNotificationPendingIntent = PendingIntent.getBroadcast(
+ context,
+ workID,
+ cancelIntent,
+ PendingIntent.FLAG_IMMUTABLE
+ )
+
+
+ try {
+ notificationBuilder.setProgress(queue, progress, progress == 0)
+ .setContentTitle(resources.getString(R.string.updating_download_data))
+ .setStyle(NotificationCompat.BigTextStyle().bigText(contentText))
+ .clearActions()
+ .addAction(0, resources.getString(R.string.cancel), cancelNotificationPendingIntent)
+ notificationManager.notify(workID, notificationBuilder.build())
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+
+
@SuppressLint("MissingPermission")
fun showFormatsUpdatedNotification(downloadIds: List) {
val notificationBuilder = getBuilder(DOWNLOAD_FINISHED_CHANNEL_ID)
diff --git a/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt
index 0a804547..887a5de4 100644
--- a/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt
@@ -5,6 +5,7 @@ import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Activity
+import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
@@ -33,6 +34,7 @@ import android.widget.PopupMenu
import android.widget.RadioButton
import android.widget.TextView
import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.DimenRes
import androidx.annotation.OptIn
import androidx.appcompat.app.AlertDialog
@@ -62,6 +64,7 @@ import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.ui.downloadcard.VideoCutListener
+import com.deniscerri.ytdl.ui.more.WebViewActivity
import com.deniscerri.ytdl.util.Extensions.enableTextHighlight
import com.deniscerri.ytdl.util.Extensions.getMediaDuration
import com.deniscerri.ytdl.util.Extensions.toStringDuration
@@ -94,6 +97,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.io.File
+import java.net.URL
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
@@ -1633,9 +1637,7 @@ object UiUtil {
}
}
-
- fun handleNoResults(context: Activity, message: String, continueAnyway: Boolean = false, continued: () -> Unit, closed: () -> Unit) {
-
+ fun handleNoResults(context: Activity, message: String, url: String? = null, continueAnyway: Boolean = false, continued: () -> Unit, closed: () -> Unit, cookieFetch: () -> Unit) {
val errDialog = MaterialAlertDialogBuilder(context)
.setTitle(R.string.no_results)
.setMessage(message)
@@ -1646,12 +1648,19 @@ object UiUtil {
d?.dismiss()
}
- if (continueAnyway) {
+ val cookieRelated = message.contains("cookie", true) || message.contains("sign in", true)
+ if (cookieRelated && !url.isNullOrBlank()) {
+ errDialog.setNeutralButton(context.getString(R.string.get_cookies)) { d: DialogInterface?, _ : Int ->
+ cookieFetch()
+ }
+ }else if (continueAnyway) {
errDialog.setNeutralButton(R.string.continue_anyway) {d: DialogInterface?, _:Int ->
continued()
}
}
+
+
errDialog.setOnCancelListener {
closed()
}
diff --git a/app/src/main/java/com/deniscerri/ytdl/util/UpdateUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/UpdateUtil.kt
index 64dbad88..6ab2cff3 100644
--- a/app/src/main/java/com/deniscerri/ytdl/util/UpdateUtil.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/util/UpdateUtil.kt
@@ -228,7 +228,7 @@ class UpdateUtil(var context: Context) {
updatingYTDL = true
- val channel = if (c.isNullOrBlank()) sharedPreferences.getString("ytdlp_source", "nightly") else c
+ val channel = if (c.isNullOrBlank()) sharedPreferences.getString("ytdlp_source", "stable") else c
val request = YoutubeDLRequest(emptyList())
request.addOption("--update-to", "${channel}@latest")
diff --git a/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt
index 60079410..1c89811b 100644
--- a/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt
@@ -110,7 +110,7 @@ class YTDLPUtil(private val context: Context) {
}
}
if (searchEngine == "ytsearch" || query.isYoutubeURL()) {
- request.addOption("--extractor-args", "youtube:${getYoutubeExtractorArgs()}")
+ request.setYoutubeExtractorArgs()
}
request.addOption("--flat-playlist")
@@ -250,7 +250,7 @@ class YTDLPUtil(private val context: Context) {
fun getYoutubeWatchLater() : ArrayList {
val request = YoutubeDLRequest(listOf())
- request.addOption("--extractor-args", "youtube:${getYoutubeExtractorArgs()}")
+ request.setYoutubeExtractorArgs()
request.addOption( "-j")
request.addOption("--flat-playlist")
request.applyDefaultOptionsForFetchingData()
@@ -269,7 +269,7 @@ class YTDLPUtil(private val context: Context) {
fun getYoutubeRecommendations() : ArrayList {
val request = YoutubeDLRequest(listOf())
- request.addOption("--extractor-args", "youtube:${getYoutubeExtractorArgs()}")
+ request.setYoutubeExtractorArgs()
request.addOption( "-j")
request.addOption("--flat-playlist")
request.applyDefaultOptionsForFetchingData()
@@ -288,7 +288,7 @@ class YTDLPUtil(private val context: Context) {
fun getYoutubeLikedVideos() : ArrayList {
val request = YoutubeDLRequest(listOf())
- request.addOption("--extractor-args", "youtube:${getYoutubeExtractorArgs()}")
+ request.setYoutubeExtractorArgs()
request.addOption( "-j")
request.addOption("--flat-playlist")
request.applyDefaultOptionsForFetchingData()
@@ -307,7 +307,7 @@ class YTDLPUtil(private val context: Context) {
fun getYoutubeWatchHistory() : ArrayList {
val request = YoutubeDLRequest(listOf())
- request.addOption("--extractor-args", "youtube:${getYoutubeExtractorArgs()}")
+ request.setYoutubeExtractorArgs()
request.addOption( "-j")
request.addOption("--flat-playlist")
request.applyDefaultOptionsForFetchingData()
@@ -574,9 +574,12 @@ class YTDLPUtil(private val context: Context) {
}else{
addOption("-I", "${downloadItem.playlistIndex!!}:${downloadItem.playlistIndex}")
}
+ addOption("-i")
}
}
+ request.addOption("--newline")
+
val metadataCommands = mutableListOf()
if (downloadItem.playlistIndex != null && useItemURL) {
@@ -732,21 +735,22 @@ class YTDLPUtil(private val context: Context) {
}
if (downloadItem.url.isYoutubeURL()) {
- request.addOption("--extractor-args", "youtube:${getYoutubeExtractorArgs()}")
+ request.setYoutubeExtractorArgs()
}
- if (!sharedPreferences.getBoolean("disable_write_info_json", false)) {
- val cachePath = "${FileUtil.getCachePath(context)}infojsons"
- val infoJsonName = MessageDigest.getInstance("MD5").digest(downloadItem.url.toByteArray()).toHexString()
-
- val infoJsonFile = File(cachePath).walkTopDown().firstOrNull { it.name == "${infoJsonName}.info.json" }
- //ignore info file if its older than 5 hours. puny measure to prevent expired formats in some cases
- if (infoJsonFile == null || System.currentTimeMillis() - infoJsonFile.lastModified() > (1000 * 60 * 60 * 5)) {
- request.addCommands(listOf("--print-to-file", "video:%()#j", "${cachePath}/${infoJsonName}.info.json"))
- }else {
- request.addOption("--load-info-json", infoJsonFile.absolutePath)
- }
- }
+ //TODO REVIEW TO ADD THIS AGAIN LATER?
+// if (!sharedPreferences.getBoolean("disable_write_info_json", false)) {
+// val cachePath = "${FileUtil.getCachePath(context)}infojsons"
+// val infoJsonName = MessageDigest.getInstance("MD5").digest(downloadItem.url.toByteArray()).toHexString()
+//
+// val infoJsonFile = File(cachePath).walkTopDown().firstOrNull { it.name == "${infoJsonName}.info.json" }
+// //ignore info file if its older than 5 hours. puny measure to prevent expired formats in some cases
+// if (infoJsonFile == null || System.currentTimeMillis() - infoJsonFile.lastModified() > (1000 * 60 * 60 * 5)) {
+// request.addCommands(listOf("--print-to-file", "video:%()#j", "${cachePath}/${infoJsonName}.info.json"))
+// }else {
+// request.addOption("--load-info-json", infoJsonFile.absolutePath)
+// }
+// }
}
if (sharedPreferences.getString("prevent_duplicate_downloads", "")!! == "download_archive"){
@@ -856,7 +860,7 @@ class YTDLPUtil(private val context: Context) {
metadataCommands.addOption("--parse-metadata", "%(album_artist,first_artist|)s:%(album_artist)s")
- metadataCommands.addOption("--parse-metadata", "description:(?:Released on: )(?P\\d{4})")
+ metadataCommands.addOption("--parse-metadata", "description:(?:.+?Released\\ on\\s*(?P\\d{4}))?")
metadataCommands.addOption("--parse-metadata", "%(dscrptn_year,release_year,release_date>%Y,upload_date>%Y)s:(?P\\d+)")
if (isPlaylistItem) {
@@ -1167,7 +1171,7 @@ class YTDLPUtil(private val context: Context) {
return YoutubeDL.getInstance().execute(req).out.trim()
}
- private fun getYoutubeExtractorArgs() : String {
+ private fun YoutubeDLRequest.setYoutubeExtractorArgs() {
val playerClient = sharedPreferences.getString("yt_player_client", "")!!.split(",").filter { it.isNotBlank() }.toMutableList()
val extractorArgs = mutableListOf()
@@ -1196,7 +1200,10 @@ class YTDLPUtil(private val context: Context) {
extractorArgs.add(otherArgs)
}
- return extractorArgs.joinToString(";")
+ val extArgs = extractorArgs.joinToString(";")
+ if (extractorArgs.isNotEmpty()) {
+ this.addOption("--extractor-args", "youtube:${extArgs}")
+ }
}
private fun YoutubeDLRequest.addConfig(commandString: String) {
diff --git a/app/src/main/java/com/deniscerri/ytdl/work/ObserveSourceWorker.kt b/app/src/main/java/com/deniscerri/ytdl/work/ObserveSourceWorker.kt
index aaf6c918..eea1d3a1 100644
--- a/app/src/main/java/com/deniscerri/ytdl/work/ObserveSourceWorker.kt
+++ b/app/src/main/java/com/deniscerri/ytdl/work/ObserveSourceWorker.kt
@@ -15,6 +15,7 @@ import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.deniscerri.ytdl.App
+import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.repository.DownloadRepository
@@ -22,6 +23,7 @@ import com.deniscerri.ytdl.database.repository.HistoryRepository
import com.deniscerri.ytdl.database.repository.ObserveSourcesRepository
import com.deniscerri.ytdl.database.repository.ResultRepository
import com.deniscerri.ytdl.util.Extensions.calculateNextTimeForObserving
+import com.deniscerri.ytdl.util.Extensions.needsDataUpdating
import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.NotificationUtil
import com.deniscerri.ytdl.util.extractors.YTDLPUtil
@@ -113,8 +115,6 @@ class ObserveSourceWorker(
val string = Gson().toJson(item.downloadItemTemplate, DownloadItem::class.java)
val downloadItem = Gson().fromJson(string, DownloadItem::class.java)
downloadItem.url = it.url
- downloadItem.title = it.title
- downloadItem.author = it.author
downloadItem.thumb = it.thumb
downloadItem.status = DownloadRepository.Status.Queued.toString()
downloadItem.playlistTitle = it.playlistTitle
@@ -137,9 +137,6 @@ class ObserveSourceWorker(
//if scheduler is on
val useScheduler = sharedPreferences.getBoolean("use_scheduler", false)
- if (useScheduler && !alarmScheduler.isDuringTheScheduledTime()){
- alarmScheduler.schedule()
- }
// if (items.any { it.playlistTitle.isEmpty() } && items.size > 1){
// items.forEachIndexed { index, it -> it.playlistTitle = "Various[${index+1}]" }
@@ -184,33 +181,17 @@ class ObserveSourceWorker(
}
}
- if (!useScheduler || alarmScheduler.isDuringTheScheduledTime() || queuedItems.any { it.downloadStartTime > 0L } ){
+ if (useScheduler && !alarmScheduler.isDuringTheScheduledTime() && alarmScheduler.canSchedule()){
+ alarmScheduler.schedule()
+ }else {
downloadRepo.startDownloadWorker(queuedItems, context)
-
- if(!useScheduler){
- queuedItems.filter { it.downloadStartTime != 0L || (it.title.isEmpty() || it.author.isEmpty() || it.thumb.isEmpty()) }.forEach {
- runCatching {
- resultsRepo.updateDownloadItem(it)?.apply {
- downloadRepo.updateWithoutUpsert(this)
- }
- }
- }
- }else{
- queuedItems.filter { it.title.isEmpty() || it.author.isEmpty() || it.thumb.isEmpty() }.forEach {
- runCatching {
- resultsRepo.updateDownloadItem(it)?.apply {
- downloadRepo.updateWithoutUpsert(this)
- }
- }
- }
- }
}
item.alreadyProcessedLinks.removeAll(items.map { it.url })
item.alreadyProcessedLinks.addAll(items.map { it.url })
}
- item.runCount = item.runCount + 1
+ item.runCount += 1
if (item.runCount > item.endsAfterCount && item.endsAfterCount > 0){
item.status = ObserveSourcesRepository.SourceStatus.STOPPED
diff --git a/app/src/main/java/com/deniscerri/ytdl/work/UpdateMultipleDownloadsDataWorker.kt b/app/src/main/java/com/deniscerri/ytdl/work/UpdateMultipleDownloadsDataWorker.kt
new file mode 100644
index 00000000..26ad710c
--- /dev/null
+++ b/app/src/main/java/com/deniscerri/ytdl/work/UpdateMultipleDownloadsDataWorker.kt
@@ -0,0 +1,77 @@
+package com.deniscerri.ytdl.work
+
+import android.content.Context
+import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
+import android.os.Build
+import androidx.work.ForegroundInfo
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import com.deniscerri.ytdl.App
+import com.deniscerri.ytdl.database.DBManager
+import com.deniscerri.ytdl.database.repository.ResultRepository
+import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
+import com.deniscerri.ytdl.util.NotificationUtil
+import kotlinx.coroutines.runBlocking
+
+
+class UpdateMultipleDownloadsDataWorker(
+ private val context: Context,
+ workerParams: WorkerParameters
+) : Worker(context, workerParams) {
+ override fun doWork(): Result {
+ val dbManager = DBManager.getInstance(context)
+ val dao = dbManager.downloadDao
+ val resDao = dbManager.resultDao
+ val resultRepo = ResultRepository(resDao, context)
+ val notificationUtil = NotificationUtil(context)
+ val ids = inputData.getLongArray("ids")!!.toMutableList()
+ val workID = inputData.getInt("id", 0)
+ if (workID == 0) return Result.failure()
+
+ val notification = notificationUtil.createDataUpdateNotification()
+
+ if (Build.VERSION.SDK_INT > 33) {
+ setForegroundAsync(ForegroundInfo(workID, notification, FOREGROUND_SERVICE_TYPE_SPECIAL_USE))
+ }else{
+ setForegroundAsync(ForegroundInfo(workID, notification))
+ }
+
+ var count = 0
+
+ return try{
+ ids.forEach {
+ if (!isStopped){
+ val d = dao.getDownloadById(it)
+ if (d.title.isNotBlank() && d.author.isNotBlank() && d.thumb.isNotBlank()) {
+ count++
+ return@forEach
+ }
+
+ runCatching {
+ runBlocking {
+ resultRepo.updateDownloadItem(d)?.apply {
+ val dd = dao.getNullableDownloadById(it)
+ if (dd != null) {
+ d.status = dd.status
+ dao.updateWithoutUpsert(this)
+ }
+ }
+ }
+ }
+
+ count++
+ notificationUtil.updateDataUpdateNotification(workID, UpdateMultipleDownloadsDataWorker::class.java.name, count, ids.size)
+ }else{
+ throw Exception()
+ }
+ }
+
+ Result.success()
+ }catch (e: Exception){
+ notificationUtil.cancelDownloadNotification(workID)
+ ids.clear()
+ Result.failure()
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/adjust_audio.xml b/app/src/main/res/layout/adjust_audio.xml
index 64ce03d2..af4324f7 100644
--- a/app/src/main/res/layout/adjust_audio.xml
+++ b/app/src/main/res/layout/adjust_audio.xml
@@ -10,7 +10,6 @@
android:paddingTop="10dp"
android:layout_width="wrap_content"
android:paddingBottom="5dp"
- android:textSize="15sp"
android:layout_height="wrap_content"
android:text="@string/adjust_audio" />
diff --git a/app/src/main/res/layout/adjust_command.xml b/app/src/main/res/layout/adjust_command.xml
index 0a7020d5..13e22ce6 100644
--- a/app/src/main/res/layout/adjust_command.xml
+++ b/app/src/main/res/layout/adjust_command.xml
@@ -9,7 +9,6 @@
diff --git a/app/src/main/res/layout/adjust_video.xml b/app/src/main/res/layout/adjust_video.xml
index e2ef2ef6..f753550d 100644
--- a/app/src/main/res/layout/adjust_video.xml
+++ b/app/src/main/res/layout/adjust_video.xml
@@ -12,8 +12,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="5dp"
- android:text="@string/adjust_video"
- android:textSize="15sp" />
+ android:text="@string/adjust_video"/>
@@ -53,6 +53,7 @@
android:layout_height="wrap_content"
android:autoLink="all"
android:text="@string/ok"
+ android:outlineProvider="none"
app:icon="@drawable/ic_check"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/layout/observe_sources_item.xml b/app/src/main/res/layout/observe_sources_item.xml
index 88014b94..36ab8918 100644
--- a/app/src/main/res/layout/observe_sources_item.xml
+++ b/app/src/main/res/layout/observe_sources_item.xml
@@ -102,7 +102,9 @@
style="@style/Widget.Material3.Chip.Assist.Elevated"
android:layout_width="wrap_content"
android:layout_height="0dp"
- android:layout_margin="12dp"
+ android:layout_marginHorizontal="5dp"
+ android:layout_marginVertical="8dp"
+ android:outlineProvider="none"
app:chipIcon="@drawable/baseline_loop_24"
app:chipIconVisible="true"
app:chipMinTouchTargetSize="0dp"
diff --git a/app/src/main/res/layout/result_card.xml b/app/src/main/res/layout/result_card.xml
index f3007c85..3fe671b1 100644
--- a/app/src/main/res/layout/result_card.xml
+++ b/app/src/main/res/layout/result_card.xml
@@ -21,6 +21,7 @@
android:layout_height="match_parent"
app:cardCornerRadius="20dp"
app:cardElevation="5dp"
+ app:cardBackgroundColor="?attr/colorSurfaceContainer"
app:strokeColor="?attr/colorPrimary"
app:checkedIconTint="?attr/colorPrimary"
app:cardMaxElevation="12dp"
@@ -71,8 +72,8 @@
android:paddingEnd="10dp"
android:scrollbars="none"
android:shadowColor="@color/black"
- android:shadowDx="2"
- android:shadowDy="2"
+ android:shadowDx="1"
+ android:shadowDy="1"
android:shadowRadius="1"
android:textColor="#FFF"
android:textSize="17sp"
@@ -89,8 +90,8 @@
android:paddingEnd="10dp"
android:scrollbars="none"
android:shadowColor="@color/black"
- android:shadowDx="2"
- android:shadowDy="2"
+ android:shadowDx="1"
+ android:shadowDy="1"
android:shadowRadius="1"
android:textColor="#FFF"
android:textSize="12sp"
@@ -107,8 +108,8 @@
android:paddingEnd="10dp"
android:paddingBottom="20dp"
android:shadowColor="@color/black"
- android:shadowDx="2"
- android:shadowDy="2"
+ android:shadowDx="1"
+ android:shadowDy="1"
android:shadowRadius="1"
android:textColor="@color/white"
android:textSize="12sp"
@@ -124,6 +125,7 @@
app:elevation="0dp"
android:elevation="0dp"
app:borderWidth="0dp"
+ android:outlineProvider="none"
android:contentDescription="@string/audio"
android:layout_height="55dp"
android:layout_marginVertical="10dp"
@@ -142,6 +144,7 @@
android:elevation="0dp"
android:contentDescription="@string/video"
app:borderWidth="0dp"
+ android:outlineProvider="none"
app:icon="@drawable/ic_video"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 9a4e9647..82912e42 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -1462,6 +1462,7 @@
- @string/language
- @string/codec
- @string/container
+ - @string/file_size
@@ -1469,6 +1470,7 @@
- language
- codec
- container
+ - file_size
@@ -1477,6 +1479,7 @@
- @string/codec
- @string/no_audio
- @string/container
+ - @string/file_size
@@ -1485,6 +1488,7 @@
- codec
- no_audio
- container
+ - file_size
diff --git a/app/src/main/res/xml/advanced_preferences.xml b/app/src/main/res/xml/advanced_preferences.xml
index 7928ffc2..b6ea249b 100644
--- a/app/src/main/res/xml/advanced_preferences.xml
+++ b/app/src/main/res/xml/advanced_preferences.xml
@@ -33,7 +33,7 @@
android:title="@string/data_fetching_extra_command" />
-
+