stuff
added auto preferred download type Show collected file size in multi download card fixed app chossing worst format and not best fixed update util not working in release fixed ytm playlists not loading fixed sponsorblock not being checked in multiple download card added playlist and playlist index metadata in download items added -a txt path if preferred download type is command or if the txt file is shared in terminal fixed app cancelling workmanager earlier than expected added title and author sync between audio and video frgaments
This commit is contained in:
parent
a1510cdcfa
commit
236f83d161
29 changed files with 377 additions and 155 deletions
|
|
@ -56,9 +56,7 @@
|
|||
android:theme="@style/Theme.BottomSheet">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import android.view.View
|
|||
import android.view.WindowInsets
|
||||
import android.widget.CheckBox
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.app.ActivityCompat
|
||||
|
|
@ -39,7 +40,9 @@ import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
|||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.ui.BaseActivity
|
||||
import com.deniscerri.ytdlnis.ui.HomeFragment
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.more.settings.SettingsActivity
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
|
|
@ -54,8 +57,10 @@ import kotlinx.coroutines.Job
|
|||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.io.Reader
|
||||
import java.net.URI
|
||||
import java.nio.charset.Charset
|
||||
import java.nio.charset.StandardCharsets
|
||||
import kotlin.system.exitProcess
|
||||
|
|
@ -332,26 +337,38 @@ class MainActivity : BaseActivity() {
|
|||
}else{
|
||||
intent.getParcelableExtra(Intent.EXTRA_STREAM)
|
||||
}
|
||||
val `is` = contentResolver.openInputStream(uri!!)
|
||||
val textBuilder = StringBuilder()
|
||||
val reader: Reader = BufferedReader(
|
||||
InputStreamReader(
|
||||
`is`, Charset.forName(
|
||||
StandardCharsets.UTF_8.name()
|
||||
|
||||
if (preferences.getString("preferred_download_type", "video") == "command"){
|
||||
val f = File(FileUtil.formatPath(uri?.path ?: ""))
|
||||
if (!f.exists()){
|
||||
Toast.makeText(context, "Couldn't read file", Toast.LENGTH_LONG).show()
|
||||
return
|
||||
}
|
||||
val item = downloadViewModel.createEmptyResultItem(f.absolutePath)
|
||||
val bottomSheet = DownloadBottomSheetDialog(item, DownloadViewModel.Type.command, null, true)
|
||||
bottomSheet.show(supportFragmentManager, "downloadSingleSheet")
|
||||
}else{
|
||||
val `is` = contentResolver.openInputStream(uri!!)
|
||||
val textBuilder = StringBuilder()
|
||||
val reader: Reader = BufferedReader(
|
||||
InputStreamReader(
|
||||
`is`, Charset.forName(
|
||||
StandardCharsets.UTF_8.name()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
var c: Int
|
||||
while (reader.read().also { c = it } != -1) {
|
||||
textBuilder.append(c.toChar())
|
||||
var c: Int
|
||||
while (reader.read().also { c = it } != -1) {
|
||||
textBuilder.append(c.toChar())
|
||||
}
|
||||
val bundle = Bundle()
|
||||
bundle.putString("url", textBuilder.toString())
|
||||
navController.popBackStack(R.id.homeFragment, true)
|
||||
navController.navigate(
|
||||
R.id.homeFragment,
|
||||
bundle
|
||||
)
|
||||
}
|
||||
val bundle = Bundle()
|
||||
bundle.putString("url", textBuilder.toString())
|
||||
navController.popBackStack(R.id.homeFragment, true)
|
||||
navController.navigate(
|
||||
R.id.homeFragment,
|
||||
bundle
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
DownloadViewModel.Type.audio -> type.setIconResource(R.drawable.ic_music)
|
||||
DownloadViewModel.Type.video -> type.setIconResource(R.drawable.ic_video)
|
||||
DownloadViewModel.Type.command -> type.setIconResource(R.drawable.ic_terminal)
|
||||
else -> {}
|
||||
}
|
||||
|
||||
val formatDetailsChip = card.findViewById<Chip>(R.id.format_note)
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ class DownloadLogsAdapter(onItemClickListener: OnItemClickListener, activity: Ac
|
|||
DownloadViewModel.Type.audio -> downloadTypeIcon.setIconResource(R.drawable.ic_music)
|
||||
DownloadViewModel.Type.video -> downloadTypeIcon.setIconResource(R.drawable.ic_video)
|
||||
DownloadViewModel.Type.command -> downloadTypeIcon.setIconResource(R.drawable.ic_terminal)
|
||||
else -> {}
|
||||
}
|
||||
|
||||
val formatNote = card.findViewById<TextView>(R.id.format_note)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
|||
data class DownloadItem(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long,
|
||||
val url: String,
|
||||
var url: String,
|
||||
var title: String,
|
||||
var author: String,
|
||||
var thumb: String,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class GithubRelease(
|
||||
@SerializedName(value = "tag_name")
|
||||
var tag_name: String,
|
||||
@SerializedName(value = "body")
|
||||
var body: String,
|
||||
@SerializedName(value = "assets")
|
||||
var assets: List<GithubReleaseAsset>
|
||||
)
|
||||
|
||||
|
||||
data class GithubReleaseAsset(
|
||||
@SerializedName(value = "name")
|
||||
var name: String,
|
||||
@SerializedName(value = "browser_download_url")
|
||||
var browser_download_url: String
|
||||
)
|
||||
|
|
@ -85,9 +85,15 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
private val dao: DownloadDao
|
||||
|
||||
enum class Type {
|
||||
audio, video, command
|
||||
auto, audio, video, command
|
||||
}
|
||||
|
||||
private val urlsForAudioType = listOf(
|
||||
"music",
|
||||
"audio",
|
||||
"soundcloud"
|
||||
)
|
||||
|
||||
init {
|
||||
dbManager = DBManager.getInstance(application)
|
||||
dao = dbManager.downloadDao
|
||||
|
|
@ -194,6 +200,13 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
return repository.getItemByID(id)
|
||||
}
|
||||
|
||||
private fun getSuitableDownloadType(url: String): Type{
|
||||
if (urlsForAudioType.any { url.contains(it) }){
|
||||
return Type.audio
|
||||
}
|
||||
return Type.video
|
||||
}
|
||||
|
||||
fun createDownloadItemFromResult(resultItem: ResultItem, givenType: Type) : DownloadItem {
|
||||
val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false)
|
||||
val saveSubs = sharedPreferences.getBoolean("write_subtitles", false)
|
||||
|
|
@ -202,6 +215,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
||||
|
||||
var type = givenType
|
||||
if (type == Type.auto){
|
||||
type = getSuitableDownloadType(resultItem.url)
|
||||
}
|
||||
if(type == Type.command && commandTemplateDao.getTotalNumber() == 0) type = Type.video
|
||||
|
||||
val customFileNameTemplate = when(type) {
|
||||
|
|
@ -320,6 +336,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
Type.audio -> sharedPreferences.getString("music_path", FileUtil.getDefaultAudioPath())!!
|
||||
Type.video -> sharedPreferences.getString("video_path", FileUtil.getDefaultVideoPath())!!
|
||||
Type.command -> sharedPreferences.getString("command_path", FileUtil.getDefaultCommandPath())!!
|
||||
else -> ""
|
||||
}
|
||||
|
||||
list.forEach {
|
||||
|
|
@ -329,6 +346,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
Type.audio -> sharedPreferences.getString("music_path", FileUtil.getDefaultAudioPath())
|
||||
Type.video -> sharedPreferences.getString("video_path", FileUtil.getDefaultVideoPath())
|
||||
Type.command -> sharedPreferences.getString("command_path", FileUtil.getDefaultCommandPath())
|
||||
else -> ""
|
||||
}
|
||||
if (it.downloadPath == currentDownloadPath) it.downloadPath = updatedDownloadPath
|
||||
|
||||
|
|
@ -359,6 +377,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
Type.audio -> FileUtil.getDefaultAudioPath()
|
||||
Type.video -> FileUtil.getDefaultVideoPath()
|
||||
Type.command -> FileUtil.getDefaultCommandPath()
|
||||
else -> ""
|
||||
}
|
||||
|
||||
val sponsorblock = sharedPreferences.getStringSet("sponsorblock_filters", emptySet())
|
||||
|
|
@ -404,7 +423,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
Type.video -> {
|
||||
return cloneFormat(
|
||||
try {
|
||||
val theFormats = formats.filter { !it.format_note.contains("audio", true) }.sortedBy { it.format_id }.ifEmpty { defaultVideoFormats }
|
||||
val theFormats = formats.filter { !it.format_note.contains("audio", true) }.sortedBy { it.format_id }.ifEmpty { defaultVideoFormats }.sortedByDescending { it.filesize }
|
||||
when (videoQualityPreference) {
|
||||
"worst" -> {
|
||||
theFormats.first()
|
||||
|
|
@ -416,7 +435,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
requirements.add { it: Format -> it.format_note.contains(videoQualityPreference.substring(0, videoQualityPreference.length - 1)) }
|
||||
requirements.add { it: Format -> it.vcodec.startsWith(videoCodec!!, true) }
|
||||
|
||||
theFormats.reversed().maxByOrNull { f -> requirements.count{ req -> req(f)} } ?: throw Exception()
|
||||
theFormats.maxByOrNull { f -> requirements.count{ req -> req(f)} } ?: throw Exception()
|
||||
}
|
||||
}
|
||||
}catch (e: Exception){
|
||||
|
|
@ -468,8 +487,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
|
||||
fun turnResultItemsToDownloadItems(items: List<ResultItem?>) : List<DownloadItem> {
|
||||
val list : MutableList<DownloadItem> = mutableListOf()
|
||||
val preferredType = sharedPreferences.getString("preferred_download_type", "video")
|
||||
var preferredType = sharedPreferences.getString("preferred_download_type", "video")
|
||||
items.forEach {
|
||||
if (preferredType == Type.auto.toString()) preferredType = getSuitableDownloadType(it!!.url).toString()
|
||||
list.add(createDownloadItemFromResult(it!!, Type.valueOf(preferredType!!)))
|
||||
}
|
||||
return list
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.deniscerri.ytdlnis.database.viewmodel
|
|||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
import android.util.Patterns
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
|
@ -111,14 +112,14 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
|
|||
}
|
||||
private fun getQueryType(inputQuery: String) : String {
|
||||
var type = "Search"
|
||||
val p = Pattern.compile("(^(https?)://(www.)?(music.)?youtu(.be)?)|(^(https?)://(www.)?piped.video)")
|
||||
val p = Pattern.compile("(^(https?)://(www.)?youtu(.be)?)|(^(https?)://(www.)?piped.video)")
|
||||
val m = p.matcher(inputQuery)
|
||||
if (m.find()) {
|
||||
type = "YT_Video"
|
||||
if (inputQuery.contains("playlist?list=") && !inputQuery.contains("music.youtu")) {
|
||||
if (inputQuery.contains("playlist?list=")) {
|
||||
type = "YT_Playlist"
|
||||
}
|
||||
} else if (inputQuery.contains("http")) {
|
||||
} else if (Patterns.WEB_URL.matcher(inputQuery).matches()) {
|
||||
type = "Default"
|
||||
}
|
||||
return type
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
homeAdapter!!.submitList(it)
|
||||
resultsList = it
|
||||
if(resultViewModel.repository.itemCount.value > 1 || resultViewModel.repository.itemCount.value == -1){
|
||||
if (it.size > 1 && it[0].playlistTitle.isNotEmpty() && it[0].playlistTitle != getString(R.string.trendingPlaylist) && !loadingItems){
|
||||
if (it.size > 1 && it[0].playlistTitle.isNotEmpty() && !loadingItems){
|
||||
downloadAllFabCoordinator!!.visibility = VISIBLE
|
||||
}else{
|
||||
downloadAllFabCoordinator!!.visibility = GONE
|
||||
|
|
@ -187,7 +187,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
recyclerView?.setPadding(0,0,0,100)
|
||||
shimmerCards!!.stopShimmer()
|
||||
shimmerCards!!.visibility = GONE
|
||||
if (resultsList!!.size > 1 && resultsList!![0]!!.playlistTitle.isNotEmpty() && resultsList!![0]!!.playlistTitle != getString(R.string.trendingPlaylist)){
|
||||
if (resultsList!!.size > 1 && resultsList!![0]!!.playlistTitle.isNotEmpty()){
|
||||
downloadAllFabCoordinator!!.visibility = VISIBLE
|
||||
}else{
|
||||
downloadAllFabCoordinator!!.visibility = GONE
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
|
@ -64,7 +65,6 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
super.setupDialog(dialog, style)
|
||||
val view = LayoutInflater.from(context).inflate(R.layout.configure_download_bottom_sheet, null)
|
||||
dialog.setContentView(view)
|
||||
|
||||
dialog.setOnShowListener {
|
||||
behavior = BottomSheetBehavior.from(view.parent as View)
|
||||
val displayMetrics = DisplayMetrics()
|
||||
|
|
@ -80,7 +80,7 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
overScrollMode = View.OVER_SCROLL_NEVER
|
||||
}
|
||||
|
||||
val fragments = mutableListOf(
|
||||
val fragments = mutableListOf<Fragment>(
|
||||
DownloadAudioFragment(resultItem, downloadItem),
|
||||
DownloadVideoFragment(resultItem, downloadItem)
|
||||
)
|
||||
|
|
@ -161,6 +161,9 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
viewPager2.registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
tabLayout.selectTab(tabLayout.getTabAt(position))
|
||||
runCatching {
|
||||
updateTitleAuthorWhenSwitching()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -168,22 +171,7 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
|
||||
val ok = view.findViewById<Button>(R.id.bottom_sheet_ok)
|
||||
ok!!.setOnClickListener {
|
||||
|
||||
val item : DownloadItem = when(tabLayout.selectedTabPosition){
|
||||
0 -> {
|
||||
val f = fragmentManager.findFragmentByTag("f0") as DownloadAudioFragment
|
||||
f.downloadItem
|
||||
}
|
||||
1 -> {
|
||||
val f = fragmentManager.findFragmentByTag("f1") as DownloadVideoFragment
|
||||
f.downloadItem
|
||||
}
|
||||
else -> {
|
||||
val f = fragmentManager.findFragmentByTag("f2") as DownloadCommandFragment
|
||||
f.downloadItem
|
||||
}
|
||||
}
|
||||
Log.e("aa", item.toString())
|
||||
val item = getDownloadItem()
|
||||
onDownloadItemUpdateListener.onDownloadItemUpdate(resultItem.id, item)
|
||||
dismiss()
|
||||
}
|
||||
|
|
@ -200,6 +188,47 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
|
||||
}
|
||||
|
||||
private fun getDownloadItem(selectedTabPosition: Int = tabLayout.selectedTabPosition) : DownloadItem{
|
||||
return when(selectedTabPosition){
|
||||
0 -> {
|
||||
val f = fragmentManager?.findFragmentByTag("f0") as DownloadAudioFragment
|
||||
f.downloadItem
|
||||
}
|
||||
1 -> {
|
||||
val f = fragmentManager?.findFragmentByTag("f1") as DownloadVideoFragment
|
||||
f.downloadItem
|
||||
}
|
||||
else -> {
|
||||
val f = fragmentManager?.findFragmentByTag("f2") as DownloadCommandFragment
|
||||
f.downloadItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun updateTitleAuthorWhenSwitching(){
|
||||
val prevDownloadItem = getDownloadItem(
|
||||
if (viewPager2.currentItem == 1) 0 else 1
|
||||
)
|
||||
|
||||
resultItem.title = prevDownloadItem.title
|
||||
resultItem.author = prevDownloadItem.author
|
||||
downloadItem.title = prevDownloadItem.title
|
||||
downloadItem.author = prevDownloadItem.author
|
||||
|
||||
when(viewPager2.currentItem){
|
||||
0 -> {
|
||||
val f = fragmentManager?.findFragmentByTag("f0") as DownloadAudioFragment
|
||||
f.updateTitleAuthor(prevDownloadItem.title, prevDownloadItem.author)
|
||||
}
|
||||
1 -> {
|
||||
val f = fragmentManager?.findFragmentByTag("f1") as DownloadVideoFragment
|
||||
f.updateTitleAuthor(prevDownloadItem.title, prevDownloadItem.author)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface OnDownloadItemUpdateListener {
|
||||
fun onDownloadItemUpdate(resultItemID: Long, item: DownloadItem)
|
||||
|
|
@ -216,16 +245,6 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
cleanUp()
|
||||
}
|
||||
|
||||
// private fun returnPreviousState(){
|
||||
// CoroutineScope(Dispatchers.IO).launch {
|
||||
// val result = resultViewModel.getItemByURL(currentItem.url)
|
||||
// result.title = currentItem.title
|
||||
// result.author = currentItem.author
|
||||
// Log.e("TAG, ", currentItem.toString())
|
||||
// resultViewModel.update(result)
|
||||
// downloadViewModel.updateDownload(currentItem)
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun cleanUp(){
|
||||
kotlin.runCatching {
|
||||
|
|
|
|||
|
|
@ -37,20 +37,19 @@ import kotlinx.coroutines.withContext
|
|||
import java.io.File
|
||||
|
||||
|
||||
class DownloadAudioFragment(private var resultItem: ResultItem, private var currentDownloadItem: DownloadItem?) : Fragment() {
|
||||
class DownloadAudioFragment(private var resultItem: ResultItem, private var currentDownloadItem: DownloadItem?) : Fragment(), TitleAuthorSync {
|
||||
private var _binding : FragmentHomeBinding? = null
|
||||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var resultViewModel : ResultViewModel
|
||||
|
||||
private lateinit var title : TextInputLayout
|
||||
private lateinit var author : TextInputLayout
|
||||
private lateinit var saveDir : TextInputLayout
|
||||
private lateinit var freeSpace : TextView
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
|
||||
lateinit var downloadItem : DownloadItem
|
||||
lateinit var title : TextInputLayout
|
||||
lateinit var author : TextInputLayout
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
|
@ -238,6 +237,13 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
}
|
||||
}
|
||||
|
||||
override fun updateTitleAuthor(t: String, a: String){
|
||||
downloadItem.title = t
|
||||
downloadItem.author = a
|
||||
title.editText?.setText(t)
|
||||
author.editText?.setText(a)
|
||||
}
|
||||
|
||||
private var audioPathResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
|
|
|
|||
|
|
@ -8,12 +8,14 @@ import android.content.res.Configuration
|
|||
import android.os.Bundle
|
||||
import android.text.format.DateFormat
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Patterns
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
|
|
@ -23,13 +25,13 @@ import com.deniscerri.ytdlnis.R
|
|||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.receiver.ShareActivity
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
|
|
@ -38,7 +40,6 @@ import com.google.android.material.button.MaterialButton
|
|||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
|
@ -56,7 +57,6 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
private lateinit var downloadAudioFragment: DownloadAudioFragment
|
||||
private lateinit var downloadVideoFragment: DownloadVideoFragment
|
||||
private lateinit var downloadCommandFragment: DownloadCommandFragment
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
|
|
@ -91,11 +91,12 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
|
||||
downloadAudioFragment = DownloadAudioFragment(resultItem, downloadItem)
|
||||
downloadVideoFragment = DownloadVideoFragment(resultItem, downloadItem)
|
||||
val fragments = mutableListOf(downloadAudioFragment, downloadVideoFragment)
|
||||
val fragments = mutableListOf<Fragment>(downloadAudioFragment, downloadVideoFragment)
|
||||
var commandTemplateNr = 0
|
||||
lifecycleScope.launch{
|
||||
withContext(Dispatchers.IO){
|
||||
commandTemplateNr = commandTemplateDao.getTotalNumber()
|
||||
if (!Patterns.WEB_URL.matcher(resultItem.url).matches()) commandTemplateNr++
|
||||
if(commandTemplateNr > 0){
|
||||
downloadCommandFragment = DownloadCommandFragment(resultItem, downloadItem)
|
||||
fragments.add(downloadCommandFragment)
|
||||
|
|
@ -113,6 +114,16 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.alpha = 0.3f
|
||||
}
|
||||
|
||||
//check if the item is coming from a text file
|
||||
val isCommandOnly = (type == Type.command && !Patterns.WEB_URL.matcher(resultItem.url).matches())
|
||||
if (isCommandOnly){
|
||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(0)?.isClickable = false
|
||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(0)?.alpha = 0.3f
|
||||
|
||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.isClickable = false
|
||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.alpha = 0.3f
|
||||
}
|
||||
|
||||
|
||||
val fragmentManager = parentFragmentManager
|
||||
fragmentAdapter = DownloadFragmentAdapter(
|
||||
|
|
@ -173,6 +184,9 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
viewPager2.registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
tabLayout.selectTab(tabLayout.getTabAt(position))
|
||||
runCatching {
|
||||
updateTitleAuthorWhenSwitching()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -186,7 +200,7 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
UiUtil.showDatePicker(fragmentManager) {
|
||||
scheduleBtn.isEnabled = false
|
||||
download.isEnabled = false
|
||||
val item: DownloadItem = getDownloadItem();
|
||||
val item: DownloadItem = getDownloadItem()
|
||||
item.downloadStartTime = it.timeInMillis
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(listOf(item))
|
||||
|
|
@ -199,7 +213,7 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
download!!.setOnClickListener {
|
||||
scheduleBtn.isEnabled = false
|
||||
download.isEnabled = false
|
||||
val item: DownloadItem = getDownloadItem();
|
||||
val item: DownloadItem = getDownloadItem()
|
||||
runBlocking {
|
||||
downloadViewModel.queueDownloads(listOf(item))
|
||||
}
|
||||
|
|
@ -223,45 +237,50 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
}
|
||||
|
||||
val link = view.findViewById<Button>(R.id.bottom_sheet_link)
|
||||
link.text = resultItem.url
|
||||
link.setOnClickListener{
|
||||
UiUtil.openLinkIntent(requireContext(), resultItem.url, null)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), resultItem.url, null)
|
||||
true
|
||||
}
|
||||
|
||||
val updateItem = view.findViewById<Button>(R.id.update_item)
|
||||
if (quickDownload) {
|
||||
(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)
|
||||
}else{
|
||||
dismiss()
|
||||
val bundle = Bundle()
|
||||
bundle.putString("url", resultItem.url)
|
||||
findNavController().popBackStack(R.id.homeFragment, true)
|
||||
findNavController().navigate(
|
||||
R.id.homeFragment,
|
||||
bundle
|
||||
)
|
||||
}
|
||||
if (Patterns.WEB_URL.matcher(resultItem.url).matches()){
|
||||
link.text = resultItem.url
|
||||
link.setOnClickListener{
|
||||
UiUtil.openLinkIntent(requireContext(), resultItem.url, null)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), resultItem.url, null)
|
||||
true
|
||||
}
|
||||
|
||||
if (quickDownload) {
|
||||
(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)
|
||||
}else{
|
||||
dismiss()
|
||||
val bundle = Bundle()
|
||||
bundle.putString("url", resultItem.url)
|
||||
findNavController().popBackStack(R.id.homeFragment, true)
|
||||
findNavController().navigate(
|
||||
R.id.homeFragment,
|
||||
bundle
|
||||
)
|
||||
}
|
||||
}
|
||||
}else{
|
||||
(updateItem.parent as LinearLayout).visibility = View.GONE
|
||||
}
|
||||
|
||||
}else{
|
||||
(updateItem.parent as LinearLayout).visibility = View.GONE
|
||||
link.visibility = View.GONE
|
||||
updateItem.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDownloadItem() : DownloadItem{
|
||||
return when(tabLayout.selectedTabPosition){
|
||||
private fun getDownloadItem(selectedTabPosition: Int = tabLayout.selectedTabPosition) : DownloadItem{
|
||||
return when(selectedTabPosition){
|
||||
0 -> {
|
||||
val f = fragmentManager?.findFragmentByTag("f0") as DownloadAudioFragment
|
||||
f.downloadItem
|
||||
|
|
@ -277,6 +296,29 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateTitleAuthorWhenSwitching(){
|
||||
val prevDownloadItem = getDownloadItem(
|
||||
if (viewPager2.currentItem == 1) 0 else 1
|
||||
)
|
||||
|
||||
resultItem.title = prevDownloadItem.title
|
||||
resultItem.author = prevDownloadItem.author
|
||||
downloadItem?.title = prevDownloadItem.title
|
||||
downloadItem?.author = prevDownloadItem.author
|
||||
|
||||
when(viewPager2.currentItem){
|
||||
0 -> {
|
||||
val f = fragmentManager?.findFragmentByTag("f0") as DownloadAudioFragment
|
||||
f.updateTitleAuthor(prevDownloadItem.title, prevDownloadItem.author)
|
||||
}
|
||||
1 -> {
|
||||
val f = fragmentManager?.findFragmentByTag("f1") as DownloadVideoFragment
|
||||
f.updateTitleAuthor(prevDownloadItem.title, prevDownloadItem.author)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancel(dialog: DialogInterface) {
|
||||
super.onCancel(dialog)
|
||||
cleanUp()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.os.Bundle
|
|||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.util.Patterns
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
|
|
@ -32,6 +33,7 @@ import com.deniscerri.ytdlnis.util.UiUtil
|
|||
import com.deniscerri.ytdlnis.util.UiUtil.enableTextHighlight
|
||||
import com.deniscerri.ytdlnis.util.UiUtil.populateCommandCard
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -77,6 +79,11 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
}
|
||||
}
|
||||
|
||||
if (!Patterns.WEB_URL.matcher(downloadItem.url).matches()){
|
||||
downloadItem.format = downloadViewModel.generateCommandFormat(CommandTemplate(0,"txt", "-a \"${downloadItem.url}\"", false))
|
||||
downloadItem.url = ""
|
||||
}
|
||||
|
||||
try {
|
||||
val templates : MutableList<CommandTemplate> = withContext(Dispatchers.IO){
|
||||
commandTemplateViewModel.getAll().toMutableList()
|
||||
|
|
@ -90,6 +97,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||
override fun afterTextChanged(p0: Editable?) {
|
||||
view.findViewById<MaterialCardView>(R.id.command_card).alpha = 0.3f
|
||||
if (p0!!.isNotEmpty()){
|
||||
chosenCommandView.endIconDrawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_delete_all)
|
||||
}else{
|
||||
|
|
@ -119,26 +127,34 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
chosenCommandView.editText!!.enableScrollText()
|
||||
|
||||
val commandTemplateCard = view.findViewById<MaterialCardView>(R.id.command_card)
|
||||
populateCommandCard(commandTemplateCard, templates.first())
|
||||
|
||||
commandTemplateCard.setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel){
|
||||
chosenCommandView.editText!!.setText(it.content)
|
||||
populateCommandCard(commandTemplateCard, it)
|
||||
downloadItem.format = Format(
|
||||
it.title,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
it.content
|
||||
)
|
||||
runCatching {
|
||||
populateCommandCard(commandTemplateCard, templates.first())
|
||||
commandTemplateCard.setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel){
|
||||
chosenCommandView.editText!!.setText(it.content)
|
||||
populateCommandCard(commandTemplateCard, it)
|
||||
downloadItem.format = Format(
|
||||
it.title,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
it.content
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (downloadItem.url.isEmpty()){
|
||||
view.findViewById<MaterialCardView>(R.id.command_card).alpha = 0.3f
|
||||
}
|
||||
}.onFailure {
|
||||
commandTemplateCard.visibility = View.GONE
|
||||
view.findViewById<Chip>(R.id.editSelected).isEnabled = false
|
||||
view.findViewById<TextView>(R.id.command_txt).visibility = View.GONE
|
||||
}
|
||||
|
||||
saveDir = view.findViewById(R.id.outputPath)
|
||||
|
|
@ -166,7 +182,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
|
||||
UiUtil.configureCommand(
|
||||
view,
|
||||
1,
|
||||
if (downloadItem.url.isEmpty()) 0 else 1,
|
||||
shortcutCount,
|
||||
newTemplateClicked = {
|
||||
UiUtil.showCommandTemplateCreationOrUpdatingSheet(null, requireActivity(), viewLifecycleOwner, commandTemplateViewModel) {
|
||||
|
|
@ -181,6 +197,9 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
0,
|
||||
it.content
|
||||
)
|
||||
commandTemplateCard.visibility = View.VISIBLE
|
||||
view.findViewById<TextView>(R.id.command_txt).visibility = View.VISIBLE
|
||||
view.findViewById<Chip>(R.id.editSelected).isEnabled = true
|
||||
populateCommandCard(commandTemplateCard, it)
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
private lateinit var recyclerView: RecyclerView
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var bottomAppBar: BottomAppBar
|
||||
private lateinit var filesize : TextView
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
|
||||
|
||||
|
|
@ -126,6 +127,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
|
||||
val scheduleBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_schedule_button)
|
||||
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
|
||||
filesize = view.findViewById<TextView>(R.id.filesize)
|
||||
|
||||
|
||||
scheduleBtn.setOnClickListener{
|
||||
|
|
@ -184,6 +186,8 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
DownloadViewModel.Type.command -> {
|
||||
preferredDownloadType.setIcon(R.drawable.baseline_insert_drive_file_24)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
|
||||
val formatListener = object : OnFormatClickListener {
|
||||
|
|
@ -204,6 +208,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
}
|
||||
listAdapter.submitList(items.toList())
|
||||
listAdapter.notifyDataSetChanged()
|
||||
updateFileSize(items.map { it.format.filesize })
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -272,6 +277,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
items = downloadViewModel.switchDownloadType(items, DownloadViewModel.Type.audio).toMutableList()
|
||||
listAdapter.submitList(items.toList())
|
||||
listAdapter.notifyDataSetChanged()
|
||||
updateFileSize(items.map { it.format.filesize })
|
||||
preferredDownloadType.setIcon(R.drawable.baseline_audio_file_24)
|
||||
bottomAppBar.menu[1].icon?.alpha = 255
|
||||
bottomAppBar.menu[3].icon?.alpha = 255
|
||||
|
|
@ -282,6 +288,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
items = downloadViewModel.switchDownloadType(items, DownloadViewModel.Type.video).toMutableList()
|
||||
listAdapter.submitList(items.toList())
|
||||
listAdapter.notifyDataSetChanged()
|
||||
updateFileSize(items.map { it.format.filesize })
|
||||
preferredDownloadType.setIcon(R.drawable.baseline_video_file_24)
|
||||
bottomAppBar.menu[1].icon?.alpha = 255
|
||||
bottomAppBar.menu[3].icon?.alpha = 255
|
||||
|
|
@ -295,6 +302,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
}
|
||||
listAdapter.submitList(items.toList())
|
||||
listAdapter.notifyDataSetChanged()
|
||||
updateFileSize(items.map { it.format.filesize })
|
||||
preferredDownloadType.setIcon(R.drawable.baseline_insert_drive_file_24)
|
||||
bottomAppBar.menu[1].icon?.alpha = 255
|
||||
bottomAppBar.menu[3].icon?.alpha = 30
|
||||
|
|
@ -477,6 +485,8 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
}
|
||||
DownloadViewModel.Type.command -> {
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -486,6 +496,15 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
|
||||
}
|
||||
|
||||
private fun updateFileSize(items: List<Long>){
|
||||
if (items.all { it > 0L }){
|
||||
filesize.visibility = View.VISIBLE
|
||||
filesize.text = "${getString(R.string.file_size)}: ~ ${FileUtil.convertFileSize(items.sum())}"
|
||||
}else{
|
||||
filesize.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private var pathResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
|
|
|
|||
|
|
@ -38,15 +38,15 @@ import kotlinx.coroutines.withContext
|
|||
import java.io.File
|
||||
|
||||
|
||||
class DownloadVideoFragment(private val resultItem: ResultItem, private var currentDownloadItem: DownloadItem?) : Fragment() {
|
||||
class DownloadVideoFragment(private val resultItem: ResultItem, private var currentDownloadItem: DownloadItem?) : Fragment(), TitleAuthorSync {
|
||||
private var _binding : FragmentHomeBinding? = null
|
||||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var resultViewModel: ResultViewModel
|
||||
|
||||
private lateinit var title : TextInputLayout
|
||||
private lateinit var author : TextInputLayout
|
||||
lateinit var title : TextInputLayout
|
||||
lateinit var author : TextInputLayout
|
||||
private lateinit var saveDir : TextInputLayout
|
||||
private lateinit var freeSpace : TextView
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
|
|
@ -266,6 +266,13 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
}
|
||||
}
|
||||
|
||||
override fun updateTitleAuthor(t: String, a: String){
|
||||
downloadItem.title = t
|
||||
downloadItem.author = a
|
||||
title.editText?.setText(t)
|
||||
author.editText?.setText(a)
|
||||
}
|
||||
|
||||
private var videoPathResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloadcard
|
||||
|
||||
interface TitleAuthorSync {
|
||||
fun updateTitleAuthor(t: String, a: String)
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import android.content.ClipboardManager
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.FileObserver
|
||||
|
|
@ -297,7 +298,17 @@ class TerminalActivity : BaseActivity() {
|
|||
Log.e(TAG, "$action $type")
|
||||
if (action == Intent.ACTION_SEND && type != null) {
|
||||
Log.e(TAG, action)
|
||||
val txt = "yt-dlp " + intent.getStringExtra(Intent.EXTRA_TEXT)
|
||||
val text = if (intent.getStringExtra(Intent.EXTRA_TEXT) == null){
|
||||
val uri = if (Build.VERSION.SDK_INT >= 33){
|
||||
intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
|
||||
}else{
|
||||
intent.getParcelableExtra(Intent.EXTRA_STREAM)
|
||||
}
|
||||
"-a \"${FileUtil.formatPath(uri?.path ?: "")}\""
|
||||
}else{
|
||||
intent.getStringExtra(Intent.EXTRA_TEXT)
|
||||
}
|
||||
val txt = "yt-dlp $text"
|
||||
input!!.setText(txt)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,24 @@
|
|||
package com.deniscerri.ytdlnis.util
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.media.MediaScannerConnection
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.DocumentsContract
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.core.net.toUri
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.anggrayudi.storage.callback.FileCallback
|
||||
import com.anggrayudi.storage.callback.FolderCallback
|
||||
import com.anggrayudi.storage.file.copyFileTo
|
||||
import com.anggrayudi.storage.file.copyFolderTo
|
||||
import com.anggrayudi.storage.file.getAbsolutePath
|
||||
import com.anggrayudi.storage.file.moveFileTo
|
||||
import com.anggrayudi.storage.file.moveTo
|
||||
import com.deniscerri.ytdlnis.App
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -56,6 +56,8 @@ object FileUtil {
|
|||
var dataValue = path
|
||||
if (dataValue.startsWith("/storage/")) return dataValue
|
||||
dataValue = dataValue.replace("content://com.android.externalstorage.documents/tree/", "")
|
||||
dataValue = dataValue.replace("^/document/".toRegex(), "")
|
||||
dataValue = dataValue.replace("^primary:".toRegex(), "primary/")
|
||||
dataValue = dataValue.replace("%3A".toRegex(), "/")
|
||||
try {
|
||||
dataValue = URLDecoder.decode(dataValue, StandardCharsets.UTF_8.name())
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ class InfoUtil(private val context: Context) {
|
|||
for (i in 0 until dataArray.length()){
|
||||
val obj = dataArray.getJSONObject(i)
|
||||
val itm = createVideoFromPipedJSON(obj, "https://youtube.com" + obj.getString("url"))
|
||||
itm?.playlistTitle = "YTDLnis"
|
||||
itm?.playlistTitle = res.getString("name") + "[${i+1}]"
|
||||
items.add(itm)
|
||||
}
|
||||
if (nextpage == "null") nextpage = ""
|
||||
|
|
@ -382,7 +382,6 @@ class InfoUtil(private val context: Context) {
|
|||
if (v == null || v.thumb.isEmpty()) {
|
||||
continue
|
||||
}
|
||||
v.playlistTitle = context.getString(R.string.trendingPlaylist)
|
||||
items.add(v)
|
||||
}
|
||||
return items
|
||||
|
|
@ -398,7 +397,6 @@ class InfoUtil(private val context: Context) {
|
|||
element.put("uploader", element.getString("uploaderName"))
|
||||
val v = createVideoFromPipedJSON(element, "https://youtube.com" + element.getString("url"))
|
||||
if (v == null || v.thumb.isEmpty()) continue
|
||||
v.playlistTitle = context.getString(R.string.trendingPlaylist)
|
||||
items.add(v)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
|
@ -627,6 +625,11 @@ class InfoUtil(private val context: Context) {
|
|||
var playlistTitle: String? = ""
|
||||
if (jsonObject.has("playlist_title")) playlistTitle = jsonObject.getString("playlist_title")
|
||||
if(playlistTitle.equals(query)) playlistTitle = ""
|
||||
|
||||
if (playlistTitle?.isNotBlank() == true){
|
||||
playlistTitle += "[${jsonObject.getString("playlist_index")}]"
|
||||
}
|
||||
|
||||
val formatsInJSON = if (jsonObject.has("formats") && jsonObject.get("formats") is JSONArray) jsonObject.getJSONArray("formats") else null
|
||||
val formats : ArrayList<Format> = parseYTDLFormats(formatsInJSON)
|
||||
|
||||
|
|
@ -967,6 +970,19 @@ class InfoUtil(private val context: Context) {
|
|||
downDir.mkdirs()
|
||||
}
|
||||
|
||||
if (downloadItem.playlistTitle.isNotBlank()){
|
||||
request.addOption("--parse-metadata","${downloadItem.playlistTitle.split("[")[0]}:%(playlist)s")
|
||||
runCatching {
|
||||
request.addOption("--parse-metadata",
|
||||
downloadItem.playlistTitle
|
||||
.substring(
|
||||
downloadItem.playlistTitle.indexOf("[") + 1,
|
||||
downloadItem.playlistTitle.indexOf("]"),
|
||||
) + ":%(playlist_index)s"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val aria2 = sharedPreferences.getBoolean("aria2", false)
|
||||
if (aria2) {
|
||||
|
|
@ -1017,15 +1033,13 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if(downloadItem.title.isNotBlank()){
|
||||
request.addCommands(listOf("--replace-in-metadata","title",".*.",downloadItem.title.take(200)))
|
||||
request.addOption("--parse-metadata", downloadItem.title.take(200) + ":%(title)s")
|
||||
}
|
||||
if (downloadItem.author.isNotBlank()){
|
||||
request.addCommands(listOf("--replace-in-metadata","uploader",".*.",downloadItem.author.take(25)))
|
||||
downloadItem.customFileNameTemplate = downloadItem.customFileNameTemplate.replace("%(uploader)s", downloadItem.author.take(25))
|
||||
request.addOption("--parse-metadata", downloadItem.author.take(25) + ":%(artist)s")
|
||||
}
|
||||
request.addCommands(listOf("--replace-in-metadata","uploader"," - Topic$",""))
|
||||
request.addCommands(listOf("--replace-in-metadata","artist"," - Topic$",""))
|
||||
|
||||
if (downloadItem.downloadSections.isNotBlank()){
|
||||
downloadItem.downloadSections.split(";").forEach {
|
||||
|
|
@ -1319,6 +1333,8 @@ class InfoUtil(private val context: Context) {
|
|||
)
|
||||
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
|
||||
return request
|
||||
|
|
@ -1333,7 +1349,15 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
return java.lang.String.join(" ", arr).replace("\"\"", "\" \"")
|
||||
var final = java.lang.String.join(" ", arr).replace("\"\"", "\" \"")
|
||||
val ppas = "--config(-locations)? \"(.*?)\"".toRegex().findAll(final)
|
||||
ppas.forEach {
|
||||
val path = "\"(.*?)\"".toRegex().find(it.value)?.value?.replace("\"", "")
|
||||
final = final.replace(it.value, "")
|
||||
final += " ${File(path ?: "").readText()}"
|
||||
}
|
||||
|
||||
return final
|
||||
}
|
||||
|
||||
private val pipedURL = sharedPreferences.getString("piped_instance", defaultPipedURL)?.ifEmpty { defaultPipedURL }?.removeSuffix("/")
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.content.Context
|
|||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.ShapeDrawable
|
||||
import android.graphics.drawable.shapes.OvalShape
|
||||
import android.net.Uri
|
||||
|
|
@ -22,7 +23,6 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.webkit.MimeTypeMap
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
|
|
@ -40,6 +40,7 @@ import androidx.fragment.app.FragmentManager
|
|||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.App
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
|
|
@ -76,6 +77,7 @@ import java.util.Calendar
|
|||
import java.util.Locale
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
object UiUtil {
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun populateFormatCard(context: Context, formatCard : MaterialCardView, chosenFormat: Format, audioFormats: List<Format>?){
|
||||
|
|
@ -118,6 +120,7 @@ object UiUtil {
|
|||
fun populateCommandCard(card: MaterialCardView, item: CommandTemplate){
|
||||
card.findViewById<TextView>(R.id.title).text = item.title
|
||||
card.findViewById<TextView>(R.id.content).text = item.content
|
||||
card.alpha = 1f
|
||||
card.tag = item.id
|
||||
}
|
||||
|
||||
|
|
@ -812,7 +815,7 @@ object UiUtil {
|
|||
val entries = context.resources.getStringArray(R.array.sponsorblock_settings_entries)
|
||||
val checkedItems : ArrayList<Boolean> = arrayListOf()
|
||||
values.forEach {
|
||||
if (items[0].videoPreferences.sponsorBlockFilters.contains(it) && items.size == 1) {
|
||||
if (items.all{ i -> i.videoPreferences.sponsorBlockFilters.contains(it)}) {
|
||||
checkedItems.add(true)
|
||||
}else{
|
||||
checkedItems.add(false)
|
||||
|
|
@ -1034,7 +1037,7 @@ object UiUtil {
|
|||
val entries = context.resources.getStringArray(R.array.sponsorblock_settings_entries)
|
||||
val checkedItems : ArrayList<Boolean> = arrayListOf()
|
||||
values.forEach {
|
||||
if (items[0].audioPreferences.sponsorBlockFilters.contains(it) && items.size == 1) {
|
||||
if (items.all{ i -> i.audioPreferences.sponsorBlockFilters.contains(it)}) {
|
||||
checkedItems.add(true)
|
||||
}else{
|
||||
checkedItems.add(false)
|
||||
|
|
|
|||
|
|
@ -49,17 +49,15 @@ class UpdateUtil(var context: Context) {
|
|||
}
|
||||
|
||||
val useBeta = sharedPreferences.getBoolean("update_beta", false)
|
||||
val v: GithubRelease? = runCatching {
|
||||
res.firstOrNull {
|
||||
if (useBeta) it.tag_name.contains("beta", true)
|
||||
else !it.tag_name.contains("beta", true)
|
||||
}
|
||||
}.getOrNull()
|
||||
var v: GithubRelease?
|
||||
if (useBeta){
|
||||
v = res.firstOrNull { it.tag_name.contains("beta", true) && res.indexOf(it) == 0 }
|
||||
if (v == null) v = res.first()
|
||||
}else{
|
||||
v = res.first { !it.tag_name.contains("beta", true) }
|
||||
}
|
||||
|
||||
if (
|
||||
(useBeta && v == null) ||
|
||||
BuildConfig.VERSION_NAME == v!!.tag_name.removePrefix("v").removeSuffix("-beta")
|
||||
){
|
||||
if (BuildConfig.VERSION_NAME == v.tag_name.removePrefix("v")){
|
||||
result(context.getString(R.string.you_are_in_latest_version))
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.util.Calendar
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
|
|
@ -231,8 +230,6 @@ class DownloadWorker(
|
|||
if (logDownloads){
|
||||
logRepo.update(it.out, logItem.id)
|
||||
}
|
||||
|
||||
if (items.size <= 1) WorkManager.getInstance(context).cancelWorkById(this@DownloadWorker.id)
|
||||
}
|
||||
|
||||
}.onFailure {
|
||||
|
|
|
|||
|
|
@ -86,6 +86,20 @@
|
|||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/filesize"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingTop="10dp"
|
||||
android:visibility="gone"
|
||||
android:text="@string/file_size"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/downloadMultipleRecyclerview"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/command_txt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="10dp"
|
||||
|
|
|
|||
9
app/src/main/res/layout/textview.xml
Normal file
9
app/src/main/res/layout/textview.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
android:id="@+id/textview"
|
||||
android:textStyle="bold"
|
||||
android:fontFamily="monospace"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
</TextView>
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
<string name="audio_format">অডিও ফরম্যাট</string>
|
||||
<string name="title">শিরোনাম</string>
|
||||
<string name="adjust_audio">অডিও সামঞ্জস্য করুন</string>
|
||||
<string name="workmanager_updated">এই পছন্দটি কার্যকর করার জন্য আপনাকে অ্যাপটি পুনরায় চালু করতে হবে এবং কোনও সক্রিয় ডাউনলোড নেই!</string>
|
||||
<string name="dont_ask_again">আবার জিজ্ঞাসা করবেন না</string>
|
||||
<string name="music_directory">মিউজিক ফোল্ডার</string>
|
||||
<string name="warning">সতর্কতা</string>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
<string name="in_queue">Di Antrean</string>
|
||||
<string name="split_by_chapters">Kapisah dening Undhang-undhang</string>
|
||||
<string name="adjust_audio">Nyetel Audio</string>
|
||||
<string name="workmanager_updated">Sampeyan kudu miwiti maneh app lan ora duwe download aktif supaya pilihan iki ditrapake!</string>
|
||||
<string name="dont_ask_again">Aja takon maneh</string>
|
||||
<string name="music_directory">Folder musik</string>
|
||||
<string name="warning">Pènget</string>
|
||||
|
|
|
|||
|
|
@ -144,12 +144,14 @@
|
|||
|
||||
|
||||
<string-array name="download_types">
|
||||
<item>@string/auto</item>
|
||||
<item>@string/audio</item>
|
||||
<item>@string/video</item>
|
||||
<item>@string/command</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="download_types_values">
|
||||
<item>auto</item>
|
||||
<item>audio</item>
|
||||
<item>video</item>
|
||||
<item>command</item>
|
||||
|
|
@ -800,4 +802,5 @@
|
|||
<item>h264</item>
|
||||
</string-array>
|
||||
|
||||
<string name="auto">Auto</string>
|
||||
</resources>
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
app:title="@string/socks5_proxy" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="video"
|
||||
android:defaultValue="auto"
|
||||
android:entries="@array/download_types"
|
||||
android:entryValues="@array/download_types_values"
|
||||
android:icon="@drawable/ic_download_type"
|
||||
|
|
|
|||
Loading…
Reference in a new issue