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