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"> + + + +