diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e1b2cd3a..116c926e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -56,9 +56,7 @@ android:theme="@style/Theme.BottomSheet"> - - diff --git a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt index d7fdcf7a..126d0756 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt @@ -18,6 +18,7 @@ import android.view.View import android.view.WindowInsets import android.widget.CheckBox import android.widget.TextView +import android.widget.Toast import androidx.annotation.RequiresApi import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.app.ActivityCompat @@ -39,7 +40,9 @@ import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel import com.deniscerri.ytdlnis.ui.BaseActivity import com.deniscerri.ytdlnis.ui.HomeFragment +import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog import com.deniscerri.ytdlnis.ui.more.settings.SettingsActivity +import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.ThemeUtil import com.deniscerri.ytdlnis.util.UpdateUtil import com.google.android.material.bottomnavigation.BottomNavigationView @@ -54,8 +57,10 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import java.io.BufferedReader +import java.io.File import java.io.InputStreamReader import java.io.Reader +import java.net.URI import java.nio.charset.Charset import java.nio.charset.StandardCharsets import kotlin.system.exitProcess @@ -332,26 +337,38 @@ class MainActivity : BaseActivity() { }else{ intent.getParcelableExtra(Intent.EXTRA_STREAM) } - val `is` = contentResolver.openInputStream(uri!!) - val textBuilder = StringBuilder() - val reader: Reader = BufferedReader( - InputStreamReader( - `is`, Charset.forName( - StandardCharsets.UTF_8.name() + + if (preferences.getString("preferred_download_type", "video") == "command"){ + val f = File(FileUtil.formatPath(uri?.path ?: "")) + if (!f.exists()){ + Toast.makeText(context, "Couldn't read file", Toast.LENGTH_LONG).show() + return + } + val item = downloadViewModel.createEmptyResultItem(f.absolutePath) + val bottomSheet = DownloadBottomSheetDialog(item, DownloadViewModel.Type.command, null, true) + bottomSheet.show(supportFragmentManager, "downloadSingleSheet") + }else{ + val `is` = contentResolver.openInputStream(uri!!) + val textBuilder = StringBuilder() + val reader: Reader = BufferedReader( + InputStreamReader( + `is`, Charset.forName( + StandardCharsets.UTF_8.name() + ) ) ) - ) - var c: Int - while (reader.read().also { c = it } != -1) { - textBuilder.append(c.toChar()) + var c: Int + while (reader.read().also { c = it } != -1) { + textBuilder.append(c.toChar()) + } + val bundle = Bundle() + bundle.putString("url", textBuilder.toString()) + navController.popBackStack(R.id.homeFragment, true) + navController.navigate( + R.id.homeFragment, + bundle + ) } - val bundle = Bundle() - bundle.putString("url", textBuilder.toString()) - navController.popBackStack(R.id.homeFragment, true) - navController.navigate( - R.id.homeFragment, - bundle - ) } catch (e: Exception) { e.printStackTrace() } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt index 7ef835dc..8dc50782 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt @@ -104,6 +104,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: DownloadViewModel.Type.audio -> type.setIconResource(R.drawable.ic_music) DownloadViewModel.Type.video -> type.setIconResource(R.drawable.ic_video) DownloadViewModel.Type.command -> type.setIconResource(R.drawable.ic_terminal) + else -> {} } val formatDetailsChip = card.findViewById(R.id.format_note) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/DownloadLogsAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/DownloadLogsAdapter.kt index 6f1a6d89..6f5c972e 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/DownloadLogsAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/DownloadLogsAdapter.kt @@ -66,6 +66,7 @@ class DownloadLogsAdapter(onItemClickListener: OnItemClickListener, activity: Ac DownloadViewModel.Type.audio -> downloadTypeIcon.setIconResource(R.drawable.ic_music) DownloadViewModel.Type.video -> downloadTypeIcon.setIconResource(R.drawable.ic_video) DownloadViewModel.Type.command -> downloadTypeIcon.setIconResource(R.drawable.ic_terminal) + else -> {} } val formatNote = card.findViewById(R.id.format_note) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItem.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItem.kt index bc34fd41..4b29f743 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItem.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/models/DownloadItem.kt @@ -9,7 +9,7 @@ import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel data class DownloadItem( @PrimaryKey(autoGenerate = true) var id: Long, - val url: String, + var url: String, var title: String, var author: String, var thumb: String, diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/models/GithubRelease.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/models/GithubRelease.kt index 6095dadc..5b132242 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/models/GithubRelease.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/models/GithubRelease.kt @@ -1,13 +1,20 @@ package com.deniscerri.ytdlnis.database.models +import com.google.gson.annotations.SerializedName + data class GithubRelease( + @SerializedName(value = "tag_name") var tag_name: String, + @SerializedName(value = "body") var body: String, + @SerializedName(value = "assets") var assets: List ) data class GithubReleaseAsset( + @SerializedName(value = "name") var name: String, + @SerializedName(value = "browser_download_url") var browser_download_url: String ) \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt index 61d06925..8deab4ea 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt @@ -85,9 +85,15 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application private val dao: DownloadDao enum class Type { - audio, video, command + auto, audio, video, command } + private val urlsForAudioType = listOf( + "music", + "audio", + "soundcloud" + ) + init { dbManager = DBManager.getInstance(application) dao = dbManager.downloadDao @@ -194,6 +200,13 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application return repository.getItemByID(id) } + private fun getSuitableDownloadType(url: String): Type{ + if (urlsForAudioType.any { url.contains(it) }){ + return Type.audio + } + return Type.video + } + fun createDownloadItemFromResult(resultItem: ResultItem, givenType: Type) : DownloadItem { val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false) val saveSubs = sharedPreferences.getBoolean("write_subtitles", false) @@ -202,6 +215,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false) var type = givenType + if (type == Type.auto){ + type = getSuitableDownloadType(resultItem.url) + } if(type == Type.command && commandTemplateDao.getTotalNumber() == 0) type = Type.video val customFileNameTemplate = when(type) { @@ -320,6 +336,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application Type.audio -> sharedPreferences.getString("music_path", FileUtil.getDefaultAudioPath())!! Type.video -> sharedPreferences.getString("video_path", FileUtil.getDefaultVideoPath())!! Type.command -> sharedPreferences.getString("command_path", FileUtil.getDefaultCommandPath())!! + else -> "" } list.forEach { @@ -329,6 +346,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application Type.audio -> sharedPreferences.getString("music_path", FileUtil.getDefaultAudioPath()) Type.video -> sharedPreferences.getString("video_path", FileUtil.getDefaultVideoPath()) Type.command -> sharedPreferences.getString("command_path", FileUtil.getDefaultCommandPath()) + else -> "" } if (it.downloadPath == currentDownloadPath) it.downloadPath = updatedDownloadPath @@ -359,6 +377,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application Type.audio -> FileUtil.getDefaultAudioPath() Type.video -> FileUtil.getDefaultVideoPath() Type.command -> FileUtil.getDefaultCommandPath() + else -> "" } val sponsorblock = sharedPreferences.getStringSet("sponsorblock_filters", emptySet()) @@ -404,7 +423,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application Type.video -> { return cloneFormat( try { - val theFormats = formats.filter { !it.format_note.contains("audio", true) }.sortedBy { it.format_id }.ifEmpty { defaultVideoFormats } + val theFormats = formats.filter { !it.format_note.contains("audio", true) }.sortedBy { it.format_id }.ifEmpty { defaultVideoFormats }.sortedByDescending { it.filesize } when (videoQualityPreference) { "worst" -> { theFormats.first() @@ -416,7 +435,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application requirements.add { it: Format -> it.format_note.contains(videoQualityPreference.substring(0, videoQualityPreference.length - 1)) } requirements.add { it: Format -> it.vcodec.startsWith(videoCodec!!, true) } - theFormats.reversed().maxByOrNull { f -> requirements.count{ req -> req(f)} } ?: throw Exception() + theFormats.maxByOrNull { f -> requirements.count{ req -> req(f)} } ?: throw Exception() } } }catch (e: Exception){ @@ -468,8 +487,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application fun turnResultItemsToDownloadItems(items: List) : List { val list : MutableList = mutableListOf() - val preferredType = sharedPreferences.getString("preferred_download_type", "video") + var preferredType = sharedPreferences.getString("preferred_download_type", "video") items.forEach { + if (preferredType == Type.auto.toString()) preferredType = getSuitableDownloadType(it!!.url).toString() list.add(createDownloadItemFromResult(it!!, Type.valueOf(preferredType!!))) } return list diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt index 9b0b2e08..e5f234f1 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt @@ -3,6 +3,7 @@ package com.deniscerri.ytdlnis.database.viewmodel import android.app.Application import android.content.SharedPreferences import android.util.Log +import android.util.Patterns import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -111,14 +112,14 @@ class ResultViewModel(application: Application) : AndroidViewModel(application) } private fun getQueryType(inputQuery: String) : String { var type = "Search" - val p = Pattern.compile("(^(https?)://(www.)?(music.)?youtu(.be)?)|(^(https?)://(www.)?piped.video)") + val p = Pattern.compile("(^(https?)://(www.)?youtu(.be)?)|(^(https?)://(www.)?piped.video)") val m = p.matcher(inputQuery) if (m.find()) { type = "YT_Video" - if (inputQuery.contains("playlist?list=") && !inputQuery.contains("music.youtu")) { + if (inputQuery.contains("playlist?list=")) { type = "YT_Playlist" } - } else if (inputQuery.contains("http")) { + } else if (Patterns.WEB_URL.matcher(inputQuery).matches()) { type = "Default" } return type 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 a0239791..cfe0b4fa 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt @@ -159,7 +159,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene homeAdapter!!.submitList(it) resultsList = it if(resultViewModel.repository.itemCount.value > 1 || resultViewModel.repository.itemCount.value == -1){ - if (it.size > 1 && it[0].playlistTitle.isNotEmpty() && it[0].playlistTitle != getString(R.string.trendingPlaylist) && !loadingItems){ + if (it.size > 1 && it[0].playlistTitle.isNotEmpty() && !loadingItems){ downloadAllFabCoordinator!!.visibility = VISIBLE }else{ downloadAllFabCoordinator!!.visibility = GONE @@ -187,7 +187,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene recyclerView?.setPadding(0,0,0,100) shimmerCards!!.stopShimmer() shimmerCards!!.visibility = GONE - if (resultsList!!.size > 1 && resultsList!![0]!!.playlistTitle.isNotEmpty() && resultsList!![0]!!.playlistTitle != getString(R.string.trendingPlaylist)){ + if (resultsList!!.size > 1 && resultsList!![0]!!.playlistTitle.isNotEmpty()){ downloadAllFabCoordinator!!.visibility = VISIBLE }else{ downloadAllFabCoordinator!!.visibility = GONE diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt index ac4fbfd2..f13fe9b1 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt @@ -11,6 +11,7 @@ import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.Toast +import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.RecyclerView @@ -64,7 +65,6 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri super.setupDialog(dialog, style) val view = LayoutInflater.from(context).inflate(R.layout.configure_download_bottom_sheet, null) dialog.setContentView(view) - dialog.setOnShowListener { behavior = BottomSheetBehavior.from(view.parent as View) val displayMetrics = DisplayMetrics() @@ -80,7 +80,7 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri overScrollMode = View.OVER_SCROLL_NEVER } - val fragments = mutableListOf( + val fragments = mutableListOf( DownloadAudioFragment(resultItem, downloadItem), DownloadVideoFragment(resultItem, downloadItem) ) @@ -161,6 +161,9 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri viewPager2.registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { tabLayout.selectTab(tabLayout.getTabAt(position)) + runCatching { + updateTitleAuthorWhenSwitching() + } } }) @@ -168,22 +171,7 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri val ok = view.findViewById