diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt index 633e75b7..5a30853a 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt @@ -77,7 +77,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: if (title.length > 100) { title = title.substring(0, 40) + "..." } - itemTitle.text = title.ifEmpty { "`${activity.getString(R.string.defaultValue)}`" } + itemTitle.text = title.ifEmpty { "<${activity.getString(R.string.defaultValue)}>" } // Author ---------------------------------- val author = card.findViewById(R.id.author) @@ -86,7 +86,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: if (item.author.isNotEmpty()) info += " • " info += item.duration } - author.text = info.ifEmpty { "`${activity.getString(R.string.defaultValue)}`" } + author.text = info.ifEmpty { "<${activity.getString(R.string.defaultValue)}>" } val type = card.findViewById(R.id.download_type) when(item.type){ 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 3b40d2c4..f3d1f57d 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/GenericDownloadAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/GenericDownloadAdapter.kt @@ -73,7 +73,7 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: if (title.length > 100) { title = title.substring(0, 40) + "..." } - itemTitle.text = title.ifEmpty { "`${activity.getString(R.string.defaultValue)}`" } + itemTitle.text = title.ifEmpty { "<${activity.getString(R.string.defaultValue)}>" } val formatNote = card.findViewById(R.id.format_note) if (item.format.format_note == "?" || item.format.format_note == "") formatNote!!.visibility = diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItem.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItem.kt index 1257f1b3..ccb5f99c 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItem.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItem.kt @@ -20,7 +20,7 @@ data class DownloadItem( var downloadSections: String, val allFormats: ArrayList, var downloadPath: String, - val website: String, + var website: String, val downloadSize: String, val playlistTitle: String, val audioPreferences : AudioPreferences, 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 9fcd0677..e5b82be5 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt @@ -193,6 +193,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi if (arguments?.getString("url") != null){ val url = requireArguments().getString("url") + arguments?.remove("url") if (inputQueries == null) inputQueries = mutableListOf() searchBar?.text = url inputQueries!!.add(url!!) @@ -202,6 +203,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi resultViewModel.deleteAll() lifecycleScope.launch(Dispatchers.IO){ resultViewModel.parseQueries(inputQueries!!) + inputQueries = null } } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt index b2a2b1a4..0068b7db 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt @@ -71,7 +71,7 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val behavior = BottomSheetBehavior.from(view.parent as View) val displayMetrics = DisplayMetrics() requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics) - behavior.peekHeight = displayMetrics.heightPixels - 700 + behavior.peekHeight = displayMetrics.heightPixels } @@ -159,9 +159,9 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val scheduleBtn.setOnClickListener{ - scheduleBtn.isEnabled = false - download.isEnabled = false uiUtil.showDatePicker(fragmentManager) { + scheduleBtn.isEnabled = false + download.isEnabled = false val item: DownloadItem = getDownloadItem(); item.downloadStartTime = it.timeInMillis runBlocking { @@ -197,13 +197,13 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val (updateItem.parent as LinearLayout).visibility = View.VISIBLE updateItem.setOnClickListener { if (activity is ShareActivity) { + dismiss() val intent = Intent(context, ShareActivity::class.java) intent.action = Intent.ACTION_SEND intent.type = "text/plain" intent.putExtra(Intent.EXTRA_TEXT, resultItem.url) intent.putExtra("quick_download", false) startActivity(intent) - dismiss() }else{ dismiss() val bundle = Bundle() 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 cfc511fd..e8589c93 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 @@ -106,9 +106,9 @@ class DownloadMultipleBottomSheetDialog(private var results: List, scheduleBtn.setOnClickListener{ - scheduleBtn.isEnabled = false - download.isEnabled = false uiUtil.showDatePicker(parentFragmentManager) { + scheduleBtn.isEnabled = false + download.isEnabled = false items.forEach { item -> item.downloadStartTime = it.timeInMillis } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt index 7480e606..d56495b2 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt @@ -88,13 +88,13 @@ class SelectPlaylistItemsBottomSheetDialog(private val items: List, val end = toTextInput.editText!!.text.toString() if (checkRanges(start, end)) { - if (start < end){ + if (start.toInt() < end.toInt()){ var startNr = Integer.parseInt(start) startNr-- var endNr = Integer.parseInt(end) endNr-- if (startNr <= 0) startNr = 0 - if (endNr > items.size) endNr = items.size + if (endNr > items.size) endNr = items.size - 1 listAdapter.checkRange(startNr, endNr) selectedText.text = "${listAdapter.getCheckedItems().size} ${resources.getString(R.string.selected)}" } @@ -108,13 +108,13 @@ class SelectPlaylistItemsBottomSheetDialog(private val items: List, val end = _text.toString() if (checkRanges(start, end)) { - if (start < end){ + if (start.toInt() < end.toInt()){ var startNr = Integer.parseInt(start) startNr-- var endNr = Integer.parseInt(end) endNr-- if (startNr <= 0) startNr = 0 - if (endNr > items.size) endNr = items.size + if (endNr > items.size) endNr = items.size -1 listAdapter.checkRange(startNr, endNr) selectedText.text = "${listAdapter.getCheckedItems().size} ${resources.getString(R.string.selected)}" } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ActiveDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ActiveDownloadsFragment.kt index a99982f2..81115b3f 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ActiveDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ActiveDownloadsFragment.kt @@ -120,7 +120,7 @@ class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickL val logFile = fileUtil.getLogFile(requireContext(), item) if (logFile.exists()) { val intent = Intent(requireContext(), DownloadLogActivity::class.java) - intent.putExtra("path", logFile.absolutePath) + intent.putExtra("logpath", logFile.absolutePath) startActivity(intent) } } 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 d10f55e2..aa8783e6 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 @@ -105,7 +105,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL val item = items.find { it.id == itemID } ?: return val file = fileUtil.getLogFile(requireContext(), item) val intent = Intent(requireContext(), DownloadLogActivity::class.java) - intent.putExtra("path", file.absolutePath) + intent.putExtra("logpath", file.absolutePath) startActivity(intent) } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogActivity.kt index 72a3bdfc..f2033766 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogActivity.kt @@ -45,7 +45,7 @@ class DownloadLogActivity : BaseActivity() { clipboard.setText(content.text) } - val path = intent.getStringExtra("path") + val path = intent.getStringExtra("logpath") if (path == null) { onBackPressedDispatcher.onBackPressed() } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogListActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogListActivity.kt index 79a433cb..86032af0 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogListActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogListActivity.kt @@ -125,7 +125,7 @@ class DownloadLogListActivity : BaseActivity(), DownloadLogsAdapter.OnItemClickL override fun onItemClick(file: File) { val intent = Intent(this, DownloadLogActivity::class.java) - intent.putExtra("path", file.absolutePath) + intent.putExtra("logpath", file.absolutePath) startActivity(intent) } 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 f3c8f554..97792aaf 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt @@ -7,6 +7,7 @@ import android.os.Looper import android.util.Log import android.widget.Toast import com.deniscerri.ytdlnis.R +import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.Format import com.deniscerri.ytdlnis.database.models.ResultItem import com.google.gson.Gson @@ -674,6 +675,51 @@ class InfoUtil(private val context: Context) { return items } + fun getMissingInfo(url: String): ResultItem? { + try { + val request = YoutubeDLRequest(url) + request.addOption("--flat-playlist") + request.addOption("-J") + request.addOption("--skip-download") + request.addOption("-R", "1") + request.addOption("--socket-timeout", "5") + + val cookiesFile = File(context.cacheDir, "cookies.txt") + if (cookiesFile.exists()){ + request.addOption("--cookies", cookiesFile.absolutePath) + } + + val youtubeDLResponse = YoutubeDL.getInstance().execute(request) + val jsonObject = JSONObject(youtubeDLResponse.out) + val thumbs = jsonObject.getJSONArray("thumbnails") + val thumb = thumbs.getJSONObject(thumbs.length() - 1).getString("url") + val isPlaylist = jsonObject.has("playlist_count") + return ResultItem( + 0, + url, + if (isPlaylist){ + "[${jsonObject.getInt("playlist_count")} Items] ${jsonObject.getString("title")}" + }else{ + jsonObject.getString("title") + }, + jsonObject.getString("uploader"), + if (jsonObject.has("duration")) formatIntegerDuration(jsonObject.getInt("duration"), Locale.US) else "", + thumb, + jsonObject.getString("extractor"), + if (isPlaylist) jsonObject.getString("title") else "", + arrayListOf(), + System.currentTimeMillis() + ) + } catch (e: Exception) { + Looper.prepare().run { + Toast.makeText(context, e.message, Toast.LENGTH_LONG).show() + } + e.printStackTrace() + } + return null + } + + fun getSearchSuggestions(query: String): ArrayList { val url = "https://suggestqueries.google.com/complete/search?client=youtube&ds=yt&client=firefox&q=$query" // invidousURL + "search/suggestions?q=" + query diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt index 59b25ca4..85ffcac7 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt @@ -1,9 +1,6 @@ package com.deniscerri.ytdlnis.util -import android.app.Notification -import android.app.NotificationChannel -import android.app.NotificationManager -import android.app.PendingIntent +import android.app.* import android.content.Context import android.content.Intent import android.content.pm.PackageManager @@ -140,16 +137,22 @@ class NotificationUtil(var context: Context) { intent.action = Intent.ACTION_VIEW intent.setDataAndType(uri, "*/*") intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - val openNotificationPendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) + val openNotificationPendingIntent: PendingIntent = TaskStackBuilder.create(context).run { + addNextIntentWithParentStack(intent) + getPendingIntent(0, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + } //share intent val shareIntent = Intent(context, SharedDownloadNotificationReceiver::class.java) shareIntent.putExtra("share", "") shareIntent.putExtra("path", filepath) shareIntent.putExtra("notificationID", DOWNLOAD_FINISHED_NOTIFICATION_ID) - shareIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK - val shareNotificationPendingIntent = PendingIntent.getActivity(context, 0, shareIntent, PendingIntent.FLAG_IMMUTABLE) - + val shareNotificationPendingIntent: PendingIntent = TaskStackBuilder.create(context).run { + addNextIntentWithParentStack(shareIntent) + getPendingIntent(0, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + } notificationBuilder.addAction(0, context.getString(R.string.Open_File), openNotificationPendingIntent) notificationBuilder.addAction(0, context.getString(R.string.share), shareNotificationPendingIntent) @@ -160,31 +163,34 @@ class NotificationUtil(var context: Context) { fun createDownloadErrored(title: String?, error: String?, - logFilePath: String?, + logFile: File?, channel: String ) { val notificationBuilder = getBuilder(channel) val intent = Intent(context, DownloadLogActivity::class.java) - intent.putExtra("path", logFilePath) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK - val errorPendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) + intent.putExtra("logpath", logFile?.absolutePath) + val errorPendingIntent: PendingIntent = TaskStackBuilder.create(context).run { + addNextIntentWithParentStack(intent) + getPendingIntent(0, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + } notificationBuilder .setContentTitle("${context.getString(R.string.failed_download)}: $title") .setContentText(error) - .setContentIntent(errorPendingIntent) - .setSmallIcon(R.drawable.ic_app_icon) + .setSmallIcon(R.drawable.ic_launcher_foreground_large) .setLargeIcon( BitmapFactory.decodeResource( context.resources, - R.drawable.ic_app_icon + R.drawable.ic_launcher_foreground_large ) ) .setPriority(NotificationCompat.PRIORITY_MAX) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .clearActions() - if (logFilePath != null){ + if (logFile != null){ + notificationBuilder.setContentIntent(errorPendingIntent) notificationBuilder.addAction(0, context.getString(R.string.logs), errorPendingIntent) } notificationManager.notify(DOWNLOAD_FINISHED_NOTIFICATION_ID, notificationBuilder.build()) 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 b10ce85e..8b907b1d 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt @@ -268,6 +268,22 @@ class DownloadWorker( } } + //update item if its incomplete + if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){ + runCatching { + setProgressAsync(workDataOf("progress" to 0, "output" to "Updating Download Item Data", "id" to downloadItem.id, "log" to false)) + val info = infoUtil.getMissingInfo(downloadItem.url) + if (downloadItem.title.isEmpty()) downloadItem.title = info?.title.toString() + if (downloadItem.author.isEmpty()) downloadItem.author = info?.author.toString() + if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info?.thumb.toString() + downloadItem.duration = info?.duration.toString() + downloadItem.website = info?.website.toString() + runBlocking { + dao.update(downloadItem) + } + } + } + val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false) val logFolder = File(context.filesDir.absolutePath + "/logs") val logFile = fileUtil.getLogFile(context, downloadItem) @@ -282,21 +298,6 @@ class DownloadWorker( "Format: ${downloadItem.format}\n\n") } - //update item if its incomplete - if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){ - runCatching { - setProgressAsync(workDataOf("progress" to 0, "output" to "Updating Download Item Data", "id" to downloadItem.id, "log" to logDownloads)) - val info = YoutubeDL.getInfo(downloadItem.url) - if (downloadItem.title.isEmpty()) downloadItem.title = info.title.toString() - if (downloadItem.author.isEmpty()) downloadItem.author = info.uploader.toString() - if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info.thumbnail.toString() - downloadItem.duration = infoUtil.formatIntegerDuration(info.duration, Locale.US) - runBlocking { - dao.update(downloadItem) - } - } - } - runCatching { YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line -> setProgressAsync(workDataOf("progress" to progress.toInt(), "output" to line.chunked(5000).first().toString(), "id" to downloadItem.id, "log" to logDownloads)) @@ -376,7 +377,7 @@ class DownloadWorker( notificationUtil.createDownloadErrored( downloadItem.title, it.message, - if (logDownloads) logFile.absolutePath else null, + if (logDownloads) logFile else null, NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID ) diff --git a/app/src/main/res/layout/download_card.xml b/app/src/main/res/layout/download_card.xml index 2b47e3da..4656c8a3 100644 --- a/app/src/main/res/layout/download_card.xml +++ b/app/src/main/res/layout/download_card.xml @@ -15,7 +15,7 @@ android:checkable="true" android:clickable="true" android:focusable="true" - android:background="?android:attr/selectableItemBackground" + android:backgroundTint="@android:color/transparent" app:cardPreventCornerOverlap="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -178,12 +178,13 @@ diff --git a/build.gradle b/build.gradle index 126bc31b..5602a5b0 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { def versionMajor = 1 def versionMinor = 6 - def versionPatch = 0 + def versionPatch = 1 def versionBuild = 0 // bump for dogfood builds, public betas, etc. ext { diff --git a/fastlane/metadata/android/en-US/changelogs/10610.txt b/fastlane/metadata/android/en-US/changelogs/10610.txt new file mode 100644 index 00000000..444087aa --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/10610.txt @@ -0,0 +1,11 @@ +## Introducing Quick Download Mode +You can launch a download (or card) immediately without fetching data at first. + +Added Theme Picker, Accents and High Contrast Mode +Added swipe actions on history,downloads,cookies,templates cards +Added finished download notification with actions +Fixed Tiktok videos not creating result cards +Added active downloads badge in the navigation bar +Added remove audio feature for videos +Added check for present downloads +Added preferred Format ID \ No newline at end of file