fixed sponsorblock not restoring properly
hid navigation bar when opening search view and reshowing it when closing
updated download item data after calling ytdlp so that the user doesnt have to wait. Its parallel
added Persian lang in the app
added socks5 proxy support
This commit is contained in:
deniscerri 2023-05-19 22:12:31 +02:00
parent c07ffcfad3
commit 59ca614ffd
No known key found for this signature in database
GPG key ID: 95C43D517D830350
12 changed files with 133 additions and 80 deletions

View file

@ -19,6 +19,7 @@ import kotlinx.coroutines.launch
import java.util.* import java.util.*
import java.util.concurrent.Executors import java.util.concurrent.Executors
class App : Application() { class App : Application() {
override fun onCreate() { override fun onCreate() {
@ -26,7 +27,7 @@ class App : Application() {
instance = this instance = this
createNotificationChannels() createNotificationChannels()
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
setDefaultValues()
applicationScope = CoroutineScope(SupervisorJob()) applicationScope = CoroutineScope(SupervisorJob())
applicationScope.launch((Dispatchers.IO)) { applicationScope.launch((Dispatchers.IO)) {
try { try {
@ -59,6 +60,21 @@ class App : Application() {
Aria2c.getInstance().init(this) Aria2c.getInstance().init(this)
} }
private fun setDefaultValues(){
val SPL = 1
val sp = PreferenceManager.getDefaultSharedPreferences(this)
if (sp.getInt("spl", 0) != SPL) {
PreferenceManager.setDefaultValues(this, R.xml.root_preferences, true)
PreferenceManager.setDefaultValues(this, R.xml.downloading_preferences, true)
PreferenceManager.setDefaultValues(this, R.xml.appearance_preferences, true)
PreferenceManager.setDefaultValues(this, R.xml.processing_preferences, true)
PreferenceManager.setDefaultValues(this, R.xml.folders_preference, true)
PreferenceManager.setDefaultValues(this, R.xml.updating_preferences, true)
sp.edit().putInt("spl", SPL).apply()
}
}
private fun createNotificationChannels() { private fun createNotificationChannels() {
val notificationUtil = NotificationUtil(this) val notificationUtil = NotificationUtil(this)
notificationUtil.createNotificationChannel() notificationUtil.createNotificationChannel()

View file

@ -207,6 +207,14 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
} }
} }
searchView?.addTransitionListener { _, _, newState ->
if (newState == SearchView.TransitionState.SHOWING){
mainActivity?.hideBottomNavigation()
}else if (newState == SearchView.TransitionState.HIDING){
mainActivity?.showBottomNavigation()
}
}
mainActivity?.onBackPressedDispatcher?.addCallback(this) { mainActivity?.onBackPressedDispatcher?.addCallback(this) {
if (searchView?.isShowing == true) { if (searchView?.isShowing == true) {
searchView?.hide() searchView?.hide()

View file

@ -32,6 +32,7 @@ import androidx.core.content.ContextCompat
import androidx.core.view.forEach import androidx.core.view.forEach
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -215,8 +216,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
} }
} }
R.id.download_queue -> { R.id.download_queue -> {
val intent = Intent(context, DownloadQueueMainFragment::class.java) findNavController().navigate(R.id.downloadQueueMainFragment)
startActivity(intent)
} }
R.id.remove_deleted_history -> { R.id.remove_deleted_history -> {
if(allhistoryList!!.isEmpty()){ if(allhistoryList!!.isEmpty()){

View file

@ -4,10 +4,12 @@ import android.app.Activity
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.edit
import androidx.core.os.LocaleListCompat import androidx.core.os.LocaleListCompat
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@ -18,7 +20,6 @@ import androidx.preference.PreferenceManager
import androidx.work.WorkInfo import androidx.work.WorkInfo
import androidx.work.WorkManager import androidx.work.WorkManager
import com.deniscerri.ytdlnis.BuildConfig import com.deniscerri.ytdlnis.BuildConfig
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.CommandTemplate import com.deniscerri.ytdlnis.database.models.CommandTemplate
import com.deniscerri.ytdlnis.database.models.CookieItem import com.deniscerri.ytdlnis.database.models.CookieItem
@ -65,7 +66,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
setPreferencesFromResource(R.xml.root_preferences, rootKey) setPreferencesFromResource(R.xml.root_preferences, rootKey)
val navController = findNavController() val navController = findNavController()
val appearance = findPreference<Preference>("appearance") val appearance = findPreference<Preference>("appearance")
appearance?.summary = "${getString(R.string.language)}, ${getString(R.string.Theme)}, ${getString(R.string.accents)}" appearance?.summary = "${if (Build.VERSION.SDK_INT < 33) getString(R.string.language) + ", " else ""}${getString(R.string.Theme)}, ${getString(R.string.accents)}, ${getString(R.string.preferred_search_engine)}"
appearance?.setOnPreferenceClickListener { appearance?.setOnPreferenceClickListener {
navController.navigate(R.id.action_mainSettingsFragment_to_appearanceSettingsFragment) navController.navigate(R.id.action_mainSettingsFragment_to_appearanceSettingsFragment)
true true
@ -338,34 +339,36 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
//preference restore //preference restore
if(json.has("settings")){ if(json.has("settings")){
val prefs = json.getAsJsonArray("settings") PreferenceManager.getDefaultSharedPreferences(requireContext()).edit(commit = true){
val preferencesKeys = preferences.all.map { it.key } clear()
prefs.forEach { val prefs = json.getAsJsonArray("settings")
val key : String = it.asJsonObject.get("key").toString().replace("\"", "") val preferencesKeys = preferences.all.map { it.key }
if (preferencesKeys.contains(key)){ prefs.forEach {
when(it.asJsonObject.get("type").toString().replace("\"", "")){ val key : String = it.asJsonObject.get("key").toString().replace("\"", "")
"String" -> { if (preferencesKeys.contains(key)){
val value = it.asJsonObject.get("value").toString().replace("\"", "") when(it.asJsonObject.get("type").toString().replace("\"", "")){
editor.putString(key, value) "String" -> {
} val value = it.asJsonObject.get("value").toString().replace("\"", "")
"Boolean" -> { putString(key, value)
val value = it.asJsonObject.get("value").toString().replace("\"", "").toBoolean() }
editor.putBoolean(key, value) "Boolean" -> {
} val value = it.asJsonObject.get("value").toString().replace("\"", "").toBoolean()
"Int" -> { putBoolean(key, value)
val value = it.asJsonObject.get("value").toString().replace("\"", "").toInt() }
editor.putInt(key, value) "Int" -> {
} val value = it.asJsonObject.get("value").toString().replace("\"", "").toInt()
"HashSet" -> { putInt(key, value)
val value = hashSetOf(it.asJsonObject.get("value").toString().replace("(\")|(\\[)|(])".toRegex(), "")) }
editor.putStringSet(key, value) "HashSet" -> {
val value = it.asJsonObject.get("value").toString().replace("(\")|(\\[)|(])|([ \\t])".toRegex(), "").split(",")
putStringSet(key, value.toHashSet())
}
} }
} }
} }
finalMessage.append("${getString(R.string.settings)}: ${prefs.count()}\n")
} }
finalMessage.append("${getString(R.string.settings)}: ${prefs.count()}\n")
} }
editor.commit()
//history restore //history restore
if(json.has("downloads")){ if(json.has("downloads")){
@ -480,14 +483,14 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
builder.setPositiveButton( builder.setPositiveButton(
getString(R.string.restart) getString(R.string.restart)
) { _: DialogInterface?, _: Int -> ) { _: DialogInterface?, _: Int ->
val intent = Intent(context, MainActivity::class.java) val intent: Intent? = requireContext().packageManager
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .getLaunchIntentForPackage(requireContext().packageName)
requireContext().startActivity(intent) intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
startActivity(intent)
if(json.has("settings")){ if(json.has("settings")){
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(preferences.getString("app_language", "en"))) AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(preferences.getString("app_language", "en")))
} }
activity?.finishAffinity() activity?.finishAffinity()
Runtime.getRuntime().exit(0)
} }
// handle the negative button of the alert dialog // handle the negative button of the alert dialog

View file

@ -540,6 +540,11 @@ class InfoUtil(private val context: Context) {
request.addOption("--cookies", cookiesFile.absolutePath) request.addOption("--cookies", cookiesFile.absolutePath)
} }
val proxy = sharedPreferences.getString("proxy", "")
if (proxy!!.isNotBlank()){
request.addOption("--proxy", proxy)
}
YoutubeDL.getInstance().execute(request){ progress, _, line -> YoutubeDL.getInstance().execute(request){ progress, _, line ->
try{ try{
val formats = mutableListOf<Format>() val formats = mutableListOf<Format>()
@ -601,6 +606,11 @@ class InfoUtil(private val context: Context) {
request.addOption("--cookies", cookiesFile.absolutePath) request.addOption("--cookies", cookiesFile.absolutePath)
} }
val proxy = sharedPreferences.getString("proxy", "")
if (proxy!!.isNotBlank()){
request.addOption("--proxy", proxy)
}
val youtubeDLResponse = YoutubeDL.getInstance().execute(request) val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
val results: Array<String?> = try { val results: Array<String?> = try {
val lineSeparator = System.getProperty("line.separator") val lineSeparator = System.getProperty("line.separator")
@ -697,6 +707,11 @@ class InfoUtil(private val context: Context) {
request.addOption("--cookies", cookiesFile.absolutePath) request.addOption("--cookies", cookiesFile.absolutePath)
} }
val proxy = sharedPreferences.getString("proxy", "")
if (proxy!!.isNotBlank()){
request.addOption("--proxy", proxy)
}
val youtubeDLResponse = YoutubeDL.getInstance().execute(request) val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
val jsonObject = JSONObject(youtubeDLResponse.out) val jsonObject = JSONObject(youtubeDLResponse.out)
@ -836,6 +851,11 @@ class InfoUtil(private val context: Context) {
request.addOption("--cookies", cookiesFile.absolutePath) request.addOption("--cookies", cookiesFile.absolutePath)
} }
val proxy = sharedPreferences.getString("proxy", "")
if (proxy!!.isNotBlank()){
request.addOption("--proxy", proxy)
}
val youtubeDLResponse = YoutubeDL.getInstance().execute(request) val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
val results: Array<String?> = try { val results: Array<String?> = try {
val lineSeparator = System.getProperty("line.separator") val lineSeparator = System.getProperty("line.separator")

View file

@ -147,24 +147,6 @@ class NotificationUtil(var context: Context) {
notificationManager.notify(DOWNLOAD_RESUME_NOTIFICATION_ID, notificationBuilder.build()) notificationManager.notify(DOWNLOAD_RESUME_NOTIFICATION_ID, notificationBuilder.build())
} }
fun createUpdatingItemNotification(channel: String){
val notificationBuilder = getBuilder(channel)
notificationBuilder
.setContentTitle(context.getString(R.string.updating_download_data))
.setSmallIcon(android.R.drawable.stat_sys_download)
.setLargeIcon(
BitmapFactory.decodeResource(
context.resources,
android.R.drawable.stat_sys_download
)
)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.clearActions()
notificationManager.notify(DOWNLOAD_UPDATING_NOTIFICATION_ID, notificationBuilder.build())
}
fun createDownloadFinished(title: String?, fun createDownloadFinished(title: String?,
filepath: String?, filepath: String?,
channel: String channel: String
@ -289,7 +271,6 @@ class NotificationUtil(var context: Context) {
const val DOWNLOAD_FINISHED_CHANNEL_ID = "3" const val DOWNLOAD_FINISHED_CHANNEL_ID = "3"
const val DOWNLOAD_FINISHED_NOTIFICATION_ID = 3 const val DOWNLOAD_FINISHED_NOTIFICATION_ID = 3
const val DOWNLOAD_RESUME_NOTIFICATION_ID = 4 const val DOWNLOAD_RESUME_NOTIFICATION_ID = 4
const val DOWNLOAD_UPDATING_NOTIFICATION_ID = 5
private const val PROGRESS_MAX = 100 private const val PROGRESS_MAX = 100
private const val PROGRESS_CURR = 0 private const val PROGRESS_CURR = 0
} }

View file

@ -16,6 +16,8 @@ import androidx.work.workDataOf
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.DBManager import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.dao.DownloadDao
import com.deniscerri.ytdlnis.database.dao.ResultDao
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.HistoryItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository import com.deniscerri.ytdlnis.database.repository.DownloadRepository
@ -25,6 +27,9 @@ import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.NotificationUtil import com.deniscerri.ytdlnis.util.NotificationUtil
import com.yausername.youtubedl_android.YoutubeDL import com.yausername.youtubedl_android.YoutubeDL
import com.yausername.youtubedl_android.YoutubeDLRequest import com.yausername.youtubedl_android.YoutubeDLRequest
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import java.io.File import java.io.File
@ -62,25 +67,9 @@ class DownloadWorker(
repository.setDownloadStatus(downloadItem, DownloadRepository.Status.Active) repository.setDownloadStatus(downloadItem, DownloadRepository.Status.Active)
} }
var wasQuickDownloaded = false CoroutineScope(Dispatchers.IO).launch {
//update item if its incomplete //update item if its incomplete
if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){ updateDownloadItem(downloadItem, infoUtil, dao, resultDao)
notificationUtil.createUpdatingItemNotification(NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID);
runCatching {
setProgressAsync(workDataOf("progress" to 0, "output" to context.getString(R.string.updating_download_data), "id" to downloadItem.id, "log" to false))
val info = infoUtil.getMissingInfo(downloadItem.url)
if (downloadItem.title.isEmpty()) downloadItem.title = info?.title.toString()
if (downloadItem.author.isEmpty()) downloadItem.author = info?.author.toString()
downloadItem.duration = info?.duration.toString()
downloadItem.website = info?.website.toString()
if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info?.thumb.toString()
runBlocking {
wasQuickDownloaded = resultDao.getCountInt() == 0
dao.update(downloadItem)
}
}
notificationUtil.cancelDownloadNotification(NotificationUtil.DOWNLOAD_UPDATING_NOTIFICATION_ID)
} }
val intent = Intent(context, MainActivity::class.java) val intent = Intent(context, MainActivity::class.java)
@ -344,7 +333,7 @@ class DownloadWorker(
NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID
) )
if (wasQuickDownloaded){ if (updateDownloadItem(downloadItem, infoUtil, dao, resultDao)){
runCatching { runCatching {
setProgressAsync(workDataOf("progress" to 100, "output" to "Creating Result Items", "id" to downloadItem.id, "log" to false)) setProgressAsync(workDataOf("progress" to 100, "output" to "Creating Result Items", "id" to downloadItem.id, "log" to false))
runBlocking { runBlocking {
@ -398,10 +387,30 @@ class DownloadWorker(
) )
} }
} }
return Result.success() return Result.success()
} }
private fun updateDownloadItem(downloadItem: DownloadItem, infoUtil: InfoUtil, dao: DownloadDao, resultDao: ResultDao) : Boolean {
var wasQuickDownloaded = false
if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){
runCatching {
setProgressAsync(workDataOf("progress" to 0, "output" to context.getString(R.string.updating_download_data), "id" to downloadItem.id, "log" to false))
val info = infoUtil.getMissingInfo(downloadItem.url)
if (downloadItem.title.isEmpty()) downloadItem.title = info?.title.toString()
if (downloadItem.author.isEmpty()) downloadItem.author = info?.author.toString()
downloadItem.duration = info?.duration.toString()
downloadItem.website = info?.website.toString()
if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info?.thumb.toString()
runBlocking {
wasQuickDownloaded = resultDao.getCountInt() == 0
dao.update(downloadItem)
}
}
}
return wasQuickDownloaded
}
override fun onStopped() { override fun onStopped() {
YoutubeDL.getInstance().destroyProcessById(itemId.toInt().toString()) YoutubeDL.getInstance().destroyProcessById(itemId.toInt().toString())
super.onStopped() super.onStopped()

View file

@ -0,0 +1,5 @@
<vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="?android:colorAccent" android:pathData="M19.5,10c0.17,0 0.33,0.03 0.5,0.05L20,1L1,20h13v-3c0,-0.89 0.39,-1.68 1,-2.23v-0.27c0,-2.48 2.02,-4.5 4.5,-4.5zM22,16v-1.5c0,-1.38 -1.12,-2.5 -2.5,-2.5S17,13.12 17,14.5L17,16c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1zM21,16h-3v-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5L21,16z"/>
</vector>

View file

@ -95,6 +95,7 @@
<item>bn</item> <item>bn</item>
<item>de</item> <item>de</item>
<item>es</item> <item>es</item>
<item>fa</item>
<item>fr</item> <item>fr</item>
<item>in</item> <item>in</item>
<item>it</item> <item>it</item>

View file

@ -50,11 +50,11 @@
<string name="limit_rate_summary">Maximum download rate (in bytes per second), e.g. 50K or 4.2M</string> <string name="limit_rate_summary">Maximum download rate (in bytes per second), e.g. 50K or 4.2M</string>
<string name="aria2_summary">Use aria2c as downloader instead of the default</string> <string name="aria2_summary">Use aria2c as downloader instead of the default</string>
<string name="processing">Processing</string> <string name="processing">Processing</string>
<string name="embed_subs_summary">Adds subtitles in the video</string> <string name="embed_subs_summary">Add subtitles in the video</string>
<string name="embed_thumb">Thumbnail Covers</string> <string name="embed_thumb">Thumbnail Covers</string>
<string name="embed_thumb_summary">Uses the thumbnail as cover art</string> <string name="embed_thumb_summary">Use the thumbnail as cover art</string>
<string name="add_chapters">Chapters in Videos</string> <string name="add_chapters">Chapters in Videos</string>
<string name="add_chapters_summary">Marks YouTube / SponsorBlock segments as chapters for the video</string> <string name="add_chapters_summary">Mark YouTube / SponsorBlock segments as chapters for the video</string>
<string name="save_thumb">Save Thumbnail</string> <string name="save_thumb">Save Thumbnail</string>
<string name="save_thumb_summary">Save the thumbnail in the download folder</string> <string name="save_thumb_summary">Save the thumbnail in the download folder</string>
<string name="audio_format">Audio Format</string> <string name="audio_format">Audio Format</string>
@ -66,13 +66,13 @@
<string name="command_download_notification_channel_name">Command Downloads</string> <string name="command_download_notification_channel_name">Command Downloads</string>
<string name="command_download_notification_channel_description">Notification showing the progress of downloading using a yt-dlp command</string> <string name="command_download_notification_channel_description">Notification showing the progress of downloading using a yt-dlp command</string>
<string name="items_left">item(s) left</string> <string name="items_left">item(s) left</string>
<string name="history_is_empty">History empty.</string> <string name="history_is_empty">History is empty.</string>
<string name="you_are_going_to_delete">Deleting</string> <string name="you_are_going_to_delete">Deleting</string>
<string name="url">URL</string> <string name="url">URL</string>
<string name="link_copied_to_clipboard">Link copied to clipboard</string> <string name="link_copied_to_clipboard">Link copied to clipboard</string>
<string name="api_key">Use API Key</string> <string name="api_key">Use API Key</string>
<string name="api_key_summary">Faster results from YouTube</string> <string name="api_key_summary">Faster results from YouTube</string>
<string name="update_app_summary">Announces new versions of the app when it is opened</string> <string name="update_app_summary">Announce new versions of the app when it is opened</string>
<string name="downloads">Downloads</string> <string name="downloads">Downloads</string>
<string name="remove_deleted">Remove Deleted</string> <string name="remove_deleted">Remove Deleted</string>
<string name="remove_duplicates">Remove Duplicates</string> <string name="remove_duplicates">Remove Duplicates</string>
@ -260,4 +260,6 @@
<string name="backup_created_successfully">Backup file saved in the downloads folder</string> <string name="backup_created_successfully">Backup file saved in the downloads folder</string>
<string name="appearance">Appearance</string> <string name="appearance">Appearance</string>
<string name="backup_restore">Backup And Restore</string> <string name="backup_restore">Backup And Restore</string>
<string name="socks5_proxy_summary">Use the specified HTTP/HTTPS/SOCKS proxy</string>
<string name="socks5_proxy">Socks5 Proxy URL</string>
</resources> </resources>

View file

@ -35,6 +35,13 @@
app:summary="@string/download_over_metered_networks_summary" app:summary="@string/download_over_metered_networks_summary"
app:title="@string/download_over_metered_networks" /> app:title="@string/download_over_metered_networks" />
<EditTextPreference
android:icon="@drawable/baseline_network_locked_24"
app:key="proxy"
app:defaultValue=""
app:summary="@string/socks5_proxy_summary"
app:title="@string/socks5_proxy" />
<ListPreference <ListPreference
android:dependency="download_card" android:dependency="download_card"
android:defaultValue="video" android:defaultValue="video"

View file

@ -6,6 +6,7 @@
<locale android:name="bn"/> <locale android:name="bn"/>
<locale android:name="de"/> <locale android:name="de"/>
<locale android:name="es"/> <locale android:name="es"/>
<locale android:name="fa-IR"/>
<locale android:name="fr"/> <locale android:name="fr"/>
<locale android:name="in"/> <locale android:name="in"/>
<locale android:name="it"/> <locale android:name="it"/>
@ -13,12 +14,12 @@
<locale android:name="lv"/> <locale android:name="lv"/>
<locale android:name="nb-NO"/> <locale android:name="nb-NO"/>
<locale android:name="pl"/> <locale android:name="pl"/>
<locale android:name="pt_BR" /> <locale android:name="pt-BR" />
<locale android:name="ru"/> <locale android:name="ru"/>
<locale android:name="ro_RO"/> <locale android:name="ro-RO"/>
<locale android:name="sq-AL"/> <locale android:name="sq-AL"/>
<locale android:name="tr-TR"/> <locale android:name="tr-TR"/>
<locale android:name="ta_IN"/> <locale android:name="ta-IN"/>
<locale android:name="uk"/> <locale android:name="uk"/>
<locale android:name="vi"/> <locale android:name="vi"/>
<locale android:name="zh-CN"/> <locale android:name="zh-CN"/>