diff --git a/README-sq.md b/README-sq.md
new file mode 100644
index 00000000..a680986a
--- /dev/null
+++ b/README-sq.md
@@ -0,0 +1,133 @@
+
+
+ YTDLnis
+
+
+
+
+
+ YTDLnis është një shkarkues video/audio falas dhe me burim të hapur duke përdorur yt-dlp për Android 6.0 dhe më lart.
+
+
+
+
+[](https://github.com/deniscerri/ytdlnis/releases/latest)
+[](https://android.izzysoft.de/repo/apk/com.deniscerri.ytdl)
+[](https://ytdlnis.en.uptodown.com/android/download)
+
+
+[](https://github.com/deniscerri/ytdlnis/releases)
+[](https://github.com/deniscerri/ytdlnis/releases)
+[](https://hosted.weblate.org/engage/ytdlnis/?utm_source=widget)
+[](https://discord.gg/WW3KYWxAPm)
+[](https://t.me/ytdlnis)
+[](https://t.me/ytdlnisupdates)
+
+
+
+
+
+
+
+## 💡 Veçoritë:
+
+- shkarko skedarë audio/video nga më shumë se 1000 website
+- përpunoni lista
+- modifikoni çdo artikull të listës veç e veç si me një artikull normal shkarkimi.
+- zgjidhni një format të përbashkët për të gjithë artikujt dhe/ose zgjidhni formate të shumta audio në rast se po i shkarkoni si video
+- zgjidhni një lloj shkarkimi për të gjithë artikujt
+- zgjidhni një shabllon të emrit të skedarit për të gjithë artikujt
+- përditëso llojin i shkarkimit në audio/video/komandë pme një klik
+- vendosni shkarkimet në radhë dhe planifikoni ato sipas datës dhe orës
+- gjithashtu mund të planifikoni shumë artikuj në të njëjtën kohë
+- shkarkoni shumë artikuj në të njëjtën kohë
+- përdorni komanda dhe shabllone të personalizuara ose shkoni në modalitetin e plotë yt-dlp me një terminal të integruar
+- mund të ruani dhe riktheni shabllonet, në mënyrë që të mund t'i ndani me miqtë tuaj
+- Mbështetje për BISKOTAT. Hyni me llogaritë tuaja dhe shkarkoni video private/të padisponueshme, zhbllokoni formatet premium etj.
+- prit video bazuar sipas kohës dhe kapitujt e videos (Kjo veçori yt-dlp është eksperimentale në projektin origjinal)
+- ju mund të bëni prerje të pafundme
+- hiqni elementet e SPONSORBLOCK (si pjeset pa muzike) nga artikulli
+- futini ato si kapituj në videon tuaj
+- fut titrat/metadatat/kapitujt etj
+- modifikoni titullin dhe autorin
+- ndani artikullin në skedarë të veçantë në varësi të kapitujve të tij
+- zgjidhni formate të ndryshme shkarkimi
+- shfaq karte direkt nga menyja e shpërndarjes, nuk ka nevojë të hapni aplikacionin
+- mund të krijoni një skedar txt dhe ta plotësoni me linke/playliste/fjale kerkimi të ndara nga një rresht i ri dhe aplikacioni do t'i përpunojë ato
+- kërkoni ose futni një link nga aplikacioni
+- mund të grumbulloni kërkime në mënyrë që t'i përpunoni ato në të njëjtën kohë
+- regjistrimet e shkarkimeve në rast problemesh
+- rishkarkimi i shkarkimeve të anuluara ose të dështuara
+- mund të përdorni gjeste për të rrëshqitur majtas për ta shkarkuar përsëri dhe djathtas për t'i fshirë
+- mund të klikoni gjatë butonin e rishkarkimit në fletën e detajeve për të shfaqur kartën e shkarkimit për më shumë funksionalitet
+- INCOGNITO kur nuk dëshironi të ruani një histori shkarkimi ose regjistra
+- mënyra e shkarkimit të shpejtë
+- shkarkoni menjëherë pa pasur nevojë të prisni që të dhënat të përpunohen. Fikni kartën e poshtme dhe ajo do të fillojë menjëherë
+- hapni / ndani skedarët e shkarkuar menjëherë nga njoftimi i përfunduar
+- shumica e veçorive yt-dlp janë zbatuar, sugjerimet janë të mirëseardhura
+- ndërfaqja e MATERIAL U
+- opsionet ngjyrash
+- rezervoni dhe rivendosni veçoritë e aplikacionit. (Pothuajse gjithçka mund të rezervohet dhe mund te shperndash me shoke)
+- Arkitektura MVVM me WorkManager
+
+## 📲 Fotot
+
+
+

+

+

+

+

+

+

+

+

+

+

+

+

+
+
+## 💬 Kontakt
+
+Bashkohuni me [Kanalin tonë Telegram](https://t.me/ytdlnis) ose [Diskord](https://discord.gg/WW3KYWxAPm) për diskutim, njoftime dhe publikime!
+
+## 🔑 Lidhu me ReVanced
+
+Emri i paketës së aplikacionit është "com.deniscerri.ytdl"
+
+## 📝 Ndihmo për të përkthyer në Weblate
+
+
+
+
+
+
+
+
+
+## 😇 Kontributo
+
+Nëse dëshironi të kontribuoni. Ju lutemi lexoni seksionin [Kontribimi](CONTRIBUTING.MD).
+
+## 📄 Liçensa
+
+[GNU GPL v3.0](https://github.com/deniscerri/ytdlnis/blob/main/LICENSE)
+
+⚠️ Paralajmërim
+
+Përveç kodit burimor të licencuar sipas licencës GPLv3, të gjitha palët e tjera janë të ndaluara të përdorin emrin 'YTDLnis' si një aplikacion shkarkues dhe e njëjta gjë vlen edhe për derivatet e tij. Derivatet përfshijnë por nuk kufizohen në forks dhe ndërtime jozyrtare.
+
+## 🙏 Falenderimet
+
+- [yt-dlp](https://github.com/yt-dlp/yt-dlp) dhe kontribuesit e tij për të bërë të mundur këtë mjet. Pa të ky aplikacion nuk do të ekzistonte.
+- [youtubedl-android](https://github.com/yausername/youtubedl-android) për transferimin e yt-dlp në android.
+- [dvd](https://github.com/yausername/dvd) për të treguar se si të zbatohet youtubedl-android
+- [seal](https://github.com/JunkFood02/Seal) për elementë dhe veçori të caktuara të dizajnit doja të përdorja gjithashtu në këtë aplikacion
+- [decipher3114](https://github.com/decipher3114) për ikonën e aplikacionit
+
+dhe shumë të huaj të tjerë nga interneti.
diff --git a/README.MD b/README.MD
index 2beee643..5b42c327 100644
--- a/README.MD
+++ b/README.MD
@@ -6,6 +6,8 @@
English
|
+
Shqip
+ |
Azərbaycanca
|
Português
diff --git a/app/build.gradle b/app/build.gradle
index f7029470..f9888e51 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -76,6 +76,9 @@ android {
}
}
+ lintOptions{
+ disable 'MissingTranslation'
+ }
android.applicationVariants.configureEach { variant ->
variant.outputs.each { output ->
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7ea3e030..a4b577a0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -84,7 +84,7 @@
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt
index 126d0756..35d934ab 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt
@@ -198,6 +198,12 @@ class MainActivity : BaseActivity() {
}
true
}
+ //settings button
+ (navigationView as NavigationView).menu.getItem(8).setOnMenuItemClickListener {
+ val intent = Intent(context, SettingsActivity::class.java)
+ startActivity(intent)
+ true
+ }
(navigationView as NavigationView).getHeaderView(0).findViewById(R.id.title).text = ThemeUtil.getStyledAppName(this)
}
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 658f9871..e82b5f2a 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
@@ -122,14 +122,14 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
audioFormatIDPreference = sharedPreferences.getString("format_id_audio", "").toString().split(",").filter { it.isNotEmpty() }
val confTmp = Configuration(application.resources.configuration)
- confTmp.locale = Locale(sharedPreferences.getString("app_language", "en")!!)
+ confTmp.setLocale(Locale(sharedPreferences.getString("app_language", "en")!!))
val metrics = DisplayMetrics()
resources = Resources(application.assets, metrics, confTmp)
videoContainer = sharedPreferences.getString("video_format", "Default")
- defaultVideoFormats = getGenericVideoFormats()
- bestVideoFormat = defaultVideoFormats.last()
+ defaultVideoFormats = infoUtil.getGenericVideoFormats(resources)
+ bestVideoFormat = defaultVideoFormats.first()
audioContainer = sharedPreferences.getString("audio_format", "mp3")
bestAudioFormat = if (audioFormatIDPreference.isEmpty()){
@@ -387,10 +387,10 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
return cloneFormat (
try {
try{
- formats.filter { it.format_note.contains("audio", ignoreCase = true)}.sortedBy { it.format_id }
+ formats.filter { it.format_note.contains("audio", ignoreCase = true)}
.firstOrNull { audioFormatIDPreference.indexOfFirst { a -> a.contains(it.format_id) } >= 0 || it.container == audioContainer} ?: throw Exception()
}catch (e: Exception){
- formats.last { it.format_note.contains("audio", ignoreCase = true) }
+ formats.first { it.format_note.contains("audio", ignoreCase = true) }
}
}catch (e: Exception){
bestAudioFormat
@@ -401,18 +401,17 @@ 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 }.sortedByDescending { it.filesize }
+ val theFormats = formats.filter { !it.format_note.contains("audio", true) }.ifEmpty { defaultVideoFormats.sortedByDescending { it.filesize } }
when (videoQualityPreference) {
"worst" -> {
- theFormats.first()
+ theFormats.last()
}
else /*best*/ -> {
val requirements: MutableList<(Format) -> Boolean> = mutableListOf()
requirements.add { it: Format -> formatIDPreference.sorted().contains(it.format_id) }
requirements.add { it: Format -> if (videoContainer == "mp4") it.container.equals("mpeg_4", true) else it.container.equals(videoContainer, true)}
- 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.format_note.contains(videoQualityPreference.split("_")[0].dropLast(1)) }
+ requirements.add { it: Format -> "^(${videoCodec}).+$".toRegex(RegexOption.IGNORE_CASE).matches(it.vcodec)}
theFormats.maxByOrNull { f -> requirements.count{ req -> req(f)} } ?: throw Exception()
}
}
@@ -440,23 +439,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
)
}
- fun getGenericAudioFormats() : MutableList{
- val audioFormats = resources.getStringArray(R.array.audio_formats)
- val formats = mutableListOf()
- val containerPreference = sharedPreferences.getString("audio_format", "")
- audioFormats.forEach { formats.add(Format(it, containerPreference!!,"","", "",0, it)) }
- audioFormatIDPreference.forEach { formats.add(Format(it, containerPreference!!,"","", "",1, it)) }
- return formats
- }
- fun getGenericVideoFormats() : MutableList{
- val videoFormats = resources.getStringArray(R.array.video_formats_values)
- val formats = mutableListOf()
- val containerPreference = sharedPreferences.getString("video_format", "")
- videoFormats.forEach { formats.add(Format(it, containerPreference!!,"Default","", "",0, it.split("_")[0])) }
- formatIDPreference.forEach { formats.add(Format(it, containerPreference!!,"Default","", "",1, it)) }
- return formats
- }
fun getLatestCommandTemplateAsFormat() : Format {
val t = commandTemplateDao.getFirst()
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/BaseActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/BaseActivity.kt
index 52b2c011..1b46367a 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/BaseActivity.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/BaseActivity.kt
@@ -2,11 +2,6 @@ package com.deniscerri.ytdlnis.ui
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowCompat
-import androidx.core.view.WindowInsetsCompat
-import androidx.core.view.updatePadding
-import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.util.ThemeUtil
import com.google.android.material.elevation.SurfaceColors
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 c52b11cf..1c9483ea 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt
@@ -435,7 +435,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
}
@SuppressLint("InflateParams")
- private suspend fun updateSearchViewItems(it: Editable?, linkYouCopied: View?){
+ private suspend fun updateSearchViewItems(searchQuery: Editable?, linkYouCopied: View?){
searchSuggestionsLinearLayout!!.visibility = GONE
searchHistoryLinearLayout!!.visibility = GONE
searchSuggestionsLinearLayout!!.removeAllViews()
@@ -449,16 +449,15 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
searchView!!.editText.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_plus, 0)
}
val suggestions = withContext(Dispatchers.IO){
- if (it!!.isEmpty()) {
- resultViewModel.getSearchHistory().map { it.query }
- }else if (sharedPreferences!!.getBoolean("search_suggestions", false)){
- infoUtil!!.getSearchSuggestions(it.toString())
+ resultViewModel.getSearchHistory().map { it.query }.filter { it.contains(searchQuery!!) } +
+ if (sharedPreferences!!.getBoolean("search_suggestions", false)){
+ infoUtil!!.getSearchSuggestions(searchQuery.toString())
}else{
emptyList()
}
}
- if (it!!.isEmpty()){
+ if (searchQuery!!.isEmpty()){
for (i in suggestions.indices) {
val v = LayoutInflater.from(fragmentContext)
.inflate(R.layout.search_suggestion_item, null)
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt
index f3345bfa..8b18d986 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt
@@ -335,7 +335,6 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
if ((event!!.action == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
- val values = rangeSlider.values
var endTimestamp = (rangeSlider.valueTo.toInt() * timeSeconds) / 100
toTextInput.editText!!.clearFocus()
@@ -361,7 +360,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
rangeSlider.setValues(startValue, endValue)
okBtn.isEnabled = startValue != 0F || endValue != 100F
try {
- player.seekTo(startSeconds.toLong() * 1000)
+ player.seekTo((seconds.toLong() - 4L) * 1000)
player.play()
}catch (ignored: Exception) {}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadAudioFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadAudioFragment.kt
index fa176495..e8a8755d 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadAudioFragment.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadAudioFragment.kt
@@ -38,7 +38,6 @@ import java.io.File
class DownloadAudioFragment(private var resultItem: ResultItem, private var currentDownloadItem: DownloadItem?) : Fragment(), TitleAuthorSync {
- private var _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null
private var activity: Activity? = null
private lateinit var downloadViewModel : DownloadViewModel
@@ -46,6 +45,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
private lateinit var saveDir : TextInputLayout
private lateinit var freeSpace : TextView
private lateinit var infoUtil: InfoUtil
+ private lateinit var genericAudioFormats: MutableList
lateinit var downloadItem : DownloadItem
lateinit var title : TextInputLayout
@@ -55,12 +55,12 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- _binding = FragmentHomeBinding.inflate(inflater, container, false)
fragmentView = inflater.inflate(R.layout.fragment_download_audio, container, false)
activity = getActivity()
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
infoUtil = InfoUtil(requireContext())
+ genericAudioFormats = infoUtil.getGenericAudioFormats(requireContext().resources)
return fragmentView
}
@@ -129,7 +129,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
downloadItem.allFormats.filter { it.format_note.contains("audio", ignoreCase = true) }
.maxByOrNull { it.filesize }!!
}.onFailure {
- downloadItem.format = downloadViewModel.getGenericAudioFormats().last()
+ downloadItem.format = genericAudioFormats.last()
}
}
}
@@ -142,7 +142,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
val containerAutoCompleteTextView =
view.findViewById(R.id.container_textview)
- if (formats.isEmpty()) formats = downloadViewModel.getGenericAudioFormats()
+ if (formats.isEmpty()) formats = genericAudioFormats
val formatCard = view.findViewById(R.id.format_card_constraintLayout)
val chosenFormat = downloadItem.format
@@ -154,16 +154,17 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
lifecycleScope.launch {
withContext(Dispatchers.IO){
resultItem.formats.removeAll(formats.toSet())
- resultItem.formats.addAll(allFormats.first())
+ resultItem.formats.addAll(allFormats.first().filter { !genericAudioFormats.contains(it) })
resultViewModel.update(resultItem)
}
}
- formats = allFormats.first().toMutableList()
+ formats = allFormats.first().filter { !genericAudioFormats.contains(it) }.toMutableList()
+ formats.removeAll(genericAudioFormats)
}
}
formatCard.setOnClickListener{
if (parentFragmentManager.findFragmentByTag("formatSheet") == null){
- val bottomSheet = FormatSelectionBottomSheetDialog(listOf(downloadItem), listOf(formats), listener)
+ val bottomSheet = FormatSelectionBottomSheetDialog(listOf(downloadItem), listOf(formats.ifEmpty { genericAudioFormats }), listener)
bottomSheet.show(parentFragmentManager, "formatSheet")
}
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt
index 94058679..13f77d6b 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt
@@ -42,7 +42,6 @@ import kotlinx.coroutines.withContext
import java.io.File
class DownloadCommandFragment(private val resultItem: ResultItem, private var currentDownloadItem: DownloadItem?) : Fragment() {
- private var _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null
private var activity: Activity? = null
private lateinit var downloadViewModel : DownloadViewModel
@@ -57,7 +56,6 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- _binding = FragmentHomeBinding.inflate(inflater, container, false)
fragmentView = inflater.inflate(R.layout.fragment_download_command, container, false)
activity = getActivity()
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
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 1a948230..0c0b9b42 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
@@ -50,6 +50,7 @@ import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.receiver.ShareActivity
import com.deniscerri.ytdlnis.util.FileUtil
+import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.deniscerri.ytdlnis.util.UiUtil.enableFastScroll
import com.deniscerri.ytdlnis.work.UpdatePlaylistFormatsWorker
@@ -78,6 +79,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList
private lateinit var bottomAppBar: BottomAppBar
private lateinit var filesize : TextView
@@ -90,6 +92,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList listOf>(downloadViewModel.getGenericAudioFormats())
- else -> listOf>(downloadViewModel.getGenericVideoFormats())
+ DownloadViewModel.Type.audio -> listOf>(infoUtil.getGenericAudioFormats(requireContext().resources))
+ else -> listOf>(infoUtil.getGenericVideoFormats(requireContext().resources))
}
}
val bottomSheet = FormatSelectionBottomSheetDialog(items, formats, formatListener)
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadVideoFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadVideoFragment.kt
index 1be349d0..d0119119 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadVideoFragment.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadVideoFragment.kt
@@ -25,7 +25,6 @@ import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
-import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.UiUtil
@@ -39,7 +38,6 @@ import java.io.File
class DownloadVideoFragment(private val resultItem: ResultItem, private var currentDownloadItem: DownloadItem?) : Fragment(), TitleAuthorSync {
- private var _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null
private var activity: Activity? = null
private lateinit var downloadViewModel : DownloadViewModel
@@ -50,6 +48,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
private lateinit var saveDir : TextInputLayout
private lateinit var freeSpace : TextView
private lateinit var infoUtil: InfoUtil
+ private lateinit var genericVideoFormats: MutableList
lateinit var downloadItem: DownloadItem
@@ -58,12 +57,12 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- _binding = FragmentHomeBinding.inflate(inflater, container, false)
fragmentView = inflater.inflate(R.layout.fragment_download_video, container, false)
activity = getActivity()
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
resultViewModel = ViewModelProvider(this@DownloadVideoFragment)[ResultViewModel::class.java]
infoUtil = InfoUtil(requireContext())
+ genericVideoFormats = infoUtil.getGenericVideoFormats(requireContext().resources)
return fragmentView
}
@@ -136,7 +135,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
downloadItem.allFormats.filter { it.vcodec.isNotEmpty() }
.maxByOrNull { it.filesize }!!
}.onFailure {
- downloadItem.format = downloadViewModel.getGenericVideoFormats().last()
+ downloadItem.format = genericVideoFormats.last()
}
}
}
@@ -149,7 +148,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
var containerPreference = sharedPreferences.getString("video_format", "Default")
if (containerPreference == "Default") containerPreference = getString(R.string.defaultValue)
- if (formats.isEmpty()) formats = downloadViewModel.getGenericVideoFormats()
+ if (formats.isEmpty()) formats = genericVideoFormats
val formatCard = view.findViewById(R.id.format_card_constraintLayout)
@@ -158,22 +157,24 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
val listener = object : OnFormatClickListener {
override fun onFormatClick(allFormats: List>, item: List) {
downloadItem.format = item.first().format
- item.first().audioFormats?.map { it.format_id }
- ?.let { downloadItem.videoPreferences.audioFormatIDs.addAll(it) }
+ item.first().audioFormats?.map { it.format_id }?.let {
+ downloadItem.videoPreferences.audioFormatIDs.clear()
+ downloadItem.videoPreferences.audioFormatIDs.addAll(it)
+ }
lifecycleScope.launch {
withContext(Dispatchers.IO){
- resultItem.formats.removeAll(formats.toSet())
- resultItem.formats.addAll(allFormats.first())
+ resultItem.formats.removeAll(formats)
+ resultItem.formats.addAll(allFormats.first().filter { !genericVideoFormats.contains(it) })
resultViewModel.update(resultItem)
}
}
- formats = allFormats.first().toMutableList()
+ formats = allFormats.first().filter { !genericVideoFormats.contains(it) }.toMutableList()
UiUtil.populateFormatCard(requireContext(), formatCard, item.first().format, item.first().audioFormats)
}
}
formatCard.setOnClickListener{
if (parentFragmentManager.findFragmentByTag("formatSheet") == null){
- val bottomSheet = FormatSelectionBottomSheetDialog(listOf(downloadItem), listOf(formats), listener)
+ val bottomSheet = FormatSelectionBottomSheetDialog(listOf(downloadItem), listOf(formats.ifEmpty { genericVideoFormats }), listener)
bottomSheet.show(parentFragmentManager, "formatSheet")
}
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/FormatSelectionBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/FormatSelectionBottomSheetDialog.kt
index a4446f48..77501afb 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/FormatSelectionBottomSheetDialog.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/FormatSelectionBottomSheetDialog.kt
@@ -276,7 +276,7 @@ class FormatSelectionBottomSheetDialog(private val items: List, p
}
}
- for (i in finalFormats.lastIndex downTo 0){
+ for (i in 0.. finalFormats.lastIndex){
val format = finalFormats[i]
val formatItem = LayoutInflater.from(context).inflate(R.layout.format_item, null)
formatItem.tag = "${format.format_id}${format.format_note}"
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt
index 518e1fd2..f5ae52b5 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt
@@ -5,8 +5,6 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
-import android.os.Build.VERSION
-import android.os.Build.VERSION_CODES
import android.os.Bundle
import android.os.PowerManager
import android.provider.Settings
@@ -29,7 +27,6 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
override val title: Int = R.string.general
private var language: ListPreference? = null
- private var language13: Preference? = null
private var theme: ListPreference? = null
private var accent: ListPreference? = null
private var highContrast: SwitchPreferenceCompat? = null
@@ -51,45 +48,28 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
}
language = findPreference("app_language")
- language13 = findPreference("app_language_13")
theme = findPreference("ytdlnis_theme")
accent = findPreference("theme_accent")
highContrast = findPreference("high_contrast")
locale = findPreference("locale")
showTerminalShareIcon = findPreference("show_terminal")
- if(VERSION.SDK_INT < VERSION_CODES.TIRAMISU){
- val values = resources.getStringArray(R.array.language_values)
- val entries = mutableListOf()
- values.forEach {
- entries.add(Locale(it).getDisplayName(Locale(it)))
- }
- language!!.entries = entries.toTypedArray()
+ val values = resources.getStringArray(R.array.language_values)
+ val entries = mutableListOf()
+ values.forEach {
+ entries.add(Locale(it).getDisplayName(Locale(it)))
+ }
+ language!!.entries = entries.toTypedArray()
- if(language!!.value == null) language!!.value = Locale.getDefault().language
- language!!.summary = Locale(language!!.value).getDisplayLanguage(Locale(language!!.value))
+ if(language!!.value == null) language!!.value = Locale.getDefault().language
+ language!!.summary = Locale(language!!.value).getDisplayLanguage(Locale(language!!.value))
- language!!.onPreferenceChangeListener =
- Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
- language!!.summary = Locale(newValue.toString()).getDisplayLanguage(Locale(newValue.toString()))
- AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(newValue.toString()))
- true
- }
-
- language13?.isVisible = false
- }else{
- language?.isVisible = false
- language13?.isVisible = true
- language13?.summary = Locale.getDefault().displayLanguage
-
- language13!!.setOnPreferenceClickListener {
- val intent = Intent(Settings.ACTION_APP_LOCALE_SETTINGS)
- intent.data = Uri.fromParts("package", requireActivity().packageName, null)
- requireActivity().startActivity(intent)
- requireActivity().finishAffinity()
+ language!!.onPreferenceChangeListener =
+ Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
+ language!!.summary = Locale(newValue.toString()).getDisplayLanguage(Locale(newValue.toString()))
+ AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(newValue.toString()))
true
}
- }
theme!!.summary = theme!!.entry
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 8d83519e..53167599 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt
@@ -2,11 +2,13 @@ package com.deniscerri.ytdlnis.util
import android.content.Context
import android.content.SharedPreferences
+import android.content.res.Resources
import android.os.Looper
import android.text.Html
import android.util.Log
import android.util.Patterns
import android.widget.Toast
+import androidx.preference.AndroidResources
import androidx.preference.PreferenceManager
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.ChapterItem
@@ -32,7 +34,6 @@ import java.util.regex.Pattern
class InfoUtil(private val context: Context) {
- private var items: ArrayList
private lateinit var sharedPreferences: SharedPreferences
init {
@@ -43,12 +44,10 @@ class InfoUtil(private val context: Context) {
} catch (e: Exception) {
e.printStackTrace()
}
- items = ArrayList()
}
fun search(query: String): ArrayList {
- items = ArrayList()
return when(sharedPreferences.getString("search_engine", "ytsearch")){
"ytsearch" -> try{
searchFromPiped(query)
@@ -68,6 +67,7 @@ class InfoUtil(private val context: Context) {
@Throws(JSONException::class)
fun searchFromPiped(query: String): ArrayList {
+ val items = arrayListOf()
val data = genericRequest("$pipedURL/search?q=$query&filter=videos®ion=${countryCODE}")
val dataArray = data.getJSONArray("items")
if (dataArray.length() == 0) return getFromYTDL(query)
@@ -86,6 +86,7 @@ class InfoUtil(private val context: Context) {
@Throws(JSONException::class)
fun searchFromPipedMusic(query: String): ArrayList {
+ val items = arrayListOf()
val data = genericRequest("$pipedURL/search?q=$query=&filter=music_songs®ion=${countryCODE}")
val dataArray = data.getJSONArray("items")
if (dataArray.length() == 0) return getFromYTDL(query)
@@ -105,7 +106,7 @@ class InfoUtil(private val context: Context) {
@Throws(JSONException::class)
fun getPlaylist(id: String, nextPageToken: String): PlaylistTuple {
try{
- items = ArrayList()
+ val items = arrayListOf()
// -------------- PIPED API FUNCTION -------------------
var url = ""
url = if (nextPageToken.isBlank()) "$pipedURL/playlists/$id"
@@ -226,7 +227,6 @@ class InfoUtil(private val context: Context) {
}
}
- formats.sortBy { it.filesize }
formats.groupBy { it.format_id }.forEach {
if (it.value.count() > 1) {
it.value.filter { f-> !f.format_note.contains("original", true) }.forEachIndexed { index, format -> format.format_id = format.format_id.split("-")[0] + "-${index}" }
@@ -234,6 +234,7 @@ class InfoUtil(private val context: Context) {
engDefault?.format_id = (engDefault?.format_id?.split("-")?.get(0) ?: "") + "-${it.value.size-1}"
}
}
+ formats.sortByDescending { it.filesize }
}
val chapters = ArrayList()
@@ -350,7 +351,6 @@ class InfoUtil(private val context: Context) {
@Throws(JSONException::class)
fun getTrending(): ArrayList {
- items = ArrayList()
if (sharedPreferences.getString("api_key", "")!!.isNotBlank()){
return getTrendingFromYoutubeAPI()
}
@@ -359,8 +359,8 @@ class InfoUtil(private val context: Context) {
@Throws(JSONException::class)
fun getTrendingFromYoutubeAPI(): ArrayList {
+ val items = arrayListOf()
val key = sharedPreferences.getString("api_key", "")!!
-
val url = "https://www.googleapis.com/youtube/v3/videos?part=snippet&chart=mostPopular&videoCategoryId=10®ionCode=$countryCODE&maxResults=25&key=$key"
//short data
val res = genericRequest(url)
@@ -389,6 +389,7 @@ class InfoUtil(private val context: Context) {
}
private fun getTrendingFromPiped(): ArrayList {
+ val items = arrayListOf()
val url = "$pipedURL/trending?region=$countryCODE"
val res = genericArrayRequest(url)
try {
@@ -547,7 +548,7 @@ class InfoUtil(private val context: Context) {
}
fun getFromYTDL(query: String): ArrayList {
- items = ArrayList()
+ val items = arrayListOf()
val searchEngine = sharedPreferences.getString("search_engine", "ytsearch")
try {
val request : YoutubeDLRequest
@@ -583,12 +584,12 @@ class InfoUtil(private val context: Context) {
}
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
- val results: Array = try {
+ val results: List = try {
val lineSeparator = System.getProperty("line.separator")
- youtubeDLResponse.out.split(lineSeparator!!).toTypedArray()
+ youtubeDLResponse.out.split(lineSeparator!!)
} catch (e: Exception) {
- arrayOf(youtubeDLResponse.out)
- }
+ listOf(youtubeDLResponse.out)
+ }.filter { it.isNotBlank() }
for (result in results) {
if (result.isNullOrBlank()) continue
val jsonObject = JSONObject(result)
@@ -690,7 +691,7 @@ class InfoUtil(private val context: Context) {
val formats = arrayListOf()
if (formatsInJSON != null) {
- for (f in 0 until formatsInJSON.length()){
+ for (f in formatsInJSON.length() - 1 downTo 0){
val format = formatsInJSON.getJSONObject(f)
if (format.has("filesize")){
if (format.get("filesize") == "None"){
@@ -987,8 +988,9 @@ class InfoUtil(private val context: Context) {
val limitRate = sharedPreferences.getString("limit_rate", "")
if (limitRate != "") request.addOption("-r", limitRate!!)
- request.addOption("--trim-filenames", 120)
if(downloadItem.type != DownloadViewModel.Type.command){
+ request.addOption("--trim-filenames", 120)
+
if (downloadItem.SaveThumb) {
request.addOption("--write-thumbnail")
request.addOption("--convert-thumbnails", "jpg")
@@ -1024,6 +1026,7 @@ class InfoUtil(private val context: Context) {
request.addCommands(listOf("--replace-in-metadata", "title", ".+", downloadItem.title))
}
if (downloadItem.author.isNotBlank()){
+ request.addOption("--parse-metadata", "%(artist,uploader,creator,channel|null)s:%(uploader)s")
request.addCommands(listOf("--replace-in-metadata", "uploader", ".+", downloadItem.author))
request.addCommands(listOf("--replace-in-metadata","uploader"," - Topic$",""))
}
@@ -1078,7 +1081,7 @@ class InfoUtil(private val context: Context) {
}
}
-
+ downloadItem.customFileNameTemplate = downloadItem.customFileNameTemplate.replace("%(uploader)s", "%(uploader,channel)s")
}
if (sharedPreferences.getBoolean("restrict_filenames", true)) {
@@ -1166,10 +1169,6 @@ class InfoUtil(private val context: Context) {
DownloadViewModel.Type.video -> {
val supportedContainers = context.resources.getStringArray(R.array.video_containers)
- if (!sharedPreferences.getBoolean("embed_metadata", true)){
- request.addOption("--no-embed-metadata")
- }
-
if (downloadItem.videoPreferences.addChapters) {
if (sharedPreferences.getBoolean("use_sponsorblock", true)){
request.addOption("--sponsorblock-mark", "all")
@@ -1200,100 +1199,102 @@ class InfoUtil(private val context: Context) {
}
//format logic
-
- val defaultFormats = context.resources.getStringArray(R.array.video_formats_values)
- var usingGenericFormat = false
-
var videof = downloadItem.format.format_id
- if (videof == context.resources.getString(R.string.best_quality) || videof == "best") {
- videof = "bestvideo"
- usingGenericFormat = true
- }else if (videof == context.resources.getString(R.string.worst_quality) || videof == "worst") {
- videof = "worst"
- }else if (defaultFormats.contains(videof)) {
- videof = "bestvideo[height<="+videof.split("_")[0].dropLast(1)+"]"
- }
-
- val preferredFormatIDs = sharedPreferences.getString("format_id", "").toString()
- .split(",")
- .filter { it.isNotEmpty() }
- .ifEmpty { listOf(videof) }
-
- var audiof = "bestaudio"
+ var audiof = "ba"
if (downloadItem.videoPreferences.audioFormatIDs.isNotEmpty()){
audiof = downloadItem.videoPreferences.audioFormatIDs.joinToString("+")
}
if (downloadItem.videoPreferences.removeAudio) audiof = ""
- val preferredAudioFormatIDs = sharedPreferences.getString("format_id_audio", "")
- .toString()
- .split(",")
- .filter { it.isNotEmpty() }
- .ifEmpty { listOf(audiof) }
-
- val preferredVideoFormats = if (usingGenericFormat) preferredFormatIDs else listOf(videof)
- val preferredAudioFormats = if (usingGenericFormat && downloadItem.videoPreferences.audioFormatIDs.isEmpty()) {
- preferredAudioFormatIDs
- } else listOf(audiof)
-
- if (preferredAudioFormats.any{it.contains("+")}){
- request.addOption("--audio-multistreams")
- }
-
- val preferredCodec = sharedPreferences.getString("video_codec", "")
- val extPref = if (cont.isNotBlank()) "[ext=$cont]" else ""
- val vCodecPref = if (preferredCodec!!.isNotBlank()) "[vcodec^=$preferredCodec]" else ""
-
+ val defaultFormats = context.resources.getStringArray(R.array.video_formats_values)
+ val usingGenericFormat = defaultFormats.contains(videof) || downloadItem.allFormats.isEmpty() || downloadItem.allFormats == getGenericVideoFormats(context.resources)
val f = StringBuilder()
- //build format with extension and vcodec
- preferredVideoFormats.forEach { v ->
- preferredAudioFormats.forEach { a ->
- val aa = if (a.isNotBlank()) "+$a" else ""
- f.append("$v$extPref$vCodecPref$aa/")
- }
- }
+ if(!usingGenericFormat){
+ val aa = if (audiof.isNotBlank()) "+$audiof" else ""
+ f.append("$videof$aa/$videof/best")
- //build format with vcodec
- if (extPref.isNotBlank()){
- preferredVideoFormats.forEach { v ->
+ if (audiof.contains("+")){
+ request.addOption("--audio-multistreams")
+ }
+ }else{
+ if (videof == context.resources.getString(R.string.best_quality) || videof == "best") {
+ videof = "bv"
+ }else if (videof == context.resources.getString(R.string.worst_quality) || videof == "worst") {
+ videof = "worst"
+ }else if (defaultFormats.contains(videof)) {
+ videof = "bv[height<="+videof.split("_")[0].dropLast(1)+"]"
+ }
+
+ val preferredFormatIDs = sharedPreferences.getString("format_id", "").toString()
+ .split(",")
+ .filter { it.isNotEmpty() }
+ .ifEmpty { listOf(videof) }.toMutableList()
+ if (!preferredFormatIDs.contains(videof)){
+ preferredFormatIDs.add(0, videof)
+ }
+
+ val preferredAudioFormatIDs = sharedPreferences.getString("format_id_audio", "")
+ .toString()
+ .split(",")
+ .filter { it.isNotEmpty() }
+ .ifEmpty { listOf(audiof) }
+
+ val preferredAudioFormats = if (downloadItem.videoPreferences.audioFormatIDs.isEmpty()) {
+ preferredAudioFormatIDs
+ } else listOf(audiof)
+
+ if (preferredAudioFormats.any{it.contains("+")}){
+ request.addOption("--audio-multistreams")
+ }
+
+ val preferredCodec = sharedPreferences.getString("video_codec", "")
+ val extPref = if (cont.isNotBlank()) "[ext=$cont]" else ""
+ val vCodecPref = if (preferredCodec!!.isNotBlank()) "[vcodec~='^($preferredCodec)']" else ""
+
+
+ preferredFormatIDs.forEach { v ->
+ //build format with extension and vcodec
preferredAudioFormats.forEach { a ->
val aa = if (a.isNotBlank()) "+$a" else ""
- f.append("$videof$vCodecPref$aa/")
+ f.append("$v$extPref$vCodecPref$aa/")
}
- }
- }
- if (vCodecPref.isNotBlank()){
- preferredVideoFormats.forEach { v ->
//build format with vcodec
- preferredAudioFormats.forEach {a ->
- val aa = if (a.isNotBlank()) "+$a" else ""
- f.append("$v$aa/")
+ if (extPref.isNotBlank()){
+ preferredAudioFormats.forEach { a ->
+ val aa = if (a.isNotBlank()) "+$a" else ""
+ f.append("$v$vCodecPref$aa/")
+ }
}
- }
- }
- if (!downloadItem.videoPreferences.removeAudio){
- //build format with best audio
- preferredVideoFormats.forEach { v ->
- if(!f.contains("$v+bestaudio/")){
- f.append("$v+bestaudio/")
+ //build format with audio
+ if (vCodecPref.isNotBlank()){
+ preferredAudioFormats.forEach {a ->
+ val aa = if (a.isNotBlank()) "+$a" else ""
+ f.append("$v$aa/")
+ }
+ }
+
+ if (!downloadItem.videoPreferences.removeAudio){
+ //build format with best audio
+ if(!f.contains("$v+ba/")){
+ f.append("$v+ba/")
+ }
+
+ //build formats with standalone video
+ if(!f.contains("/$v/")){
+ f.append("$v/")
+ }
}
}
- //build formats with standalone video
- preferredVideoFormats.forEach { v ->
- if(!f.contains("/$v/")){
- f.append("$v/")
- }
+ if(!f.endsWith("best/")){
+ //last fallback
+ f.append("best")
}
}
- if(!f.endsWith("best/")){
- //last fallback
- f.append("best")
- }
request.addOption("-f", f.toString().replace("/$".toRegex(), ""))
@@ -1302,8 +1303,10 @@ class InfoUtil(private val context: Context) {
request.addOption("--write-subs")
request.addOption("--write-auto-subs")
- request.addOption("--sub-format", "${subFormat}/best")
- request.addOption("--convert-subtitles", subFormat ?: "srt")
+ if(subFormat!!.isNotBlank()){
+ request.addOption("--sub-format", "${subFormat}/best")
+ request.addOption("--convert-subtitles", subFormat ?: "srt")
+ }
if (!downloadItem.videoPreferences.embedSubs) {
request.addOption("--sub-langs", downloadItem.videoPreferences.subsLanguages.ifEmpty { "en.*,.*-orig" })
}
@@ -1368,6 +1371,27 @@ class InfoUtil(private val context: Context) {
return final
}
+ fun getGenericAudioFormats(resources: Resources) : MutableList{
+ val audioFormatIDPreference = sharedPreferences.getString("format_id_audio", "").toString().split(",").filter { it.isNotEmpty() }
+ val audioFormats = resources.getStringArray(R.array.audio_formats)
+ val formats = mutableListOf()
+ val containerPreference = sharedPreferences.getString("audio_format", "")
+ audioFormats.reversed().forEach { formats.add(Format(it, containerPreference!!,"","", "",0, it)) }
+ audioFormatIDPreference.forEach { formats.add(Format(it, containerPreference!!,"","", "",1, it)) }
+ return formats
+ }
+
+ fun getGenericVideoFormats(resources: Resources) : MutableList{
+ val formatIDPreference = sharedPreferences.getString("format_id", "").toString().split(",").filter { it.isNotEmpty() }
+
+ val videoFormats = resources.getStringArray(R.array.video_formats_values)
+ val formats = mutableListOf()
+ val containerPreference = sharedPreferences.getString("video_format", "")
+ videoFormats.reversed().forEach { formats.add(Format(it, containerPreference!!,"Default","", "",0, it.split("_")[0])) }
+ formatIDPreference.forEach { formats.add(Format(it, containerPreference!!,"Default","", "",1, it)) }
+ return formats
+ }
+
private val pipedURL = sharedPreferences.getString("piped_instance", defaultPipedURL)?.ifEmpty { defaultPipedURL }?.removeSuffix("/")
class PlaylistTuple internal constructor(
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt
index 44d50a81..2876a6ab 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/util/NotificationUtil.kt
@@ -34,11 +34,18 @@ class NotificationUtil(var context: Context) {
NotificationManager::class.java
)
- //gui downloads
- var name: CharSequence = context.getString(R.string.download_notification_channel_name)
- var description = context.getString(R.string.download_notification_channel_description)
+ //downloading worker notification
+ var name: CharSequence = context.getString(R.string.downloading)
+ var description = "WorkManager Default Notification"
val importance = NotificationManager.IMPORTANCE_LOW
- var channel = NotificationChannel(DOWNLOAD_SERVICE_CHANNEL_ID, name, importance)
+ var channel = NotificationChannel(DOWNLOAD_WORKER_CHANNEL_ID, name, importance)
+ channel.description = description
+ notificationManager.createNotificationChannel(channel)
+
+ //gui downloads
+ name = context.getString(R.string.download_notification_channel_name)
+ description = context.getString(R.string.download_notification_channel_description)
+ channel = NotificationChannel(DOWNLOAD_SERVICE_CHANNEL_ID, name, importance)
channel.description = description
notificationManager.createNotificationChannel(channel)
@@ -77,7 +84,7 @@ class NotificationUtil(var context: Context) {
}
fun createDefaultWorkerNotification() : Notification {
- val notificationBuilder = getBuilder(DOWNLOAD_SERVICE_CHANNEL_ID)
+ val notificationBuilder = getBuilder(DOWNLOAD_WORKER_CHANNEL_ID)
return notificationBuilder
.setContentTitle(context.getString(R.string.downloading))
@@ -480,6 +487,7 @@ class NotificationUtil(var context: Context) {
const val FORMAT_UPDATING_FINISHED_NOTIFICATION_ID = 7
const val DOWNLOAD_MISC_CHANNEL_ID = "4"
const val DOWNLOAD_MISC_NOTIFICATION_ID = 4
+ const val DOWNLOAD_WORKER_CHANNEL_ID = "5"
private const val PROGRESS_MAX = 100
private const val PROGRESS_CURR = 0
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/UpdateUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/UpdateUtil.kt
index ecf6f52e..19e87b2c 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/util/UpdateUtil.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/util/UpdateUtil.kt
@@ -57,16 +57,13 @@ class UpdateUtil(var context: Context) {
v = res.first { !it.tag_name.contains("beta", true) }
}
- val current = BuildConfig.VERSION_NAME.replace("-beta", "").replace(".", "").toInt()
- val incoming = v.tag_name.removePrefix("v").replace("-beta", "").replace(".", "").toInt()
+ val current = BuildConfig.VERSION_NAME.replace("-beta", "").replace(".", "").padEnd(10,'0').toInt()
+ val incoming = v.tag_name.removePrefix("v").replace("-beta", "").replace(".", "").padEnd(10,'0').toInt()
- Log.e("aa", current.toString())
- Log.e("aa", incoming.toString())
var isInLatest = true
- if ((BuildConfig.VERSION_NAME.contains("beta", true) && !useBeta) ||
- (!BuildConfig.VERSION_NAME.contains("beta", true) && useBeta) ||
- current < incoming ){
+ if ((current < incoming) ||
+ (current > incoming && BuildConfig.VERSION_NAME.contains("beta", true) && !useBeta)){
isInLatest = false
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt b/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt
index e328d647..84a39a53 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt
@@ -1,8 +1,11 @@
package com.deniscerri.ytdlnis.work
import android.content.Context
+import android.content.res.Configuration
+import android.content.res.Resources
import android.os.Handler
import android.os.Looper
+import android.util.DisplayMetrics
import android.util.Log
import android.widget.Toast
import androidx.navigation.NavDeepLinkBuilder
@@ -35,6 +38,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.io.File
+import java.util.Locale
import kotlin.random.Random
@@ -60,6 +64,12 @@ class DownloadWorker(
val currentWork = WorkManager.getInstance(context).getWorkInfosByTag("download").await()
if (currentWork.count{it.state == WorkInfo.State.RUNNING} > 1) return Result.success()
+ val confTmp = Configuration(context.resources.configuration)
+ val currLang = sharedPreferences.getString("app_language", "en")!!.split("-")
+ confTmp.setLocale(if (currLang.size == 1) Locale(currLang[0]) else Locale(currLang[0], currLang[1]))
+ val metrics = DisplayMetrics()
+ val resources = Resources(context.assets, metrics, confTmp)
+
val pendingIntent = NavDeepLinkBuilder(context)
.setGraph(R.navigation.nav_graph)
.setDestination(R.id.downloadQueueMainFragment)
@@ -162,8 +172,10 @@ class DownloadWorker(
.sortedByDescending { it.length() }
.map { it.absolutePath }
.toList()
-
FileUtil.scanMedia(finalPaths, context)
+ if (finalPaths.isEmpty()){
+ finalPaths = listOf(context.getString(R.string.unfound_file))
+ }
}else{
//move file from internal to set download directory
setProgressAsync(workDataOf("progress" to 100, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id))
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index d2e2a5d7..724a05c8 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -48,7 +48,7 @@
- worst
- - 360p
+ - 360p_ytdlnisgeneric
- 480p_ytdlnisgeneric
- 720p_ytdlnisgeneric
- 1080p_ytdlnisgeneric
@@ -766,6 +766,15 @@
+ - @string/defaultValue
+ - srt
+ - ass
+ - lrc
+ - vtt
+
+
+
+
- srt
- ass
- lrc
@@ -794,9 +803,9 @@
- - av0
- - vp
- - avc
- - hev
+ - av[01]
+ - vp[09]
+ - avc|h264
+ - hev|h265
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5db9503c..8eee5618 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -292,7 +292,7 @@
Extra Command
Use Cookies
Embed Metadata
- Embed metadata to the video file. Also embeds chapters/infojson if present
+ Embed and parse metadata to the audio file.
Update Formats in Background
Auto-Update yt-dlp
Use SponsorBlock
diff --git a/app/src/main/res/xml/general_preferences.xml b/app/src/main/res/xml/general_preferences.xml
index d1d181d5..062acb33 100644
--- a/app/src/main/res/xml/general_preferences.xml
+++ b/app/src/main/res/xml/general_preferences.xml
@@ -11,13 +11,6 @@
app:summary="en"
app:title="@string/language" />
-
-
-