fixed terminal mode somewhat & implemented language preference

pull/44/head
Denis Çerri 3 years ago
parent 7783b2846d
commit 5482105a18
No known key found for this signature in database
GPG Key ID: 95C43D517D830350

@ -320,7 +320,7 @@
<PersistentState>
<option name="values">
<map>
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/text_format/baseline_text_format_24.xml" />
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/terminal/baseline_terminal_24.xml" />
</map>
</option>
</PersistentState>
@ -330,7 +330,7 @@
</option>
<option name="values">
<map>
<entry key="outputName" value="ic_textformat" />
<entry key="outputName" value="ic_terminal" />
<entry key="sourceFile" value="C:\Users\denis\Desktop\adaptiveproduct_youtube_foreground_color_108 (1).svg" />
</map>
</option>

@ -14,8 +14,10 @@
<application
android:name=".App"
android:allowBackup="false"
android:localeConfig="@xml/locales_config"
android:extractNativeLibs="true"
android:icon="@mipmap/ic_launcher"
android:configChanges="layoutDirection|locale"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
@ -27,6 +29,7 @@
tools:ignore="DataExtractionRules">
<activity android:name=".MainActivity"
android:windowSoftInputMode="adjustResize"
android:configChanges="layoutDirection|locale"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -46,6 +49,7 @@
</activity>
<activity android:name=".receiver.ShareActivity"
android:configChanges="layoutDirection|locale"
android:exported="true">
<!-- <intent-filter>-->
@ -62,6 +66,7 @@
</activity>
<activity
android:name=".ui.settings.SettingsActivity"
android:configChanges="layoutDirection|locale"
android:parentActivityName=".MainActivity"
android:exported="true">
<intent-filter>
@ -71,6 +76,7 @@
</activity>
<activity
android:name=".ui.CustomCommandActivity"
android:configChanges="layoutDirection|locale"
android:theme="@style/AppDefaultTheme"
android:parentActivityName=".MainActivity"
android:label="@string/run_command"

@ -2,6 +2,8 @@ package com.deniscerri.ytdlnis
import android.app.Application
import android.widget.Toast
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import androidx.preference.PreferenceManager
import androidx.work.Configuration
import androidx.work.WorkManager
@ -11,9 +13,11 @@ import com.yausername.aria2c.Aria2c
import com.yausername.ffmpeg.FFmpeg
import com.yausername.youtubedl_android.YoutubeDL
import com.yausername.youtubedl_android.YoutubeDLException
import java.util.*
import java.util.concurrent.Executors
class App : Application() {
override fun onCreate() {
super.onCreate()
DynamicColors.applyToActivitiesIfAvailable(this)
@ -40,6 +44,9 @@ class App : Application() {
Toast.makeText(this@App, e.message, Toast.LENGTH_SHORT).show()
e.printStackTrace()
}
val locale = getSharedPreferences("root_preferences", MODE_PRIVATE)
.getString("app_language", Locale.getDefault().language)!!
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(locale))
}
@Throws(YoutubeDLException::class)
private fun initLibraries() {

@ -5,6 +5,7 @@ import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.net.Uri
import android.os.Build
import android.os.Build.VERSION_CODES
@ -15,7 +16,9 @@ import android.view.MenuItem
import android.view.View
import android.view.WindowInsets
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.app.ActivityCompat
import androidx.core.os.LocaleListCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
@ -49,6 +52,7 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityMainBinding.inflate(layoutInflater)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setContentView(binding.root)
context = baseContext
@ -253,6 +257,10 @@ class MainActivity : AppCompatActivity() {
}
dialog.show()
}
override fun onConfigurationChanged(newConfig: Configuration) {
startActivity(Intent(this, MainActivity::class.java))
super.onConfigurationChanged(newConfig)
}
companion object {
private const val TAG = "MainActivity"

@ -103,7 +103,7 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
DownloadViewModel.Type.video -> {
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
}
DownloadViewModel.Type.command -> {
else -> {
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_baseline_keyboard_arrow_right_24)
}
}

@ -38,7 +38,8 @@ class Converters {
return when(string){
"audio" -> DownloadViewModel.Type.audio
"video" -> DownloadViewModel.Type.video
else -> DownloadViewModel.Type.command
"command" -> DownloadViewModel.Type.command
else -> DownloadViewModel.Type.terminal
}
}

@ -52,4 +52,7 @@ interface DownloadDao {
@Query("SELECT * FROM downloads WHERE url=:url AND format=:format AND (status='Error' OR status='Cancelled') LIMIT 1")
fun getUnfinishedByURLAndFormat(url: String, format: String) : DownloadItem
@Query("SELECT * FROM downloads WHERE type='terminal' ORDER BY id DESC LIMIT 1")
fun getTerminalDownload() : DownloadItem
}

@ -64,4 +64,8 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
0L
}
}
fun getTerminalDownload() : Long {
return downloadDao.getTerminalDownload().id
}
}

@ -37,7 +37,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
private var bestVideoFormat : Format
private var bestAudioFormat : Format
enum class Type {
audio, video, command
audio, video, command, terminal
}
init {
@ -92,7 +92,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
val downloadPath = when(type){
Type.audio -> sharedPreferences.getString("music_path", getApplication<App>().resources.getString(R.string.music_path))
Type.video -> sharedPreferences.getString("video_path", getApplication<App>().resources.getString(R.string.video_path))
Type.command -> sharedPreferences.getString("command_path", getApplication<App>().resources.getString(R.string.command_path))
else -> sharedPreferences.getString("command_path", getApplication<App>().resources.getString(R.string.command_path))
}
val audioPreferences = AudioPreferences(embedThumb)
@ -111,18 +111,19 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
}
private fun getFormat(resultItem: ResultItem, type: Type) : Format {
private fun getFormat(resultItem: ResultItem?, type: Type) : Format {
when(type) {
Type.audio -> {
return try {
resultItem.formats.last { it.format_note.contains("audio", ignoreCase = true) }
resultItem!!.formats.last { it.format_note.contains("audio", ignoreCase = true) }
}catch (e: Exception){
bestAudioFormat
}
}
Type.video -> {
return try {
resultItem.formats.last { !it.format_note.contains("audio", ignoreCase = true) }
resultItem!!.formats.last { !it.format_note.contains("audio", ignoreCase = true) }
}catch (e: Exception){
bestVideoFormat
}
@ -203,4 +204,39 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
}
}
fun startTerminalDownload(command: String) = viewModelScope.launch(Dispatchers.IO) {
val downloadPath = sharedPreferences.getString("command_path", getApplication<App>().resources.getString(R.string.command_path))
val downloadItem = DownloadItem(0,
"",
"",
"",
"",
"",
Type.terminal,
Format("", "", 0, command),
downloadPath!!, "", "", "", AudioPreferences(), VideoPreferences(), "", false, DownloadRepository.Status.Processing.toString(), 0
)
downloadItem.status = DownloadRepository.Status.Queued.toString()
Log.e("aaaaaaaa", downloadItem.toString())
val id = repository.insert(downloadItem)
downloadItem.id = id
val workRequest = OneTimeWorkRequestBuilder<DownloadWorker>()
.setInputData(Data.Builder().putLong("id", downloadItem.id).build())
.addTag("terminal")
.build()
val context = getApplication<App>().applicationContext
WorkManager.getInstance(context).beginUniqueWork(
downloadItem.id.toString(),
ExistingWorkPolicy.KEEP,
workRequest
).enqueue()
}
fun getTerminalDownload(): Long {
return repository.getTerminalDownload();
}
}

@ -6,19 +6,34 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.EditText
import android.widget.ScrollView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.work.WorkInfo
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.service.IDownloaderService
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.yausername.youtubedl_android.YoutubeDL
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
class CustomCommandActivity : AppCompatActivity() {
private var topAppBar: MaterialToolbar? = null
private lateinit var downloadViewModel: DownloadViewModel
private lateinit var notificationUtil: NotificationUtil
private lateinit var workManager: WorkManager
private var isDownloadServiceRunning = false
private var output: TextView? = null
private var input: EditText? = null
@ -27,80 +42,6 @@ class CustomCommandActivity : AppCompatActivity() {
private var iDownloaderService: IDownloaderService? = null
private var scrollView: ScrollView? = null
var context: Context? = null
// private val serviceConnection: ServiceConnection = object : ServiceConnection {
// override fun onServiceConnected(className: ComponentName, service: IBinder) {
// downloaderService = (service as LocalBinder).service
// iDownloaderService = service
// isDownloadServiceRunning = true
// try {
// val listeners = ArrayList<IDownloaderListener>()
// listeners.add(listener)
// iDownloaderService!!.addActivity(this@CustomCommandActivity, listeners)
// listener.onDownloadStart(iDownloaderService!!.info)
// } catch (e: Exception) {
// e.printStackTrace()
// }
// }
//
// override fun onServiceDisconnected(componentName: ComponentName) {
// downloaderService = null
// iDownloaderService = null
// isDownloadServiceRunning = false
// }
// }
// var listener: IDownloaderListener = object : IDownloaderListener {
// override fun onDownloadStart(info: DownloadInfo) {
// input!!.isEnabled = false
// output!!.text = ""
// swapFabs()
// }
//
// override fun onDownloadProgress(info: DownloadInfo) {
// val newInfo = info.outputLine
// if (newInfo.contains("[download]")) {
// val temp = output!!.text.toString()
// output!!.text =
// temp.substring(0, temp.lastIndexOf(System.getProperty("line.separator")!!) - 2)
// }
// output!!.append(
// """${info.outputLine}
//"""
// )
// output!!.scrollTo(0, output!!.height)
// scrollView!!.fullScroll(View.FOCUS_DOWN)
// }
//
// @SuppressLint("SetTextI18n")
// override fun onDownloadError(info: DownloadInfo) {
// output!!.append(
// """
//
// ${info.outputLine}
// """.trimIndent()
// )
// scrollView!!.scrollTo(0, scrollView!!.maxScrollAmount)
// input!!.setText("yt-dlp ")
// input!!.isEnabled = true
// swapFabs()
// }
//
// @SuppressLint("SetTextI18n")
// override fun onDownloadEnd(info: DownloadInfo) {
// output!!.append(info.outputLine)
// scrollView!!.scrollTo(0, scrollView!!.maxScrollAmount)
// // MEDIA SCAN
// MediaScannerConnection.scanFile(context, arrayOf("/storage"), null, null)
// input!!.setText("yt-dlp ")
// input!!.isEnabled = true
// swapFabs()
// }
//
// override fun onDownloadCancel(downloadInfo: DownloadInfo) {}
// override fun onDownloadCancelAll(downloadInfo: DownloadInfo) {}
// override fun onDownloadServiceEnd() {
// stopDownloadService()
// }
// }
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -115,19 +56,18 @@ class CustomCommandActivity : AppCompatActivity() {
input!!.requestFocus()
fab = findViewById(R.id.command_fab)
fab!!.setOnClickListener {
if (isStoragePermissionGranted) {
startDownloadService(
input!!.text.toString(),
NotificationUtil.COMMAND_DOWNLOAD_NOTIFICATION_ID
)
}
startDownload(
input!!.text.toString()
)
}
cancelFab = findViewById(R.id.cancel_command_fab)
cancelFab!!.setOnClickListener {
cancelDownloadService()
swapFabs()
cancelDownload()
input!!.isEnabled = true
}
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
notificationUtil = NotificationUtil(this)
workManager = WorkManager.getInstance(this)
handleIntent(intent)
}
@ -147,53 +87,32 @@ class CustomCommandActivity : AppCompatActivity() {
}
}
private fun swapFabs() {
val cancel = cancelFab!!.visibility
val start = fab!!.visibility
cancelFab!!.visibility = start
fab!!.visibility = cancel
}
private fun startDownloadService(command: String?, id: Int) {
private fun startDownload(command: String?) {
if (isDownloadServiceRunning) return
//val serviceIntent = Intent(context, DownloaderService::class.java)
// serviceIntent.putExtra("command", command)
// serviceIntent.putExtra("id", id)
//context!!.applicationContext.bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE)
}
fun stopDownloadService() {
// if (!isDownloadServiceRunning) return
// iDownloaderService!!.removeActivity(this)
// context!!.applicationContext.unbindService(serviceConnection)
// downloaderService!!.stopForeground(true)
// downloaderService!!.stopSelf()
// isDownloadServiceRunning = false
}
downloadViewModel.startTerminalDownload(command!!)
output!!.text = ""
workManager.getWorkInfosByTagLiveData("terminal")
.observe(this){ list ->
list.forEach {
if(it.progress.getString("output") != null){
output?.append("\n" + it.progress.getString("output") + "\n")
output?.scrollTo(0, output!!.height)
scrollView?.fullScroll(View.FOCUS_DOWN)
}
}
}
fun cancelDownloadService() {
if (!isDownloadServiceRunning) return
iDownloaderService!!.cancelDownload(false)
stopDownloadService()
}
private val isStoragePermissionGranted: Boolean
get() = if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
== PackageManager.PERMISSION_GRANTED
) {
true
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
1
)
false
private fun cancelDownload() {
lifecycleScope.launch {
val id = withContext(Dispatchers.IO){ downloadViewModel.getTerminalDownload(); }
YoutubeDL.getInstance().destroyProcessById(id.toString())
WorkManager.getInstance(this@CustomCommandActivity).cancelUniqueWork(id.toString())
notificationUtil.cancelDownloadNotification(id.toInt())
}
}
companion object {
private const val TAG = "CustomCommandActivity"

@ -72,7 +72,7 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
tabLayout.selectTab(tabLayout.getTabAt(1))
viewPager2.setCurrentItem(1, false)
}
Type.command -> {
else -> {
tabLayout.selectTab(tabLayout.getTabAt(2))
viewPager2.setCurrentItem(2, false)
}

@ -73,7 +73,7 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
tabLayout.selectTab(tabLayout.getTabAt(1))
viewPager2.setCurrentItem(1, false)
}
Type.command -> {
else -> {
tabLayout.selectTab(tabLayout.getTabAt(2))
viewPager2.setCurrentItem(2, false)
}

@ -1,12 +1,16 @@
package com.deniscerri.ytdlnis.ui.settings
import android.content.Context
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.view.View
import android.os.LocaleList
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentManager
import com.deniscerri.ytdlnis.R
import com.google.android.material.appbar.MaterialToolbar
import java.util.*
class SettingsActivity : AppCompatActivity() {
private var fm: FragmentManager? = null
@ -23,4 +27,34 @@ class SettingsActivity : AppCompatActivity() {
.replace(R.id.settings_frame_layout, SettingsFragment())
.commit()
}
fun setLocale(l: String){
val locale = Locale(l)
Locale.setDefault(locale)
val config: Configuration = this.resources.configuration
if (Build.VERSION.SDK_INT >= 24){
Locale.setDefault(locale)
config.setLocales(LocaleList(locale))
this.resources.updateConfiguration(config, this.resources.displayMetrics)
onConfigurationChanged(config)
}else{
Locale.setDefault(locale)
config.locale = locale
config.setLayoutDirection(locale)
this.resources.updateConfiguration(config, this.resources.displayMetrics)
onConfigurationChanged(config)
}
restartActivity()
}
private fun restartActivity() {
// val intent = intent
// finish()
// startActivity(Intent(this, MainActivity::class.java))
recreate()
}
}

@ -2,17 +2,23 @@ package com.deniscerri.ytdlnis.ui.settings
import android.app.Activity
import android.content.Intent
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import androidx.preference.*
import com.deniscerri.ytdlnis.BuildConfig
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.UpdateUtil
import java.util.*
class SettingsFragment : PreferenceFragmentCompat() {
private var language: ListPreference? = null
private var musicPath: Preference? = null
private var videoPath: Preference? = null
private var commandPath: Preference? = null
@ -51,6 +57,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
val preferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
val editor = preferences.edit()
language = findPreference("app_language")
musicPath = findPreference("music_path")
videoPath = findPreference("video_path")
commandPath = findPreference("command_path")
@ -76,6 +83,20 @@ class SettingsFragment : PreferenceFragmentCompat() {
updateApp = findPreference("update_app")
version = findPreference("version")
version!!.summary = BuildConfig.VERSION_NAME
val values = resources.getStringArray(R.array.language_values)
if (Build.VERSION.SDK_INT >= 34){
language!!.isVisible = false
}else{
val entries = mutableListOf<String>()
values.forEach {
entries.add(Locale(it).getDisplayName(Locale(it)))
}
language!!.entries = entries.toTypedArray()
}
val lang = if (values.contains(Locale.getDefault().language)) Locale.getDefault().language else "en"
editor.putString("app_language", lang)
if (preferences.getString("music_path", "")!!.isEmpty()) {
editor.putString("music_path", getString(R.string.music_path))
}
@ -111,6 +132,17 @@ class SettingsFragment : PreferenceFragmentCompat() {
val preferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
val editor = preferences.edit()
language!!.summary = Locale(preferences.getString("app_language", "")!!).getDisplayLanguage(Locale(preferences.getString("app_language", "")!!))
language!!.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
editor.putString("app_language", newValue.toString())
language!!.summary = Locale(newValue.toString()).getDisplayLanguage(Locale(newValue.toString()))
editor.apply()
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(newValue.toString()))
(requireActivity() as SettingsActivity).setLocale(newValue.toString())
true
}
musicPath!!.summary = fileUtil?.formatPath(preferences.getString("music_path", "")!!)
musicPath!!.onPreferenceClickListener =
Preference.OnPreferenceClickListener {

@ -67,13 +67,13 @@ class DownloadWorker(
val url = downloadItem.url
val request = YoutubeDLRequest(url)
var request = YoutubeDLRequest(url)
val type = downloadItem.type
val downloadLocation = downloadItem.downloadPath
val tempFolder = StringBuilder(context.cacheDir.absolutePath + """/${downloadItem.title}##${downloadItem.type}""")
var tempFolder = StringBuilder(context.cacheDir.absolutePath + """/${downloadItem.title}##${downloadItem.type}""")
tempFolder.append("##${downloadItem.format.format_id}")
val tempFileDir = File(tempFolder.toString())
var tempFileDir = File(tempFolder.toString())
tempFileDir.delete()
tempFileDir.mkdir()
@ -190,6 +190,32 @@ class DownloadWorker(
}
}
}
DownloadViewModel.Type.terminal -> {
if(downloadItem.format.format_note.startsWith("yt-dlp ")){
downloadItem.format.format_note = downloadItem.format.format_note.substring(6).trim();
}
val commandRegex = "\"([^\"]*)\"|(\\S+)"
request = YoutubeDLRequest(emptyList())
tempFolder = StringBuilder(context.cacheDir.absolutePath + """/${downloadItem.format.format_id}##terminal""")
tempFileDir = File(tempFolder.toString())
tempFileDir.delete()
tempFileDir.mkdir()
val m = Pattern.compile(commandRegex).matcher(downloadItem.format.format_note)
while (m.find()) {
if (m.group(1) != null) {
request.addOption(m.group(1)!!)
} else {
request.addOption(m.group(2)!!)
}
}
request.addOption("-o", tempFileDir.absolutePath + "/${downloadItem.customFileNameTemplate}.%(ext)s")
}
}
runCatching {

@ -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="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM18.92,8h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56 1.84,0.63 3.37,1.91 4.33,3.56zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82c0.43,-1.43 1.08,-2.76 1.91,-3.96zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2 0,0.68 0.06,1.34 0.14,2L4.26,14zM5.08,16h2.95c0.32,1.25 0.78,2.45 1.38,3.56 -1.84,-0.63 -3.37,-1.9 -4.33,-3.56zM8.03,8L5.08,8c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8zM12,19.96c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96h3.82c-0.43,1.43 -1.08,2.76 -1.91,3.96zM14.34,14L9.66,14c-0.09,-0.66 -0.16,-1.32 -0.16,-2 0,-0.68 0.07,-1.35 0.16,-2h4.68c0.09,0.65 0.16,1.32 0.16,2 0,0.68 -0.07,1.34 -0.16,2zM14.59,19.56c0.6,-1.11 1.06,-2.31 1.38,-3.56h2.95c-0.96,1.65 -2.49,2.93 -4.33,3.56zM16.36,14c0.08,-0.66 0.14,-1.32 0.14,-2 0,-0.68 -0.06,-1.34 -0.14,-2h3.38c0.16,0.64 0.26,1.31 0.26,2s-0.1,1.36 -0.26,2h-3.38z"/>
</vector>

@ -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="M20,4H4C2.89,4 2,4.9 2,6v12c0,1.1 0.89,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.11,4 20,4zM20,18H4V8h16V18zM18,17h-6v-2h6V17zM7.5,17l-1.41,-1.41L8.67,13l-2.59,-2.59L7.5,9l4,4L7.5,17z"/>
</vector>

@ -64,8 +64,7 @@
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/custom_command_toolbar"
android:elevation="0dp"
app:layout_scrollFlags="scroll|enterAlways|snap"
app:title="@string/custom_command"
app:title="@string/terminal"
android:layout_width="match_parent"
app:navigationIcon="@drawable/ic_back"
android:layout_height="match_parent"/>

@ -142,4 +142,22 @@
<string name="sponsorblock_fillers">Pjesë Shtesë</string>
<string name="sponsorblock_reminders">Përkujtuesit e Abonimit</string>
<string name="select_sponsorblock_filtering">Zgjidh Filtrimin e SponsorBlock</string>
<string name="save_dir">Direktoria</string>
<string name="new_template">Shabllon i ri</string>
<string name="adjust_templates">Cakto Shabllonët</string>
<string name="edit_selected">Redakto të zgjedhurin</string>
<string name="adjust_video">Modifiko Videon</string>
<string name="schedule">Planifiko</string>
<string name="concurrent_downloads">Shkarkimet e njëkohësishme</string>
<string name="concurrent_downloads_summary">Numri i shkarkimeve qe do ekzekutohen në të njëjtën kohë</string>
<string name="defaultValue">Siç është</string>
<string name="container">Formati</string>
<string name="template">Shablloni</string>
<string name="logs">Shënimet</string>
<string name="commands">Komandat</string>
<string name="date_added">Data e shtuar</string>
<string name="update_ytdl_nightly">Shkarko versionin beta të yt-dlp</string>
<string name="adjust_audio">Modifiko Audion</string>
<string name="file_name_template">Formati i Emrit të Skedarit</string>
<string name="language">Gjuha</string>
</resources>

@ -58,4 +58,16 @@
<item>0.0</item>
<item>100.0</item>
</array>
<string-array name="language_values">
<item>en</item>
<item>de</item>
<item>fr</item>
<item>ja</item>
<item>nb</item>
<item>pl</item>
<item>ru</item>
<item>sq</item>
<item>tr</item>
</string-array>
</resources>

@ -155,7 +155,6 @@
<string name="adjust_templates">Adjust templates</string>
<string name="edit_selected">Edit selected</string>
<string name="adjust_video">Adjust video</string>
<string name="remove_audio">Remove Audio</string>
<string name="schedule">Schedule</string>
<string name="concurrent_downloads">Concurrent Downloads</string>
<string name="concurrent_downloads_summary">Number of downloads executing at the same time</string>
@ -168,4 +167,7 @@
<string name="update_ytdl_nightly">Download Nightly Version of yt-dlp</string>
<string name="adjust_audio">Adjust Audio</string>
<string name="file_name_template">Filename Template</string>
<string name="language">Language</string>
<string name="command_templates">Command Templates</string>
<string name="terminal">Terminal</string>
</resources>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="en"/>
<locale android:name="de"/>
<locale android:name="fr"/>
<locale android:name="ja"/>
<locale android:name="nb-NO"/>
<locale android:name="pl"/>
<locale android:name="ru"/>
<locale android:name="sq-AL"/>
<locale android:name="tr-TR"/>
</locale-config>

@ -17,10 +17,11 @@
android:data="https://github.com/deniscerri/ytdlnis" />
</Preference>
<Preference
app:icon="@drawable/ic_baseline_keyboard_arrow_right_24"
app:icon="@drawable/ic_terminal"
app:key="run_command"
app:title="@string/custom_command">
app:title="@string/terminal">
<intent android:action="ytdlnis.page.CustomCommandActivity" />
</Preference>
@ -32,9 +33,18 @@
<intent android:action="ytdlnis.page.DownloadLogsActivity" />
</Preference>
<Preference
app:icon="@drawable/ic_baseline_keyboard_arrow_right_24"
app:key="command_templates"
app:allowDividerBelow="true"
app:title="@string/command_templates">
<intent android:action="ytdlnis.page.DownloadLogsActivity" />
</Preference>
<Preference
app:icon="@drawable/ic_settings"
app:key="open_settings"
app:allowDividerAbove="true"
app:title="@string/settings">
<intent android:action="ytdlnis.settings.SettingsActivity" />
</Preference>

@ -1,6 +1,14 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ListPreference
android:entries="@array/language_values"
android:entryValues="@array/language_values"
android:icon="@drawable/ic_language"
app:key="app_language"
app:summary="en"
app:title="@string/language" />
<PreferenceCategory android:title="@string/directories">
<Preference
app:icon="@drawable/ic_music_downloaded"

Loading…
Cancel
Save