diff --git a/app/build.gradle b/app/build.gradle index a002eeb8..97f94d83 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -137,7 +137,6 @@ dependencies { implementation "androidx.navigation:navigation-ui-ktx:$navVer" implementation "androidx.navigation:navigation-dynamic-features-fragment:$navVer" implementation 'androidx.core:core-ktx:1.9.0' - implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.test.ext:junit-ktx:1.1.5' implementation 'androidx.benchmark:benchmark-macro:1.1.1' testImplementation "junit:junit:$junitVer" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index aac7de73..87c0ba9e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -115,7 +115,7 @@ ?){ + checkedItems.clear() + checkedItems.addAll(items!!.map { it!!.id }) + notifyDataSetChanged() + } + fun invertSelected(items: List?){ val invertedList = mutableListOf() items?.forEach { diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt index 044d62f1..a193c54b 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt @@ -527,7 +527,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi downloadViewModel.turnResultItemsToDownloadItems(resultsList!!) } if (sharedPreferences!!.getBoolean("download_card", true)) { - val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList.toMutableList()) + val bottomSheet = DownloadMultipleBottomSheetDialog(resultsList!!, downloadList.toMutableList()) bottomSheet.show(parentFragmentManager, "downloadMultipleSheet") } else { downloadViewModel.queueDownloads(downloadList) @@ -584,7 +584,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi actionMode?.finish() if (sharedPreferences!!.getBoolean("download_card", true)) { - val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList.toMutableList()) + val bottomSheet = DownloadMultipleBottomSheetDialog(selectedObjects!!, downloadList.toMutableList()) bottomSheet.show(parentFragmentManager, "downloadMultipleSheet") } else { downloadViewModel.queueDownloads(downloadList) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt index b2708ebd..558579ab 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt @@ -21,6 +21,7 @@ import androidx.recyclerview.widget.RecyclerView import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.adapter.ConfigureMultipleDownloadsAdapter import com.deniscerri.ytdlnis.database.models.DownloadItem +import com.deniscerri.ytdlnis.database.models.ResultItem import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel @@ -40,7 +41,7 @@ import kotlinx.coroutines.withContext import java.text.SimpleDateFormat import java.util.* -class DownloadMultipleBottomSheetDialog(private var items: MutableList) : BottomSheetDialogFragment(), ConfigureMultipleDownloadsAdapter.OnItemClickListener, View.OnClickListener, +class DownloadMultipleBottomSheetDialog(private var results: List, private var items: MutableList) : BottomSheetDialogFragment(), ConfigureMultipleDownloadsAdapter.OnItemClickListener, View.OnClickListener, ConfigureDownloadBottomSheetDialog.OnDownloadItemUpdateListener { private lateinit var downloadViewModel: DownloadViewModel private lateinit var commandTemplateViewModel: CommandTemplateViewModel @@ -131,82 +132,88 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList - val itemId = m.itemId - if (itemId == R.id.folder) { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) - pathResultLauncher.launch(intent) - } else if (itemId == R.id.preferred_download_type){ - lifecycleScope.launch{ - val bottomSheet = BottomSheetDialog(requireContext()) - bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE) - bottomSheet.setContentView(R.layout.download_type_sheet) + when (m.itemId) { + R.id.folder -> { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) + intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) + pathResultLauncher.launch(intent) + } + R.id.preferred_download_type -> { + lifecycleScope.launch{ + val bottomSheet = BottomSheetDialog(requireContext()) + bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE) + bottomSheet.setContentView(R.layout.download_type_sheet) - // BUTTON ---------------------------------- - val audio = bottomSheet.findViewById(R.id.audio) - val video = bottomSheet.findViewById(R.id.video) - val command = bottomSheet.findViewById(R.id.command) + // BUTTON ---------------------------------- + val audio = bottomSheet.findViewById(R.id.audio) + val video = bottomSheet.findViewById(R.id.video) + val command = bottomSheet.findViewById(R.id.command) - withContext(Dispatchers.IO){ - val nr = commandTemplateViewModel.getTotalNumber() - if(nr == 0){ - command!!.visibility = View.GONE - }else{ - command!!.visibility = View.VISIBLE - } - } - - audio!!.setOnClickListener { - items = downloadViewModel.switchDownloadType(items, DownloadViewModel.Type.audio).toMutableList() - listAdapter.submitList(items.toList()) - listAdapter.notifyDataSetChanged() - preferredDownloadType.setIcon(R.drawable.baseline_audio_file_24) - bottomSheet.cancel() - } - - video!!.setOnClickListener { - items = downloadViewModel.switchDownloadType(items, DownloadViewModel.Type.video).toMutableList() - listAdapter.submitList(items.toList()) - listAdapter.notifyDataSetChanged() - preferredDownloadType.setIcon(R.drawable.baseline_video_file_24) - bottomSheet.cancel() - } - - command!!.setOnClickListener { - lifecycleScope.launch { - items = withContext(Dispatchers.IO){ - downloadViewModel.switchDownloadType(items, DownloadViewModel.Type.command).toMutableList() + withContext(Dispatchers.IO){ + val nr = commandTemplateViewModel.getTotalNumber() + if(nr == 0){ + command!!.visibility = View.GONE + }else{ + command!!.visibility = View.VISIBLE } + } + + audio!!.setOnClickListener { + items = downloadViewModel.switchDownloadType(items, DownloadViewModel.Type.audio).toMutableList() listAdapter.submitList(items.toList()) listAdapter.notifyDataSetChanged() - preferredDownloadType.setIcon(R.drawable.baseline_insert_drive_file_24) + preferredDownloadType.setIcon(R.drawable.baseline_audio_file_24) bottomSheet.cancel() } + + video!!.setOnClickListener { + items = downloadViewModel.switchDownloadType(items, DownloadViewModel.Type.video).toMutableList() + listAdapter.submitList(items.toList()) + listAdapter.notifyDataSetChanged() + preferredDownloadType.setIcon(R.drawable.baseline_video_file_24) + bottomSheet.cancel() + } + + command!!.setOnClickListener { + lifecycleScope.launch { + items = withContext(Dispatchers.IO){ + downloadViewModel.switchDownloadType(items, DownloadViewModel.Type.command).toMutableList() + } + listAdapter.submitList(items.toList()) + listAdapter.notifyDataSetChanged() + preferredDownloadType.setIcon(R.drawable.baseline_insert_drive_file_24) + bottomSheet.cancel() + } + } + + bottomSheet.show() + bottomSheet.window!!.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) } - bottomSheet.show() - bottomSheet.window!!.setLayout( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT - ) } + R.id.format -> { + if (results.first()!!.formats.isEmpty()){ - } else if (itemId == R.id.format){ -// val formatListCollection = items.map { it.format } -// val commonFormats = getCommonFormats(formatListCollection) -// -// val listener = object : OnFormatClickListener { -// override fun onFormatClick(allFormats: List, item: Format) { -// -// } -// } -// if (parentFragmentManager.findFragmentByTag("formatSheet") == null){ -// val bottomSheet = FormatSelectionBottomSheetDialog(null, commonFormats.toList(), listener) -// bottomSheet.show(parentFragmentManager, "formatSheet") -// } + } + // val formatListCollection = items.map { it.format } + // val commonFormats = getCommonFormats(formatListCollection) + // + // val listener = object : OnFormatClickListener { + // override fun onFormatClick(allFormats: List, item: Format) { + // + // } + // } + // if (parentFragmentManager.findFragmentByTag("formatSheet") == null){ + // val bottomSheet = FormatSelectionBottomSheetDialog(null, commonFormats.toList(), listener) + // bottomSheet.show(parentFragmentManager, "formatSheet") + // } + } } true } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt index 0e2fd7b3..aae8d2d9 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt @@ -158,7 +158,7 @@ class SelectPlaylistItemsBottomSheetDialog(private val items: List, downloadItems.add(i) } - val bottomSheet = DownloadMultipleBottomSheetDialog(downloadItems) + val bottomSheet = DownloadMultipleBottomSheetDialog(items, downloadItems) bottomSheet.show(parentFragmentManager, "downloadMultipleSheet") } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/HistoryFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/HistoryFragment.kt index 3970ece8..5312d53c 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/HistoryFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/HistoryFragment.kt @@ -559,6 +559,13 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{ actionMode?.finish() true } + R.id.select_all -> { + historyAdapter?.checkAll(historyList) + selectedObjects?.clear() + historyList?.forEach { selectedObjects?.add(it!!) } + mode?.title = getString(R.string.all_items_selected) + true + } R.id.invert_selected -> { historyAdapter?.invertSelected(historyList) val invertedList = arrayListOf() diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt index 195dc306..25b991d8 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt @@ -10,8 +10,11 @@ import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.database.models.Format import com.deniscerri.ytdlnis.database.models.ResultItem import com.google.gson.Gson +import com.google.gson.JsonObject +import com.google.gson.reflect.TypeToken import com.yausername.youtubedl_android.YoutubeDL import com.yausername.youtubedl_android.YoutubeDLRequest +import kotlinx.serialization.json.Json import org.json.JSONArray import org.json.JSONException import org.json.JSONObject @@ -22,6 +25,7 @@ import java.net.HttpURLConnection import java.net.URL import java.util.* import java.util.regex.Pattern +import kotlin.collections.ArrayList class InfoUtil(private val context: Context) { private var items: ArrayList @@ -498,6 +502,56 @@ class InfoUtil(private val context: Context) { } } + fun getFormatsTest(urls: List, progress: (progress: List) -> Unit){ + init() + val urlsFile = File(context.cacheDir, "urls.txt") + urlsFile.delete() + urlsFile.createNewFile() + urls.forEach { + urlsFile.appendText(it+"\n") + } + try { + val request = YoutubeDLRequest(emptyList()) + request.addOption("--print", "%(formats)s") + request.addOption("-a", urlsFile.absolutePath) + request.addOption("--skip-download") + request.addOption("-R", "1") + request.addOption("--socket-timeout", "5") + val cookiesFile = File(context.cacheDir, "cookies.txt") + if (cookiesFile.exists()){ + request.addOption("--cookies", cookiesFile.absolutePath) + } + + val youtubeDLResponse = YoutubeDL.getInstance().execute(request){ progress, _, line -> + val formats = mutableListOf() + val listOfStrings = JSONArray(line) + for (f in 0 until listOfStrings.length()){ + val format = listOfStrings.get(f) as JSONObject + try{ + if (format.getString("filesize") == "None") continue + }catch (e: Exception) { continue } + val formatProper = Gson().fromJson(format.toString(), Format::class.java) + if (formatProper.filesize > 0){ + if ( !formatProper.format_note.contains("audio only", true)) { + formatProper.format_note = format.getString("format_note") + }else{ + formatProper.format_note = "${format.getString("format_note")} audio" + } + formatProper.container = format.getString("ext") + formats.add(formatProper) + } + } + progress(formats) + } + } catch (e: Exception) { + Looper.prepare().run { + Toast.makeText(context, e.message, Toast.LENGTH_LONG).show() + } + e.printStackTrace() + } + urlsFile.delete() + } + fun getFromYTDL(query: String): ArrayList { init() items = ArrayList() diff --git a/app/src/main/res/drawable/baseline_recommend_24.xml b/app/src/main/res/drawable/baseline_recommend_24.xml new file mode 100644 index 00000000..54728a28 --- /dev/null +++ b/app/src/main/res/drawable/baseline_recommend_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/active_download_card.xml b/app/src/main/res/layout/active_download_card.xml index ab7a52ca..a24d3734 100644 --- a/app/src/main/res/layout/active_download_card.xml +++ b/app/src/main/res/layout/active_download_card.xml @@ -199,12 +199,14 @@ + +