fixed file scanning and tabs not storing correct types

This commit is contained in:
Denis Çerri 2023-02-03 16:07:46 +01:00
parent 144e8e9bc5
commit 2b0f1322d3
No known key found for this signature in database
GPG key ID: 95C43D517D830350
15 changed files with 185 additions and 206 deletions

View file

@ -165,7 +165,6 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
interface OnItemClickListener { interface OnItemClickListener {
fun onCardClick(itemID: Long, isPresent: Boolean) fun onCardClick(itemID: Long, isPresent: Boolean)
fun onCardSelect(itemID: Long, isChecked: Boolean) fun onCardSelect(itemID: Long, isChecked: Boolean)
fun onButtonClick(position: Int)
} }
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")

View file

@ -21,9 +21,9 @@ data class DownloadItem(
val website: String, val website: String,
val downloadSize: String, val downloadSize: String,
val playlistTitle: String, val playlistTitle: String,
val embedSubs: Boolean, var embedSubs: Boolean,
val addChapters: Boolean, var addChapters: Boolean,
val SaveThumb: Boolean, var SaveThumb: Boolean,
@ColumnInfo(defaultValue = "Queued") @ColumnInfo(defaultValue = "Queued")
var status: String var status: String
) )

View file

@ -29,12 +29,8 @@ class HistoryRepository(private val historyDao: HistoryDao) {
historyDao.insert(item) historyDao.insert(item)
} }
suspend fun delete(item: HistoryItem, deleteFile: Boolean){ suspend fun delete(item: HistoryItem){
historyDao.delete(item.id!!) historyDao.delete(item.id)
if (deleteFile){
val fileUtil = FileUtil()
fileUtil.deleteFile(item.downloadPath)
}
} }
suspend fun deleteAll(){ suspend fun deleteAll(){

View file

@ -33,6 +33,10 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
val processingDownloads : LiveData<List<DownloadItem>> val processingDownloads : LiveData<List<DownloadItem>>
private var bestVideoFormat: Format private var bestVideoFormat: Format
private var bestAudioFormat: Format
enum class Type {
AUDIO, VIDEO, COMMAND
}
init { init {
val dao = DBManager.getInstance(application).downloadDao val dao = DBManager.getInstance(application).downloadDao
@ -45,30 +49,22 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
activeDownloads = repository.activeDownloads activeDownloads = repository.activeDownloads
processingDownloads = repository.processingDownloads processingDownloads = repository.processingDownloads
val format = getApplication<App>().resources.getStringArray(R.array.video_formats) val videoFormat = getApplication<App>().resources.getStringArray(R.array.video_formats)
val container = sharedPreferences.getString("video_format", "Default") val videoContainer = sharedPreferences.getString("video_format", "Default")
bestVideoFormat = Format( bestVideoFormat = Format(
format[format.lastIndex], videoFormat[videoFormat.lastIndex],
container!!, videoContainer!!,
0, 0,
format[format.lastIndex] videoFormat[videoFormat.lastIndex]
) )
}
fun startWork(items: List<DownloadItem>){ val audioContainer = sharedPreferences.getString("audio_format", "mp3")
items.forEach { bestAudioFormat = Format(
insertDownload(it) "",
} audioContainer!!,
0,
} ""
)
fun insertDownload(item: DownloadItem) : LiveData<Long> {
val result = MutableLiveData<Long>()
viewModelScope.launch(Dispatchers.IO){
val id = repository.insert(item)
result.postValue(id)
}
return result
} }
fun deleteDownload(item: DownloadItem) = viewModelScope.launch(Dispatchers.IO) { fun deleteDownload(item: DownloadItem) = viewModelScope.launch(Dispatchers.IO) {
@ -107,12 +103,12 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
return try { return try {
resultItem.formats.last { it.format_note.contains("audio", ignoreCase = true) } resultItem.formats.last { it.format_note.contains("audio", ignoreCase = true) }
}catch (e: Exception){ }catch (e: Exception){
Format() bestAudioFormat
} }
} }
"video" -> { "video" -> {
return try { return try {
resultItem.formats[resultItem.formats.lastIndex] resultItem.formats.last { !it.format_note.contains("audio", ignoreCase = true) }
}catch (e: Exception){ }catch (e: Exception){
bestVideoFormat bestVideoFormat
} }

View file

@ -13,6 +13,7 @@ import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.models.HistoryItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.repository.HistoryRepository import com.deniscerri.ytdlnis.database.repository.HistoryRepository
import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySort import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySort
import com.deniscerri.ytdlnis.util.FileUtil
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -77,7 +78,11 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
} }
fun delete(item: HistoryItem, deleteFile: Boolean) = viewModelScope.launch(Dispatchers.IO){ fun delete(item: HistoryItem, deleteFile: Boolean) = viewModelScope.launch(Dispatchers.IO){
repository.delete(item, deleteFile) repository.delete(item)
if (deleteFile){
val fileUtil = FileUtil()
fileUtil.deleteFile(item.downloadPath)
}
} }
fun deleteAll() = viewModelScope.launch(Dispatchers.IO) { fun deleteAll() = viewModelScope.launch(Dispatchers.IO) {

View file

@ -38,8 +38,7 @@ import java.io.File
/** /**
* A fragment representing a list of Items. * A fragment representing a list of Items.
*/ */
class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener, class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
OnClickListener, OnLongClickListener {
private lateinit var historyViewModel : HistoryViewModel private lateinit var historyViewModel : HistoryViewModel
private var fragmentView: View? = null private var fragmentView: View? = null
@ -90,7 +89,9 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
deleteFab = view.findViewById(R.id.delete_selected_fab) deleteFab = view.findViewById(R.id.delete_selected_fab)
fileUtil = FileUtil() fileUtil = FileUtil()
deleteFab?.tag = "deleteSelected" deleteFab?.tag = "deleteSelected"
deleteFab?.setOnClickListener(this) deleteFab?.setOnClickListener{
removeSelectedItems()
}
uiHandler = Handler(Looper.getMainLooper()) uiHandler = Handler(Looper.getMainLooper())
selectedObjects = ArrayList() selectedObjects = ArrayList()
@ -129,6 +130,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
historyViewModel.getFilteredList().observe(viewLifecycleOwner) { historyViewModel.getFilteredList().observe(viewLifecycleOwner) {
historyAdapter!!.submitList(it) historyAdapter!!.submitList(it)
historyList = it historyList = it
scrollToTop()
} }
initMenu() initMenu()
@ -301,31 +303,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
} }
} }
override fun onClick(v: View) {
when (v.id) {
R.id.bottomsheet_remove_button -> {
removeItem(v.tag as Long)
}
R.id.bottom_sheet_link -> {
openLinkIntent(v.tag as Long)
}
R.id.bottomsheet_open_file_button -> {
openFileIntent(v.tag as Long)
}
R.id.delete_selected_fab -> {
removeSelectedItems()
}
}
}
override fun onLongClick(v: View): Boolean {
val id = v.id
if (id == R.id.bottom_sheet_link) {
copyLinkToClipBoard(v.tag as Long)
return true
}
return false
}
private fun removeSelectedItems() { private fun removeSelectedItems() {
if (bottomSheet != null) bottomSheet!!.hide() if (bottomSheet != null) bottomSheet!!.hide()
@ -348,25 +325,23 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
deleteDialog.show() deleteDialog.show()
} }
private fun removeItem(id: Long) { private fun removeItem(item: HistoryItem) {
if (bottomSheet != null) bottomSheet!!.hide() if (bottomSheet != null) bottomSheet!!.hide()
val deleteFile = booleanArrayOf(false) val deleteFile = booleanArrayOf(false)
val v = findItem(id)
val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!) val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + v!!.title + "\"!") deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + item.title + "\"!")
deleteDialog.setMultiChoiceItems( deleteDialog.setMultiChoiceItems(
arrayOf(getString(R.string.delete_file_too)), arrayOf(getString(R.string.delete_file_too)),
booleanArrayOf(false) booleanArrayOf(false)
) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b } ) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b }
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() } deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int -> deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
historyViewModel.delete(v, deleteFile[0]) historyViewModel.delete(item, deleteFile[0])
} }
deleteDialog.show() deleteDialog.show()
} }
private fun copyLinkToClipBoard(id: Long) { private fun copyLinkToClipBoard(url: String) {
val url = findItem(id)?.url
val clipboard = context?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clipboard = context?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.url), url) val clip = ClipData.newPlainText(getString(R.string.url), url)
clipboard.setPrimaryClip(clip) clipboard.setPrimaryClip(clip)
@ -375,16 +350,14 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
.show() .show()
} }
private fun openLinkIntent(id: Long) { private fun openLinkIntent(url: String) {
val url = findItem(id)?.url
val i = Intent(Intent.ACTION_VIEW) val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(url) i.data = Uri.parse(url)
if (bottomSheet != null) bottomSheet!!.hide() if (bottomSheet != null) bottomSheet!!.hide()
startActivity(i) startActivity(i)
} }
private fun openFileIntent(id: Long) { private fun openFileIntent(downloadPath: String) {
val downloadPath = findItem(id)!!.downloadPath
val file = File(downloadPath) val file = File(downloadPath)
val uri = FileProvider.getUriForFile( val uri = FileProvider.getUriForFile(
fragmentContext!!, fragmentContext!!,
@ -411,14 +384,23 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
val url = video.url val url = video.url
link!!.text = url link!!.text = url
link.tag = videoID link.tag = videoID
link.setOnClickListener(this) link.setOnClickListener{
link.setOnLongClickListener(this) openLinkIntent(video.url)
}
link.setOnLongClickListener{
copyLinkToClipBoard(video.url)
true
}
val remove = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_remove_button) val remove = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_remove_button)
remove!!.tag = videoID remove!!.tag = videoID
remove.setOnClickListener(this) remove.setOnClickListener{
removeItem(video)
}
val openFile = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_open_file_button) val openFile = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_open_file_button)
openFile!!.tag = videoID openFile!!.tag = videoID
openFile.setOnClickListener(this) openFile.setOnClickListener{
openFileIntent(video.downloadPath)
}
if (!isPresent) openFile.visibility = GONE if (!isPresent) openFile.visibility = GONE
bottomSheet!!.show() bottomSheet!!.show()
bottomSheet!!.window!!.setLayout( bottomSheet!!.window!!.setLayout(
@ -438,17 +420,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener,
} }
} }
override fun onButtonClick(position: Int) {
// val vid = historyObjects!![position]
// try {
// //mainActivity!!.removeItemFromDownloadQueue(vid, vid!!.downloadedType)
// } catch (e: Exception) {
// val info = DownloadInfo()
// info.video = vid
// info.downloadType = vid!!.downloadedType
// }
}
private fun findItem(id : Long): HistoryItem? { private fun findItem(id : Long): HistoryItem? {
return historyList?.find { it?.id == id } return historyList?.find { it?.id == id }
} }

View file

@ -8,25 +8,21 @@ import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.widget.Button import android.widget.Button
import android.widget.Toast
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.findFragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem) : BottomSheetDialogFragment() { class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem) : BottomSheetDialogFragment() {
private lateinit var tabLayout: TabLayout private lateinit var tabLayout: TabLayout
@ -36,6 +32,10 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
private lateinit var downloadViewModel: DownloadViewModel private lateinit var downloadViewModel: DownloadViewModel
private lateinit var resultViewModel: ResultViewModel private lateinit var resultViewModel: ResultViewModel
private val audioDownloadItem =clone(downloadItem)
private val videoDownloadItem = clone(downloadItem)
private val commandDownloadItem = clone(downloadItem)
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]
@ -60,7 +60,11 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
viewPager2 = view.findViewById(R.id.download_viewpager) viewPager2 = view.findViewById(R.id.download_viewpager)
val fragmentManager = parentFragmentManager val fragmentManager = parentFragmentManager
fragmentAdapter = DownloadFragmentAdapter(downloadItem, fragmentManager, lifecycle) fragmentAdapter = DownloadFragmentAdapter(
audioDownloadItem,videoDownloadItem,commandDownloadItem,
fragmentManager,
lifecycle
)
viewPager2.adapter = fragmentAdapter viewPager2.adapter = fragmentAdapter
viewPager2.isSaveFromParentEnabled = false viewPager2.isSaveFromParentEnabled = false
@ -104,9 +108,13 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
dismiss() dismiss()
} }
val download = view.findViewById<Button>(R.id.bottom_sheet_ok) val ok = view.findViewById<Button>(R.id.bottom_sheet_ok)
download!!.setOnClickListener { ok!!.setOnClickListener {
downloadViewModel.updateDownload(downloadItem) when(tabLayout.selectedTabPosition){
0 -> downloadViewModel.updateDownload(audioDownloadItem)
1 -> downloadViewModel.updateDownload(videoDownloadItem)
else -> downloadViewModel.updateDownload(commandDownloadItem)
}
dismiss() dismiss()
} }
} }
@ -142,5 +150,10 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
} }
} }
private fun clone(item: DownloadItem) : DownloadItem {
val stringItem = Gson().toJson(item, DownloadItem::class.java)
return Gson().fromJson(stringItem, DownloadItem::class.java)
}
} }

View file

@ -17,20 +17,18 @@ import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdlnis.MainActivity import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
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.viewmodel.DownloadViewModel 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.databinding.FragmentHomeBinding import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment() {
class DownloadAudioFragment(private var downloadItem: DownloadItem) : Fragment() {
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
@ -43,24 +41,7 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
private lateinit var author : TextInputLayout private lateinit var author : TextInputLayout
private lateinit var saveDir : TextInputLayout private lateinit var saveDir : TextInputLayout
override fun onResume() {
super.onResume()
downloadItem.type = "audio"
lifecycleScope.launch{
// val item = withContext(Dispatchers.IO){
// downloadViewModel.getItemByID(downloadItem.id)
// }
// if (::title.isInitialized){
// title.editText!!.setText(item.title)
// downloadItem.title = item.title
// }
// if(::author.isInitialized){
// author.editText!!.setText(item.author)
// downloadItem.author = item.author
// }
}
//downloadViewModel.updateDownload(downloadItem)
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -79,11 +60,11 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
downloadItem.type = "audio"
lifecycleScope.launch { lifecycleScope.launch {
val resultItem = withContext(Dispatchers.IO){ val resultItem = withContext(Dispatchers.IO){
resultViewModel.getItemByURL(downloadItem.url) resultViewModel.getItemByURL(downloadItem.url)
} }
val type = downloadItem.type
val sharedPreferences = val sharedPreferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE) requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
@ -128,13 +109,11 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
audioPathResultLauncher.launch(intent) audioPathResultLauncher.launch(intent)
} }
val formats = resultItem.formats.filter { it.format_note.contains("audio", ignoreCase = true) }
val format = view.findViewById<TextInputLayout>(R.id.format) val format = view.findViewById<TextInputLayout>(R.id.format)
if (formats.isEmpty()) { if (resultItem.formats.isEmpty()) {
format.visibility = View.GONE format.visibility = View.GONE
downloadItem.format = Format()
} else { } else {
val formatTitles = formats.map { val formatTitles = resultItem.formats.map {
if (it.format_note.contains("AUDIO_QUALITY_")) { if (it.format_note.contains("AUDIO_QUALITY_")) {
it.format_note.replace( it.format_note.replace(
"AUDIO_QUALITY_", "AUDIO_QUALITY_",
@ -157,12 +136,12 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
) )
) )
if (formatTitles.isNotEmpty()) { if (formatTitles.isNotEmpty()) {
autoCompleteTextView!!.setText(formatTitles[formats.lastIndex], false) autoCompleteTextView!!.setText(formatTitles[resultItem.formats.lastIndex], false)
} }
(format!!.editText as AutoCompleteTextView?)!!.onItemClickListener = (format!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.format.format_note = formats[index].format_note downloadItem.format.format_note = resultItem.formats[index].format_note
downloadItem.format.format_id = formats[index].format_id downloadItem.format.format_id = resultItem.formats[index].format_id
} }
} }
@ -179,8 +158,12 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
containers containers
) )
) )
val selectedContainer: String = formats.find { downloadItem.format.format_note == it.format_note }?.container Log.e("aa", downloadItem.format.container)
?: sharedPreferences.getString("audio_format", "mp3")!! val selectedContainer: String = if (containers.contains(downloadItem.format.container)){
downloadItem.format.container
}else{
containers[0]
}
downloadItem.format.container = selectedContainer downloadItem.format.container = selectedContainer
containerAutoCompleteTextView!!.setText(selectedContainer, false) containerAutoCompleteTextView!!.setText(selectedContainer, false)
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener = (container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =

View file

@ -4,40 +4,33 @@ import android.annotation.SuppressLint
import android.app.Dialog import android.app.Dialog
import android.content.DialogInterface import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.os.SystemClock
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.widget.Adapter
import android.widget.Button import android.widget.Button
import android.widget.LinearLayout
import androidx.core.view.get
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.findFragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import androidx.work.Data
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
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.work.DownloadWorker
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.gson.Gson
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment() { class DownloadBottomSheetDialog(private val downloadItem: DownloadItem) : BottomSheetDialogFragment() {
private lateinit var tabLayout: TabLayout private lateinit var tabLayout: TabLayout
private lateinit var viewPager2: ViewPager2 private lateinit var viewPager2: ViewPager2
private lateinit var fragmentAdapter : DownloadFragmentAdapter private lateinit var fragmentAdapter : DownloadFragmentAdapter
private val downloadItem = item
private lateinit var downloadViewModel: DownloadViewModel private lateinit var downloadViewModel: DownloadViewModel
private var downloadType = Type.VIDEO
private val audioDownloadItem = clone(downloadItem)
private val videoDownloadItem = clone(downloadItem)
private val commandDownloadItem = clone(downloadItem)
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]
@ -55,11 +48,17 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
val view = LayoutInflater.from(context).inflate(R.layout.download_bottom_sheet, null) val view = LayoutInflater.from(context).inflate(R.layout.download_bottom_sheet, null)
dialog.setContentView(view) dialog.setContentView(view)
Log.e("aaa", downloadItem.toString())
tabLayout = view.findViewById(R.id.download_tablayout) tabLayout = view.findViewById(R.id.download_tablayout)
viewPager2 = view.findViewById(R.id.download_viewpager) viewPager2 = view.findViewById(R.id.download_viewpager)
val fragmentManager = parentFragmentManager val fragmentManager = parentFragmentManager
fragmentAdapter = DownloadFragmentAdapter(downloadItem, fragmentManager, lifecycle) fragmentAdapter = DownloadFragmentAdapter(
audioDownloadItem, videoDownloadItem, commandDownloadItem,
fragmentManager,
lifecycle
)
viewPager2.adapter = fragmentAdapter viewPager2.adapter = fragmentAdapter
viewPager2.isSaveFromParentEnabled = false viewPager2.isSaveFromParentEnabled = false
@ -104,7 +103,13 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
val download = view.findViewById<Button>(R.id.bottomsheet_download_button) val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener { download!!.setOnClickListener {
downloadViewModel.queueDownloads(listOf(downloadItem)) Log.e("aa", tabLayout.selectedTabPosition.toString())
val item: List<DownloadItem> = when(tabLayout.selectedTabPosition){
0 -> listOf(audioDownloadItem)
1 -> listOf(videoDownloadItem)
else -> listOf(commandDownloadItem)
}
downloadViewModel.queueDownloads(item)
dismiss() dismiss()
} }
} }
@ -130,5 +135,14 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
downloadViewModel.deleteSingleProcessing(downloadItem) downloadViewModel.deleteSingleProcessing(downloadItem)
} }
fun updateType(type: Type){
downloadType = type
}
private fun clone(item: DownloadItem) : DownloadItem {
val stringItem = Gson().toJson(item, DownloadItem::class.java)
return Gson().fromJson(stringItem, DownloadItem::class.java)
}
} }

View file

@ -9,7 +9,13 @@ import androidx.viewpager2.adapter.FragmentStateAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.google.gson.Gson import com.google.gson.Gson
class DownloadFragmentAdapter (private val downloadItem : DownloadItem, fragmentManager : FragmentManager, lifecycle : Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) { class DownloadFragmentAdapter (
private val audioDownloadItem : DownloadItem,
private val videoDownloadItem : DownloadItem,
private val commandDownloadItem : DownloadItem,
fragmentManager : FragmentManager,
lifecycle : Lifecycle
) : FragmentStateAdapter(fragmentManager, lifecycle) {
override fun getItemCount(): Int { override fun getItemCount(): Int {
return 3 return 3
@ -18,18 +24,13 @@ class DownloadFragmentAdapter (private val downloadItem : DownloadItem, fragment
override fun createFragment(position: Int): Fragment { override fun createFragment(position: Int): Fragment {
when (position) { when (position) {
0 -> { 0 -> {
return DownloadAudioFragment(downloadItem) return DownloadAudioFragment(audioDownloadItem)
} }
1 -> { 1 -> {
return DownloadVideoFragment(downloadItem) return DownloadVideoFragment(videoDownloadItem)
} }
} }
return DownloadCommandFragment(downloadItem) return DownloadCommandFragment(commandDownloadItem)
} }
private fun clone(item: DownloadItem) : DownloadItem {
val stringItem = Gson().toJson(item, DownloadItem::class.java)
return Gson().fromJson(stringItem, DownloadItem::class.java)
}
} }

View file

@ -5,7 +5,6 @@ import android.content.Intent
import android.os.Bundle 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.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -14,7 +13,6 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdlnis.App
import com.deniscerri.ytdlnis.MainActivity import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
@ -23,12 +21,13 @@ 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.databinding.FragmentHomeBinding import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment() { class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment() {
private var _binding : FragmentHomeBinding? = null private var _binding : FragmentHomeBinding? = null
@ -43,24 +42,8 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
private lateinit var author : TextInputLayout private lateinit var author : TextInputLayout
private lateinit var saveDir : TextInputLayout private lateinit var saveDir : TextInputLayout
override fun onResume() {
super.onResume()
downloadItem.type = "video"
// lifecycleScope.launch{
// val item = withContext(Dispatchers.IO){
// downloadViewModel.getItemByID(downloadItem.id)
// }
// if (::title.isInitialized){
// title.editText!!.setText(item.title)
// downloadItem.title = item.title
// }
// if(::author.isInitialized){
// author.editText!!.setText(item.author)
// downloadItem.author = item.author
// }
// }
//downloadviewmodel.updateDownload(downloadItem)
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -79,7 +62,7 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
downloadItem.type = "video"
lifecycleScope.launch { lifecycleScope.launch {
val resultItem = withContext(Dispatchers.IO){ val resultItem = withContext(Dispatchers.IO){
resultViewModel.getItemByURL(downloadItem.url) resultViewModel.getItemByURL(downloadItem.url)
@ -140,13 +123,17 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
formats.addAll(resultItem.formats.filter { !it.format_note.contains("audio", ignoreCase = true) }) formats.addAll(resultItem.formats.filter { !it.format_note.contains("audio", ignoreCase = true) })
if (formats.isEmpty()) { if (formats.isEmpty()) {
val videoFormats = resources.getStringArray(R.array.video_formats) val videoFormats = resources.getStringArray(R.array.video_formats)
videoFormats.forEach { formats.add(Format(it, "", 0, it)) } val container = sharedPreferences.getString("video_format", "Default")
videoFormats.forEach { formats.add(Format(it, container!!, 0, it)) }
} }
val formatTitles = formats.map { val formatTitles = formats.map {
it.format_note + if (it.filesize == 0L) "" else " / " + fileUtil.convertFileSize(it.filesize) it.format_note + if (it.filesize == 0L) "" else " / " + fileUtil.convertFileSize(it.filesize)
} }
downloadItem.format = formats[formats.lastIndex]
val format = view.findViewById<TextInputLayout>(R.id.format) val format = view.findViewById<TextInputLayout>(R.id.format)
val autoCompleteTextView = val autoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.format_textview) view.findViewById<AutoCompleteTextView>(R.id.format_textview)
@ -181,10 +168,7 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
containers containers
) )
) )
var selectedContainer: String = downloadItem.format.container val selectedContainer: String = downloadItem.format.container
if (selectedContainer.isEmpty()){
selectedContainer = sharedPreferences.getString("video_format", "Default")!!
}
containerAutoCompleteTextView!!.setText(selectedContainer, false) containerAutoCompleteTextView!!.setText(selectedContainer, false)
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener = (container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
@ -193,13 +177,22 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
} }
val embedSubs = view.findViewById<Chip>(R.id.embed_subtitles) val embedSubs = view.findViewById<Chip>(R.id.embed_subtitles)
embedSubs!!.isChecked = sharedPreferences.getBoolean("embed_subtitles", false) embedSubs!!.isChecked = embedSubs.isChecked
embedSubs.setOnClickListener {
downloadItem.embedSubs = embedSubs.isChecked
}
val addChapters = view.findViewById<Chip>(R.id.add_chapters) val addChapters = view.findViewById<Chip>(R.id.add_chapters)
addChapters!!.isChecked = sharedPreferences.getBoolean("add_chapters", false) addChapters!!.isChecked = addChapters.isChecked
addChapters.setOnClickListener{
downloadItem.addChapters = addChapters.isChecked
}
val saveThumbnail = view.findViewById<Chip>(R.id.save_thumbnail) val saveThumbnail = view.findViewById<Chip>(R.id.save_thumbnail)
saveThumbnail!!.isChecked = sharedPreferences.getBoolean("write_thumbnail", false) saveThumbnail!!.isChecked = saveThumbnail.isChecked
saveThumbnail.setOnClickListener {
downloadItem.SaveThumb = saveThumbnail.isChecked
}
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()

View file

@ -17,6 +17,7 @@ import java.nio.file.Files
import java.nio.file.StandardCopyOption import java.nio.file.StandardCopyOption
import java.text.DecimalFormat import java.text.DecimalFormat
import kotlin.math.log10 import kotlin.math.log10
import kotlin.math.max
import kotlin.math.pow import kotlin.math.pow
class FileUtil() { class FileUtil() {
@ -58,21 +59,18 @@ class FileUtil() {
return formattedPath.toString() return formattedPath.toString()
} }
private fun scanMedia(destDir: String, context: Context) : String { private fun scanMedia(destDir: String, fileName: String, context: Context) : String {
val files = ArrayList<File>() val file : File
val path = File(formatPath(destDir)) val path = File(formatPath(destDir))
try { try {
for (file in path.listFiles()!!) { file = path.listFiles()?.find {
if (file.isFile) { it!!.name == fileName
files.add(file) }!!
}
}
val paths = arrayOfNulls<String>(files.size) val paths = arrayOf(file.absolutePath)
for (i in files.indices) paths[i] = files[i].absolutePath
MediaScannerConnection.scanFile(context, paths, null, null) MediaScannerConnection.scanFile(context, paths, null, null)
return paths[0]!! return paths[0]
}catch (e: Exception){ }catch (e: Exception){
e.printStackTrace() e.printStackTrace()
} }
@ -81,12 +79,19 @@ class FileUtil() {
} }
@Throws(Exception::class) @Throws(Exception::class)
fun moveFile(originDir: File, context: Context, destDir: String, progress: (p: Int) -> Unit) : String { fun moveFile(originDir: File, context: Context, destDir: String, progress: (p: Int) -> Unit) : String {
var fileName = ""
var maxSize = 0L
originDir.listFiles()?.forEach { originDir.listFiles()?.forEach {
if (it.name.equals("rList")){ if (it.name.equals("rList")){
it.delete() it.delete()
return@forEach return@forEach
} }
if (it.length() > maxSize){
maxSize = it.length()
fileName = it.name
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
val f = File(formatPath(destDir)+"/"+it.name) val f = File(formatPath(destDir)+"/"+it.name)
f.mkdirs() f.mkdirs()
@ -131,8 +136,12 @@ class FileUtil() {
it.delete() it.delete()
} }
} }
originDir.delete() originDir.delete()
return scanMedia(destDir, context) return if (maxSize > 0L){
scanMedia(destDir, fileName, context)
}else{
context.getString(R.string.unfound_file)
}
} }
fun convertFileSize(s: Long): String{ fun convertFileSize(s: Long): String{

View file

@ -108,9 +108,14 @@ class DownloadWorker(
request.addOption("-x") request.addOption("-x")
var audioQualityId : String = downloadItem.format.format_id var audioQualityId : String = downloadItem.format.format_id
if (audioQualityId == "0" || audioQualityId.isEmpty()) audioQualityId = "ba" if (audioQualityId == "0" || audioQualityId.isEmpty()) audioQualityId = "ba"
val ext = downloadItem.format.container
request.addOption("-f", audioQualityId) request.addOption("-f", audioQualityId)
request.addOption("--audio-format", ext)
val ext = downloadItem.format.container
if(ext != context.getString(R.string.defaultValue)){
request.addOption("--audio-format", ext)
}else{
request.addOption("--audio-format", sharedPreferences.getString("audio_format", "mp3")!!)
}
request.addOption("--embed-metadata") request.addOption("--embed-metadata")
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false) val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)

View file

@ -1,5 +1,6 @@
<resources> <resources>
<string-array name="audio_containers"> <string-array name="audio_containers">
<item>@string/defaultValue</item>
<item>mp3</item> <item>mp3</item>
<item>m4a</item> <item>m4a</item>
<item>aac</item> <item>aac</item>
@ -9,11 +10,6 @@
<item>wav</item> <item>wav</item>
</string-array> </string-array>
<string-array name="audio_formats">
<item>@string/worst</item>
<item>@string/best</item>
</string-array>
<string-array name="video_containers"> <string-array name="video_containers">
<item>@string/defaultValue</item> <item>@string/defaultValue</item>
<item>mp4</item> <item>mp4</item>

View file

@ -160,8 +160,6 @@
<string name="schedule">Schedule</string> <string name="schedule">Schedule</string>
<string name="concurrent_downloads">Concurrent Downloads</string> <string name="concurrent_downloads">Concurrent Downloads</string>
<string name="concurrent_downloads_summary">Number of downloads executing at the same time</string> <string name="concurrent_downloads_summary">Number of downloads executing at the same time</string>
<string name="best">Best</string>
<string name="worst">Worst</string>
<string name="defaultValue">Default</string> <string name="defaultValue">Default</string>
<string name="container">Container</string> <string name="container">Container</string>
<string name="template">Template</string> <string name="template">Template</string>