From f88bfab70ed3d9ac677a946d1e27c01a1d787ad2 Mon Sep 17 00:00:00 2001 From: deniscerri <64997243+deniscerri@users.noreply.github.com> Date: Mon, 3 Apr 2023 22:12:30 +0200 Subject: [PATCH] fixed download logs text not being highlightable, fixed app not deleting some cached files, filed filenames being too short, fixed sometimes error output not being shown in terminal output, added keyboard focus when adding template in the terminal, made the loading of video player faster when you are cutting it --- .../ytdlnis/adapter/HistoryAdapter.kt | 2 +- .../database/viewmodel/DownloadViewModel.kt | 5 ++- .../downloadcard/CutVideoBottomSheetDialog.kt | 27 +++++++------ .../ytdlnis/ui/more/TerminalActivity.kt | 16 ++++---- .../more/downloadLogs/DownloadLogActivity.kt | 1 + .../ui/more/settings/SettingsFragment.kt | 19 ++++------ .../com/deniscerri/ytdlnis/util/FileUtil.kt | 4 +- .../com/deniscerri/ytdlnis/util/InfoUtil.kt | 20 +++------- .../deniscerri/ytdlnis/work/DownloadWorker.kt | 33 ++++++++-------- .../ytdlnis/work/TerminalDownloadWorker.kt | 38 +++++++------------ .../main/res/layout/active_download_card.xml | 8 ++-- .../main/res/layout/activity_download_log.xml | 25 +++++++----- 12 files changed, 92 insertions(+), 106 deletions(-) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/HistoryAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/HistoryAdapter.kt index 68d84f15..172c8203 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/HistoryAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/HistoryAdapter.kt @@ -94,7 +94,7 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit // System.currentTimeMillis(), // DateUtils.MINUTE_IN_MILLIS // ) - datetime.text = SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(item.time * 1000L) + datetime.text = SimpleDateFormat(android.text.format.DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(item.time * 1000L) // BUTTON ---------------------------------- val btn = card.findViewById(R.id.downloads_download_button_type) 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 588e1bbd..55b1b83c 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 @@ -24,6 +24,7 @@ import com.deniscerri.ytdlnis.work.DownloadWorker import com.google.gson.Gson import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.sql.Date import java.text.SimpleDateFormat import java.util.* @@ -310,7 +311,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application ).enqueue() } items.forEach { - it.id = repository.checkIfReDownloadingErroredOrCancelled(it) + it.id = withContext(Dispatchers.IO){ + repository.checkIfReDownloadingErroredOrCancelled(it) + } if (it.id != 0L){ repository.delete(it) } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt index 4a105e57..a40e00df 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt @@ -107,21 +107,20 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list } if (url.isBlank()) throw Exception("No Streaming URL found!") - Log.e("aa", url.split("\n")[0]) - Log.e("aa", url.split("\n")[1]) - val urls = url.split("\n") - if (urls.size == 2){ - val audioSource: MediaSource = - DefaultMediaSourceFactory(requireContext()) - .createMediaSource(fromUri(Uri.parse(urls[0]))) - val videoSource: MediaSource = - DefaultMediaSourceFactory(requireContext()) - .createMediaSource(fromUri(Uri.parse(urls[1]))) - (player as ExoPlayer).setMediaSource(MergingMediaSource(videoSource, audioSource)) - }else{ - player.addMediaItem(fromUri(Uri.parse(urls[0]))) - } +// val urls = url.split("\n") +// if (urls.size == 2){ +// val audioSource: MediaSource = +// DefaultMediaSourceFactory(requireContext()) +// .createMediaSource(fromUri(Uri.parse(urls[0]))) +// val videoSource: MediaSource = +// DefaultMediaSourceFactory(requireContext()) +// .createMediaSource(fromUri(Uri.parse(urls[1]))) +// (player as ExoPlayer).setMediaSource(MergingMediaSource(videoSource, audioSource)) +// }else{ +// player.addMediaItem(fromUri(Uri.parse(urls[0]))) +// } + player.addMediaItem(fromUri(Uri.parse(url))) progress.visibility = View.GONE 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 c13cc0cd..8a8e4fa2 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 @@ -9,6 +9,7 @@ import android.util.Log import android.view.View import android.view.ViewGroup import android.view.Window +import android.view.inputmethod.InputMethodManager import android.widget.EditText import android.widget.LinearLayout import android.widget.ScrollView @@ -17,11 +18,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope -import androidx.work.Data -import androidx.work.ExistingWorkPolicy -import androidx.work.OneTimeWorkRequestBuilder -import androidx.work.WorkInfo -import androidx.work.WorkManager +import androidx.work.* import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel import com.deniscerri.ytdlnis.util.NotificationUtil @@ -109,9 +106,7 @@ class TerminalActivity : AppCompatActivity() { input!!.requestFocus() hideCancelFab() } - val line = work.progress.getString("output") ?: return@observe - val id = work.progress.getInt("id", 0) - if(id == 0) return@observe + val line = work.progress.getString("output") ?: (work.outputData.getString("output") ?: return@observe) runOnUiThread { try { output!!.text = "${output!!.text}\n$line" @@ -168,6 +163,11 @@ class TerminalActivity : AppCompatActivity() { item.setOnClickListener { input!!.text.insert(input!!.selectionStart, template.content + " ") bottomSheet.cancel() + val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager + input!!.postDelayed({ + input!!.requestFocus() + imm.showSoftInput(input!!, 0) + }, 200) } linearLayout.addView(item) } 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 8e1a74d3..d0c1707f 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 @@ -34,6 +34,7 @@ class DownloadLogActivity : AppCompatActivity() { } content = findViewById(R.id.content) + content.setTextIsSelectable(true) contentScrollView = findViewById(R.id.content_scrollview) copyLog = findViewById(R.id.copy_log) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt index b761e68a..b0b19753 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt @@ -28,6 +28,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.yausername.youtubedl_android.YoutubeDL import kotlinx.coroutines.launch import kotlinx.serialization.json.Json +import java.io.File import java.util.* @@ -135,15 +136,11 @@ class SettingsFragment : PreferenceFragmentCompat() { version!!.summary = BuildConfig.VERSION_NAME val values = resources.getStringArray(R.array.language_values) - if (Build.VERSION.SDK_INT >= 33 || Build.VERSION.SDK_INT < 24){ - language!!.isVisible = false - }else{ - val entries = mutableListOf() - values.forEach { - entries.add(Locale(it).getDisplayName(Locale(it))) - } - language!!.entries = entries.toTypedArray() + val entries = mutableListOf() + values.forEach { + entries.add(Locale(it).getDisplayName(Locale(it))) } + language!!.entries = entries.toTypedArray() val lang = if (values.contains(Locale.getDefault().language)) Locale.getDefault().language else "en" editor.putString("app_language", lang) @@ -258,14 +255,14 @@ class SettingsFragment : PreferenceFragmentCompat() { true } - var cacheSize = requireContext().cacheDir.walkBottomUp().fold(0L) { acc, file -> acc + file.length() } + var cacheSize = File(requireContext().cacheDir.absolutePath + "/downloads").walkBottomUp().fold(0L) { acc, file -> acc + file.length() } clearCache!!.summary = "(${fileUtil!!.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}" clearCache!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { if (activeDownloadCount == 0){ - requireContext().cacheDir.deleteRecursively() + File(requireContext().cacheDir.absolutePath + "/downloads").deleteRecursively() Toast.makeText(requireContext(), getString(R.string.cache_cleared), Toast.LENGTH_SHORT).show() - cacheSize = requireContext().cacheDir.walkBottomUp().fold(0L) { acc, file -> acc + file.length() } + cacheSize = File(requireContext().cacheDir.absolutePath + "/downloads").walkBottomUp().fold(0L) { acc, file -> acc + file.length() } clearCache!!.summary = "(${fileUtil!!.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}" }else{ Toast.makeText(requireContext(), getString(R.string.downloads_running_try_later), Toast.LENGTH_SHORT).show() 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 41344340..f5b808ad 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/FileUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/FileUtil.kt @@ -132,13 +132,13 @@ class FileUtil() { } } - originDir.delete() + originDir.deleteRecursively() return scanMedia(fileList, context) } fun getLogFile(context: Context, item: DownloadItem) : File { val titleRegex = Regex("[^A-Za-z\\d ]") - return File(context.filesDir.absolutePath + """/logs/${item.id} - ${titleRegex.replace(item.title, "")}##${item.type}##${item.format.format_id}.log""") + return File(context.filesDir.absolutePath + """/logs/${item.id} - ${titleRegex.replace(item.title, "").take(150)}##${item.type}##${item.format.format_id}.log""") } fun getLogFileForTerminal(context: Context, command: String) : File { val titleRegex = Regex("[^A-Za-z\\d ]") 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 19bf05d3..6725a709 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt @@ -630,23 +630,13 @@ class InfoUtil(context: Context) { } fun getStreamingUrl(url: String) : String { - try { + return try { val request = YoutubeDLRequest(url) - request.addOption("-j") - request.addOption("--skip-download") - request.addOption("-R", "1") - request.addOption("--socket-timeout", "5") - val youtubeDLResponse = YoutubeDL.getInstance().execute(request) - val results: Array = try { - val lineSeparator = System.getProperty("line.separator") - youtubeDLResponse.out.split(lineSeparator!!).toTypedArray() - } catch (e: Exception) { - arrayOf(youtubeDLResponse.out) - } - val jsonObject = JSONObject(results[0]!!) - return jsonObject.getString("urls") + request.addOption("-f", "best") + val youtubeDlInfo = YoutubeDL.getInstance().getInfo(request) + youtubeDlInfo.url ?: "" } catch (e: Exception) { - return "" + "" } } 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 b8e91e8f..97f2220b 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt @@ -8,10 +8,7 @@ import android.os.Handler import android.os.Looper import android.util.Log import android.widget.Toast -import androidx.work.ForegroundInfo -import androidx.work.Worker -import androidx.work.WorkerParameters -import androidx.work.workDataOf +import androidx.work.* import com.deniscerri.ytdlnis.MainActivity import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.database.DBManager @@ -69,9 +66,9 @@ class DownloadWorker( val type = downloadItem.type val downloadLocation = downloadItem.downloadPath - val tempFileDir = File(context.cacheDir.absolutePath + "/" + downloadItem.id) + val tempFileDir = File(context.cacheDir.absolutePath + "/downloads/" + downloadItem.id) tempFileDir.delete() - tempFileDir.mkdir() + tempFileDir.mkdirs() val sharedPreferences = context.getSharedPreferences("root_preferences", Service.MODE_PRIVATE @@ -111,10 +108,10 @@ class DownloadWorker( } if(downloadItem.title.isNotBlank()){ - request.addCommands(listOf("--replace-in-metadata","title",".*.",downloadItem.title)) + request.addCommands(listOf("--replace-in-metadata","title",".*.",downloadItem.title.take(200))) } if (downloadItem.author.isNotBlank()){ - request.addCommands(listOf("--replace-in-metadata","uploader",".*.",downloadItem.author)) + request.addCommands(listOf("--replace-in-metadata","uploader",".*.",downloadItem.author.take(25))) } if (downloadItem.customFileNameTemplate.isBlank()) downloadItem.customFileNameTemplate = "%(uploader)s - %(title)s" @@ -127,8 +124,6 @@ class DownloadWorker( request.addOption("--restrict-filenames") } - request.addOption("--trim-filenames", 100) - when(type){ DownloadViewModel.Type.audio -> { request.addOption("-x") @@ -150,7 +145,7 @@ class DownloadWorker( request.addOption("--embed-thumbnail") request.addOption("--convert-thumbnails", "png") try { - val config = File(context.cacheDir, "config" + downloadItem.title + "##" + downloadItem.format.format_id + ".txt") + val config = File(context.cacheDir.absolutePath + "/downloads/config" + downloadItem.title + "##" + downloadItem.format.format_id + ".txt") val configData = "--ppa \"ffmpeg: -c:v png -vf crop=\\\"'if(gt(ih,iw),iw,ih)':'if(gt(iw,ih),ih,iw)'\\\"\"" config.writeText(configData) @@ -177,6 +172,7 @@ class DownloadWorker( DownloadViewModel.Type.video -> { if (downloadItem.videoPreferences.addChapters) { request.addOption("--sponsorblock-mark", "all") + request.addOption("--embed-chapters") } if (downloadItem.videoPreferences.embedSubs) { request.addOption("--embed-subs", "") @@ -216,7 +212,7 @@ class DownloadWorker( DownloadViewModel.Type.command -> { request.addOption( "--config-locations", - File(context.cacheDir, "config${System.currentTimeMillis()}.txt").apply { + File(context.cacheDir.absolutePath + "/downloads/config${System.currentTimeMillis()}.txt").apply { writeText(downloadItem.format.format_note) }.absolutePath ) @@ -255,12 +251,13 @@ class DownloadWorker( } }.onSuccess { //move file from internal to set download directory + setProgressAsync(workDataOf("progress" to 100, "output" to "Moving file to $downloadLocation", "id" to downloadItem.id, "log" to logDownloads)) var finalPath : String? try { finalPath = moveFile(tempFileDir.absoluteFile, downloadLocation){ progress -> - setProgressAsync(workDataOf("progress" to progress)) + setProgressAsync(workDataOf("progress" to progress, "output" to "Moving file to $downloadLocation", "id" to downloadItem.id, "log" to logDownloads)) } - setProgressAsync(workDataOf("progress" to 1000, "output" to "Moved file to $finalPath", "id" to downloadItem.id, "log" to logDownloads)) + setProgressAsync(workDataOf("progress" to 100, "output" to "Moved file to $finalPath", "id" to downloadItem.id, "log" to logDownloads)) }catch (e: Exception){ finalPath = context.getString(R.string.unfound_file) e.printStackTrace() @@ -288,7 +285,9 @@ class DownloadWorker( runBlocking { dao.update(downloadItem) } - return Result.failure() + return Result.failure( + Data.Builder().putString("output", "Download has been cancelled!").build() + ) }else{ if (logDownloads && logFile.exists()){ logFile.appendText("${it.message}\n") @@ -310,7 +309,9 @@ class DownloadWorker( runBlocking { dao.update(downloadItem) } - return Result.failure() + return Result.failure( + Data.Builder().putString("output", it.toString()).build() + ) } } 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 db884c32..6f39e60f 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/work/TerminalDownloadWorker.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/work/TerminalDownloadWorker.kt @@ -8,10 +8,7 @@ import android.os.Handler import android.os.Looper import android.util.Log import android.widget.Toast -import androidx.work.ForegroundInfo -import androidx.work.Worker -import androidx.work.WorkerParameters -import androidx.work.workDataOf +import androidx.work.* import com.deniscerri.ytdlnis.MainActivity import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.util.FileUtil @@ -48,13 +45,13 @@ class TerminalDownloadWorker( ) val downloadLocation = sharedPreferences.getString("command_path", context.getString(R.string.command_path)) - val tempFileDir = File(context.cacheDir.absolutePath + "/" + itemId) + val tempFileDir = File(context.cacheDir.absolutePath + "/downloads/" + itemId) tempFileDir.delete() - tempFileDir.mkdir() + tempFileDir.mkdirs() request.addOption( "--config-locations", - File(context.cacheDir, "config${System.currentTimeMillis()}.txt").apply { + File(context.cacheDir.absolutePath + "/downloads/config${System.currentTimeMillis()}.txt").apply { writeText(command) }.absolutePath ) @@ -93,7 +90,6 @@ class TerminalDownloadWorker( finalPath = moveFile(tempFileDir.absoluteFile, downloadLocation!!){ progress -> setProgressAsync(workDataOf("progress" to progress)) } - setProgressAsync(workDataOf("progress" to 100, "output" to "Moved file to $finalPath", "id" to itemId, "log" to logDownloads)) }catch (e: Exception){ finalPath = context.getString(R.string.unfound_file) e.printStackTrace() @@ -101,20 +97,7 @@ class TerminalDownloadWorker( Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show() }, 1000) } - //put download in history -// val incognito = sharedPreferences.getBoolean("incognito", false) -// if (!incognito) { -// val unixtime = System.currentTimeMillis() / 1000 -// val file = File(finalPath!!) -// downloadItem.format.filesize = if (file.exists()) file.length() else 0L -// val historyItem = HistoryItem(0, downloadItem.url, downloadItem.title, downloadItem.author, downloadItem.duration, downloadItem.thumb, downloadItem.type, unixtime, finalPath, downloadItem.website, downloadItem.format) -// runBlocking { -// historyDao.insert(historyItem) -// } -// } -// runBlocking { -// dao.delete(downloadItem.id) -// } + }.onFailure { if (it is YoutubeDL.CanceledException) { return Result.failure() @@ -123,8 +106,6 @@ class TerminalDownloadWorker( if (logDownloads && logFile.exists()){ logFile.appendText("${it.message}\n") } - setProgressAsync(workDataOf("progress" to -1, "output" to it.message, "id" to itemId, "log" to logDownloads)) - tempFileDir.delete() Log.e(TAG, context.getString(R.string.failed_download), it) @@ -133,7 +114,14 @@ class TerminalDownloadWorker( context.getString(R.string.failed_download), 0, 0, command.take(20), NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID ) - return Result.failure() + + if (logDownloads && logFile.exists()){ + logFile.appendText("${it.message}\n") + } + + return Result.failure( + Data.Builder().putString("output", it.message.toString()).build() + ) } return Result.success() diff --git a/app/src/main/res/layout/active_download_card.xml b/app/src/main/res/layout/active_download_card.xml index 78caa092..bcd1ffe5 100644 --- a/app/src/main/res/layout/active_download_card.xml +++ b/app/src/main/res/layout/active_download_card.xml @@ -105,13 +105,13 @@ + app:layout_constraintTop_toBottomOf="@+id/barrier"> - + android:layout_height="wrap_content" + android:focusableInTouchMode="true" + android:orientation="vertical"> + + + +