more more fixes lol
fixed Snackbar overlapping with buttons on settings fixed locale not translating right in download card fixed format updating the container when re-selecting it made the video tab disabled when the item only has audio formats made the app fetch streaming url and chapters from the start so it loads faster when trying to cut a video added url in format item
This commit is contained in:
parent
bfdc7df88a
commit
0f6d1fa765
46 changed files with 1056 additions and 459 deletions
448
app/schemas/com.deniscerri.ytdlnis.database.DBManager/6.json
Normal file
448
app/schemas/com.deniscerri.ytdlnis.database.DBManager/6.json
Normal file
|
|
@ -0,0 +1,448 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 6,
|
||||
"identityHash": "d34711f8239a4a966885543cd5454eab",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "results",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `website` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `formats` TEXT NOT NULL, `urls` TEXT NOT NULL DEFAULT '', `chapters` TEXT, `creationTime` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "author",
|
||||
"columnName": "author",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "duration",
|
||||
"columnName": "duration",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "thumb",
|
||||
"columnName": "thumb",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "playlistTitle",
|
||||
"columnName": "playlistTitle",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "formats",
|
||||
"columnName": "formats",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "urls",
|
||||
"columnName": "urls",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "chapters",
|
||||
"columnName": "chapters",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "creationTime",
|
||||
"columnName": "creationTime",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "history",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadId` INTEGER NOT NULL DEFAULT 0)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "author",
|
||||
"columnName": "author",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "duration",
|
||||
"columnName": "duration",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "thumb",
|
||||
"columnName": "thumb",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "time",
|
||||
"columnName": "time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadPath",
|
||||
"columnName": "downloadPath",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "format",
|
||||
"columnName": "format",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadId",
|
||||
"columnName": "downloadId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "downloads",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `format` TEXT NOT NULL, `container` TEXT NOT NULL DEFAULT 'Default', `downloadSections` TEXT NOT NULL DEFAULT '', `allFormats` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `audioPreferences` TEXT NOT NULL, `videoPreferences` TEXT NOT NULL, `customFileNameTemplate` TEXT NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `downloadStartTime` INTEGER NOT NULL DEFAULT 0)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "author",
|
||||
"columnName": "author",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "thumb",
|
||||
"columnName": "thumb",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "duration",
|
||||
"columnName": "duration",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "format",
|
||||
"columnName": "format",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "container",
|
||||
"columnName": "container",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "'Default'"
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadSections",
|
||||
"columnName": "downloadSections",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "''"
|
||||
},
|
||||
{
|
||||
"fieldPath": "allFormats",
|
||||
"columnName": "allFormats",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadPath",
|
||||
"columnName": "downloadPath",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadSize",
|
||||
"columnName": "downloadSize",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "playlistTitle",
|
||||
"columnName": "playlistTitle",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "audioPreferences",
|
||||
"columnName": "audioPreferences",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "videoPreferences",
|
||||
"columnName": "videoPreferences",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "customFileNameTemplate",
|
||||
"columnName": "customFileNameTemplate",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "SaveThumb",
|
||||
"columnName": "SaveThumb",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "status",
|
||||
"columnName": "status",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "'Queued'"
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadStartTime",
|
||||
"columnName": "downloadStartTime",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "commandTemplates",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "searchHistory",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `query` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "query",
|
||||
"columnName": "query",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "templateShortcuts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `content` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "cookies",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `content` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd34711f8239a4a966885543cd5454eab')"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
|||
import com.deniscerri.ytdlnis.ui.BaseActivity
|
||||
import com.deniscerri.ytdlnis.ui.HomeFragment
|
||||
import com.deniscerri.ytdlnis.ui.more.settings.SettingsActivity
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
|
|
@ -67,7 +68,6 @@ class MainActivity : BaseActivity() {
|
|||
private lateinit var navHostFragment : NavHostFragment
|
||||
private lateinit var navController : NavController
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeUtil.updateTheme(this)
|
||||
|
|
@ -338,9 +338,9 @@ class MainActivity : BaseActivity() {
|
|||
|
||||
|
||||
private fun createDefaultFolders(){
|
||||
val audio = File(getString(R.string.music_path))
|
||||
val video = File(getString(R.string.video_path))
|
||||
val command = File(getString(R.string.command_path))
|
||||
val audio = File(FileUtil.getDefautAudioPath())
|
||||
val video = File(FileUtil.getDefautVideoPath())
|
||||
val command = File(FileUtil.getDefaultCommandPath())
|
||||
|
||||
audio.mkdirs()
|
||||
video.mkdirs()
|
||||
|
|
|
|||
|
|
@ -28,12 +28,10 @@ import com.squareup.picasso.Picasso
|
|||
class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ActiveDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||
private val onItemClickListener: OnItemClickListener
|
||||
private val activity: Activity
|
||||
private val fileUtil: FileUtil
|
||||
|
||||
init {
|
||||
this.onItemClickListener = onItemClickListener
|
||||
this.activity = activity
|
||||
fileUtil = FileUtil()
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||
|
|
@ -113,7 +111,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
}
|
||||
|
||||
val fileSize = card.findViewById<Chip>(R.id.file_size)
|
||||
fileSize.text = fileUtil.convertFileSize(item.format.filesize)
|
||||
fileSize.text = FileUtil.convertFileSize(item.format.filesize)
|
||||
if (fileSize.text == "?") fileSize.visibility = View.GONE
|
||||
|
||||
if (fileSize.visibility == View.VISIBLE && codec.visibility == View.GONE){
|
||||
|
|
|
|||
|
|
@ -24,12 +24,10 @@ import java.util.Locale
|
|||
class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ConfigureMultipleDownloadsAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||
private val onItemClickListener: OnItemClickListener
|
||||
private val activity: Activity
|
||||
private var fileUtil: FileUtil
|
||||
|
||||
init {
|
||||
this.onItemClickListener = onItemClickListener
|
||||
this.activity = activity
|
||||
fileUtil = FileUtil()
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||
|
|
@ -96,7 +94,7 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
|||
}
|
||||
|
||||
val fileSize = card.findViewById<TextView>(R.id.file_size)
|
||||
val fileSizeReadable = fileUtil.convertFileSize(item.format.filesize)
|
||||
val fileSizeReadable = FileUtil.convertFileSize(item.format.filesize)
|
||||
if (fileSizeReadable == "?") fileSize.visibility = View.GONE
|
||||
else {
|
||||
fileSize.text = fileSizeReadable
|
||||
|
|
|
|||
|
|
@ -24,14 +24,12 @@ import com.squareup.picasso.Picasso
|
|||
class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, GenericDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||
private val onItemClickListener: OnItemClickListener
|
||||
private val activity: Activity
|
||||
private var fileUtil: FileUtil
|
||||
private val checkedItems: ArrayList<Long>
|
||||
|
||||
init {
|
||||
checkedItems = ArrayList()
|
||||
this.onItemClickListener = onItemClickListener
|
||||
this.activity = activity
|
||||
fileUtil = FileUtil()
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||
|
|
@ -94,7 +92,7 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
}
|
||||
|
||||
val fileSize = card.findViewById<TextView>(R.id.file_size)
|
||||
val fileSizeReadable = fileUtil.convertFileSize(item.format.filesize)
|
||||
val fileSizeReadable = FileUtil.convertFileSize(item.format.filesize)
|
||||
if (fileSizeReadable == "?") fileSize.visibility = View.GONE
|
||||
else fileSize.text = fileSizeReadable
|
||||
|
||||
|
|
@ -107,7 +105,7 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
DownloadRepository.Status.Queued.toString() -> actionButton.setIconResource(R.drawable.ic_baseline_delete_outline_24)
|
||||
else -> {
|
||||
actionButton.setIconResource(R.drawable.ic_baseline_file_open_24)
|
||||
val logFile = fileUtil.getLogFile(activity, item)
|
||||
val logFile = FileUtil.getLogFile(activity, item)
|
||||
if (!logFile.exists()){
|
||||
actionButton.visibility = View.GONE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.deniscerri.ytdlnis.database
|
|||
|
||||
import androidx.room.TypeConverter
|
||||
import com.deniscerri.ytdlnis.database.models.AudioPreferences
|
||||
import com.deniscerri.ytdlnis.database.models.ChapterItem
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import com.deniscerri.ytdlnis.database.models.VideoPreferences
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
|
@ -50,4 +51,16 @@ class Converters {
|
|||
fun videoPreferencesToString(videoPreferences: VideoPreferences): String = Gson().toJson(videoPreferences)
|
||||
@TypeConverter
|
||||
fun stringToVideoPreferences(string: String): VideoPreferences = Gson().fromJson(string, VideoPreferences::class.java)
|
||||
|
||||
@TypeConverter
|
||||
fun stringToListOfChapters(value: String?): ArrayList<ChapterItem>? {
|
||||
val listType: Type = object : TypeToken<ArrayList<ChapterItem?>?>() {}.type
|
||||
return Gson().fromJson(value, listType)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun listOfChaptersToString(list: ArrayList<ChapterItem?>?): String {
|
||||
val gson = Gson()
|
||||
return gson.toJson(list)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,12 +8,13 @@ import com.deniscerri.ytdlnis.database.models.*
|
|||
@TypeConverters(Converters::class)
|
||||
@Database(
|
||||
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class, SearchHistoryItem::class, TemplateShortcut::class, CookieItem::class],
|
||||
version = 5,
|
||||
version = 6,
|
||||
autoMigrations = [
|
||||
AutoMigration (from = 1, to = 2),
|
||||
AutoMigration (from = 2, to = 3),
|
||||
AutoMigration (from = 3, to = 4),
|
||||
AutoMigration (from = 4, to = 5)
|
||||
AutoMigration (from = 4, to = 5),
|
||||
AutoMigration (from = 5, to = 6)
|
||||
]
|
||||
)
|
||||
abstract class DBManager : RoomDatabase(){
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ data class DownloadItem(
|
|||
var duration: String,
|
||||
var type: DownloadViewModel.Type,
|
||||
var format: Format,
|
||||
@ColumnInfo(defaultValue = "Default")
|
||||
var container: String,
|
||||
@ColumnInfo(defaultValue = "")
|
||||
var downloadSections: String,
|
||||
val allFormats: ArrayList<Format>,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ data class Format(
|
|||
var acodec: String = "",
|
||||
@SerializedName(value = "encoding")
|
||||
var encoding: String = "",
|
||||
@SerializedName(value = "filesize", alternate = ["clen", "filesize_approx"])
|
||||
@SerializedName(value = "filesize", alternate = ["clen", "filesize_approx", "contentLength"])
|
||||
var filesize: Long = 0,
|
||||
@SerializedName(value = "format_note", alternate = ["resolution", "audioQuality", "quality"])
|
||||
var format_note: String = "",
|
||||
|
|
@ -21,5 +21,6 @@ data class Format(
|
|||
var fps: String? = "",
|
||||
@SerializedName(value = "asr", alternate = ["audioSampleRate"])
|
||||
var asr: String? = "",
|
||||
|
||||
@SerializedName(value = "url")
|
||||
var url: String? = ""
|
||||
)
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
|
|
@ -15,5 +16,8 @@ data class ResultItem(
|
|||
val website: String,
|
||||
var playlistTitle: String,
|
||||
var formats: ArrayList<Format>,
|
||||
@ColumnInfo(defaultValue = "")
|
||||
var urls: String,
|
||||
var chapters: ArrayList<ChapterItem>?,
|
||||
var creationTime: Long = System.currentTimeMillis() / 1000,
|
||||
)
|
||||
|
|
@ -10,7 +10,7 @@ class CommandTemplateRepository(private val commandDao: CommandTemplateDao) {
|
|||
val shortcuts : LiveData<List<TemplateShortcut>> = commandDao.getAllShortcutsLiveData()
|
||||
|
||||
fun getAll() : List<CommandTemplate> {
|
||||
return commandDao.getAllTemplates();
|
||||
return commandDao.getAllTemplates()
|
||||
}
|
||||
|
||||
fun getTotalNumber() : Int {
|
||||
|
|
@ -34,7 +34,7 @@ class CommandTemplateRepository(private val commandDao: CommandTemplateDao) {
|
|||
}
|
||||
|
||||
fun getAllShortCuts() : List<TemplateShortcut> {
|
||||
return commandDao.getAllShortcuts();
|
||||
return commandDao.getAllShortcuts()
|
||||
}
|
||||
|
||||
suspend fun insertShortcut(item: TemplateShortcut){
|
||||
|
|
|
|||
|
|
@ -59,9 +59,8 @@ class HistoryRepository(private val historyDao: HistoryDao) {
|
|||
}
|
||||
|
||||
suspend fun clearDeletedHistory(){
|
||||
val fileUtil = FileUtil()
|
||||
items.value?.forEach { item ->
|
||||
if (!fileUtil.exists(item.downloadPath)){
|
||||
if (!FileUtil.exists(item.downloadPath)){
|
||||
historyDao.delete(item.id)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import com.deniscerri.ytdlnis.database.models.HistoryItem
|
|||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.models.VideoPreferences
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
import com.deniscerri.ytdlnis.work.DownloadWorker
|
||||
import com.google.gson.Gson
|
||||
|
|
@ -46,7 +47,7 @@ import java.util.Locale
|
|||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
class DownloadViewModel(private val application: Application) : AndroidViewModel(application) {
|
||||
class DownloadViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private val repository : DownloadRepository
|
||||
private val sharedPreferences: SharedPreferences
|
||||
private val commandTemplateDao: CommandTemplateDao
|
||||
|
|
@ -152,9 +153,9 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
}
|
||||
|
||||
val downloadPath = when(type){
|
||||
Type.audio -> sharedPreferences.getString("music_path", File(Environment.DIRECTORY_DOWNLOADS, "YTDLnis/Audio").absolutePath)
|
||||
Type.video -> sharedPreferences.getString("video_path", File(Environment.DIRECTORY_DOWNLOADS, "YTDLnis/Video").absolutePath)
|
||||
else -> sharedPreferences.getString("command_path", File(Environment.DIRECTORY_DOWNLOADS, "YTDLnis/Command").absolutePath)
|
||||
Type.audio -> sharedPreferences.getString("music_path", FileUtil.getDefautAudioPath())
|
||||
Type.video -> sharedPreferences.getString("video_path", FileUtil.getDefautVideoPath())
|
||||
else -> sharedPreferences.getString("command_path", FileUtil.getDefaultCommandPath())
|
||||
}
|
||||
|
||||
val sponsorblock = sharedPreferences.getStringSet("sponsorblock_filters", emptySet())
|
||||
|
|
@ -170,6 +171,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
resultItem.duration,
|
||||
type,
|
||||
getFormat(resultItem.formats, type),
|
||||
sharedPreferences.getString("video_format", "Default")!!,
|
||||
"",
|
||||
resultItem.formats,
|
||||
downloadPath!!, resultItem.website, "", resultItem.playlistTitle, audioPreferences, videoPreferences,customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Processing.toString(), 0
|
||||
|
|
@ -188,6 +190,8 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
downloadItem.website,
|
||||
downloadItem.playlistTitle,
|
||||
downloadItem.allFormats,
|
||||
"",
|
||||
arrayListOf(),
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
|
||||
|
|
@ -204,6 +208,8 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
downloadItem.website,
|
||||
"",
|
||||
arrayListOf(),
|
||||
"",
|
||||
arrayListOf(),
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
|
||||
|
|
@ -220,6 +226,8 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
"",
|
||||
"",
|
||||
arrayListOf(),
|
||||
"",
|
||||
arrayListOf(),
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
|
||||
|
|
@ -247,9 +255,15 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
}
|
||||
|
||||
val downloadPath = when(historyItem.type){
|
||||
Type.audio -> sharedPreferences.getString("music_path", File(Environment.DIRECTORY_DOWNLOADS, "YTDLnis/Audio").absolutePath)
|
||||
Type.video -> sharedPreferences.getString("video_path", File(Environment.DIRECTORY_DOWNLOADS, "YTDLnis/Video").absolutePath)
|
||||
else -> sharedPreferences.getString("command_path", File(Environment.DIRECTORY_DOWNLOADS, "YTDLnis/Command").absolutePath)
|
||||
Type.audio -> sharedPreferences.getString("music_path", FileUtil.getDefautAudioPath())
|
||||
Type.video -> sharedPreferences.getString("video_path", FileUtil.getDefautVideoPath())
|
||||
else -> sharedPreferences.getString("command_path", FileUtil.getDefaultCommandPath())
|
||||
}
|
||||
|
||||
val container = when(historyItem.type){
|
||||
Type.audio -> sharedPreferences.getString("audio_format", "Default")!!
|
||||
Type.video -> sharedPreferences.getString("video_format", "Default")!!
|
||||
else -> ""
|
||||
}
|
||||
|
||||
val sponsorblock = sharedPreferences.getStringSet("sponsorblock_filters", emptySet())
|
||||
|
|
@ -265,6 +279,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
historyItem.duration,
|
||||
historyItem.type,
|
||||
historyItem.format,
|
||||
container,
|
||||
"",
|
||||
ArrayList(),
|
||||
downloadPath!!, historyItem.website, "", "", audioPreferences, videoPreferences,customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Processing.toString(), 0
|
||||
|
|
@ -438,24 +453,6 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
}
|
||||
}
|
||||
|
||||
//if the download was quick downloaded and are incomplete
|
||||
if (queuedItems.count() == 1){
|
||||
val item = queuedItems.first()
|
||||
if (item.title.isEmpty() || item.author.isEmpty() || item.thumb.isEmpty()){
|
||||
runCatching {
|
||||
val info = infoUtil.getMissingInfo(item.url)
|
||||
if (item.title.isEmpty()) item.title = info?.title.toString()
|
||||
if (item.author.isEmpty()) item.author = info?.author.toString()
|
||||
item.duration = info?.duration.toString()
|
||||
item.website = info?.website.toString()
|
||||
if (item.thumb.isEmpty()) item.thumb = info?.thumb.toString()
|
||||
repository.update(item)
|
||||
}.onFailure { err ->
|
||||
Log.e("error", err.message.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
queuedItems.forEach {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
var delay = if (it.downloadStartTime != 0L){
|
||||
|
|
|
|||
|
|
@ -90,8 +90,7 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
|
|||
fun delete(item: HistoryItem, deleteFile: Boolean) = viewModelScope.launch(Dispatchers.IO){
|
||||
repository.delete(item)
|
||||
if (deleteFile){
|
||||
val fileUtil = FileUtil()
|
||||
fileUtil.deleteFile(item.downloadPath)
|
||||
FileUtil.deleteFile(item.downloadPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class SharedDownloadNotificationReceiver : AppCompatActivity() {
|
|||
val notificationId = intent.getIntExtra("notificationID", 0)
|
||||
if (message != null && path != null) {
|
||||
if (notificationId != 0) NotificationUtil(this).cancelDownloadNotification(notificationId)
|
||||
val uiUtil = UiUtil(FileUtil())
|
||||
val uiUtil = UiUtil()
|
||||
uiUtil.shareFileIntent(this, listOf(path))
|
||||
this.finishAffinity()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,5 @@ open class BaseActivity : AppCompatActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
ThemeUtil.updateTheme(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { v, insets ->
|
||||
v.setPadding(0, 0, 0, 0)
|
||||
insets
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +37,6 @@ import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
|||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadMultipleBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
import com.facebook.shimmer.ShimmerFrameLayout
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
|
|
@ -88,7 +87,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
private var uiHandler: Handler? = null
|
||||
private var resultsList: List<ResultItem?>? = null
|
||||
private var selectedObjects: ArrayList<ResultItem>? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var quickLaunchSheet = false
|
||||
private var sharedPreferences: SharedPreferences? = null
|
||||
private var _binding : FragmentHomeBinding? = null
|
||||
|
|
@ -114,7 +112,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
|
||||
fragmentContext = context
|
||||
layoutinflater = LayoutInflater.from(context)
|
||||
fileUtil = FileUtil()
|
||||
uiHandler = Handler(Looper.getMainLooper())
|
||||
selectedObjects = ArrayList()
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
commandTemplateDao = DBManager.getInstance(requireContext()).commandTemplateDao
|
||||
onDownloadItemUpdateListener = listener
|
||||
uiUtil = UiUtil(FileUtil())
|
||||
uiUtil = UiUtil()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
|
@ -94,6 +94,13 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
}
|
||||
}
|
||||
|
||||
//check if the item has formats and its audio-only
|
||||
val isAudioOnly = resultItem.formats.isNotEmpty() && resultItem.formats.none { !it.format_note.contains("audio") }
|
||||
if (isAudioOnly){
|
||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.isClickable = true
|
||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.alpha = 0.3f
|
||||
}
|
||||
|
||||
|
||||
val fragmentManager = parentFragmentManager
|
||||
fragmentAdapter = DownloadFragmentAdapter(
|
||||
|
|
@ -111,8 +118,14 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
viewPager2.setCurrentItem(0, false)
|
||||
}
|
||||
Type.video -> {
|
||||
tabLayout.selectTab(tabLayout.getTabAt(1))
|
||||
viewPager2.setCurrentItem(1, false)
|
||||
if (isAudioOnly){
|
||||
tabLayout.getTabAt(0)!!.select()
|
||||
viewPager2.setCurrentItem(0, false)
|
||||
Toast.makeText(context, getString(R.string.audio_only_item), Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
tabLayout.getTabAt(1)!!.select()
|
||||
viewPager2.setCurrentItem(1, false)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
tabLayout.selectTab(tabLayout.getTabAt(2))
|
||||
|
|
@ -127,6 +140,9 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
if (tab!!.position == 2 && commandTemplateNr == 0){
|
||||
tabLayout.selectTab(tabLayout.getTabAt(1))
|
||||
Toast.makeText(context, getString(R.string.add_template_first), Toast.LENGTH_SHORT).show()
|
||||
}else if (tab.position == 1 && isAudioOnly){
|
||||
tabLayout.selectTab(tabLayout.getTabAt(0))
|
||||
Toast.makeText(context, getString(R.string.audio_only_item), Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
viewPager2.setCurrentItem(tab.position, false)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,9 +60,8 @@ import java.util.*
|
|||
import kotlin.properties.Delegates
|
||||
|
||||
|
||||
class CutVideoBottomSheetDialog(private val item: DownloadItem, private val listener: VideoCutListener) : BottomSheetDialogFragment() {
|
||||
class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls : String?, private var chapters: List<ChapterItem>?, private val listener: VideoCutListener) : BottomSheetDialogFragment() {
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var fileUtil: FileUtil
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
private lateinit var uiUtil: UiUtil
|
||||
private lateinit var player: Player
|
||||
|
|
@ -86,14 +85,12 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
|
|||
private lateinit var chipGroup : ChipGroup
|
||||
|
||||
private var timeSeconds by Delegates.notNull<Int>()
|
||||
private lateinit var chapters: List<ChapterItem>
|
||||
private lateinit var selectedCuts: MutableList<String>
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(fileUtil)
|
||||
uiUtil = UiUtil()
|
||||
infoUtil = InfoUtil(requireActivity().applicationContext)
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +147,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
|
|||
val videoView = view.findViewById<StyledPlayerView>(R.id.video_view)
|
||||
videoView.player = player
|
||||
timeSeconds = convertStringToTimestamp(item.duration)
|
||||
chapters = emptyList()
|
||||
if (chapters == null) chapters = emptyList()
|
||||
|
||||
//cut section
|
||||
cutSection = view.findViewById(R.id.cut_section)
|
||||
|
|
@ -166,7 +163,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
|
|||
okBtn = view.findViewById(R.id.okButton)
|
||||
suggestedChips = view.findViewById(R.id.chapters)
|
||||
suggestedChapters = view.findViewById(R.id.suggested_cuts)
|
||||
initCutSection()
|
||||
|
||||
|
||||
//cut list section
|
||||
cutListSection = view.findViewById(R.id.list_section)
|
||||
|
|
@ -174,6 +171,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
|
|||
resetBtn = view.findViewById(R.id.reset_all)
|
||||
chipGroup = view.findViewById(R.id.cut_list_chip_group)
|
||||
|
||||
|
||||
selectedCuts = if (chipGroup.childCount == 0){
|
||||
mutableListOf()
|
||||
}else {
|
||||
|
|
@ -183,6 +181,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
|
|||
chipGroup.children.map { (it as Chip).text.toString() }.toMutableList()
|
||||
}
|
||||
|
||||
initCutSection()
|
||||
initCutListSection()
|
||||
|
||||
if (item.downloadSections.isBlank()) cutSection.visibility = View.VISIBLE
|
||||
|
|
@ -190,16 +189,22 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
|
|||
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val data = withContext(Dispatchers.IO){
|
||||
infoUtil.getStreamingUrlAndChapters(item.url)
|
||||
val data : MutableList<String?> = withContext(Dispatchers.IO){
|
||||
if (urls.isNullOrEmpty() || chapters.isNullOrEmpty()) {
|
||||
infoUtil.getStreamingUrlAndChapters(item.url)
|
||||
}else {
|
||||
urls.split("\n").toMutableList()
|
||||
}
|
||||
}
|
||||
if (data.isEmpty()) throw Exception("No Data found!")
|
||||
try{
|
||||
val listType: Type = object : TypeToken<List<ChapterItem>>() {}.type
|
||||
chapters = Gson().fromJson(data.first().toString(), listType)
|
||||
}catch (ignored: Exception) {}
|
||||
data.removeFirst()
|
||||
|
||||
if (data.isEmpty()) throw Exception("No Data found!")
|
||||
if (chapters!!.isEmpty()){
|
||||
try{
|
||||
val listType: Type = object : TypeToken<List<ChapterItem>>() {}.type
|
||||
chapters = Gson().fromJson(data.first().toString(), listType)
|
||||
}catch (ignored: Exception) {}
|
||||
data.removeFirst()
|
||||
}
|
||||
|
||||
if (data.isEmpty()) throw Exception("No Streaming URL found!")
|
||||
if (data.size == 2){
|
||||
|
|
@ -375,11 +380,11 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
|
|||
}
|
||||
|
||||
private fun populateSuggestedChapters(){
|
||||
if (chapters.isEmpty()) suggestedChapters.visibility = View.GONE
|
||||
if (chapters!!.isEmpty()) suggestedChapters.visibility = View.GONE
|
||||
else {
|
||||
suggestedChapters.visibility = View.VISIBLE
|
||||
suggestedChips.removeAllViews()
|
||||
chapters.forEach {
|
||||
chapters!!.forEach {
|
||||
val chip = layoutInflater.inflate(R.layout.suggestion_chip, chipGroup, false) as Chip
|
||||
chip.text = it.title
|
||||
chip.chipBackgroundColor = ColorStateList.valueOf(MaterialColors.getColor(requireContext(), R.attr.colorSecondaryContainer, Color.BLACK))
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var resultViewModel : ResultViewModel
|
||||
private lateinit var fileUtil : FileUtil
|
||||
private lateinit var uiUtil : UiUtil
|
||||
|
||||
private lateinit var title : TextInputLayout
|
||||
|
|
@ -71,8 +70,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(fileUtil)
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +110,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
})
|
||||
saveDir = view.findViewById(R.id.outputPath)
|
||||
saveDir.editText!!.setText(
|
||||
fileUtil.formatPath(downloadItem.downloadPath)
|
||||
FileUtil.formatPath(downloadItem.downloadPath)
|
||||
)
|
||||
saveDir.editText!!.isFocusable = false
|
||||
saveDir.editText!!.isClickable = true
|
||||
|
|
@ -124,8 +122,8 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
audioPathResultLauncher.launch(intent)
|
||||
}
|
||||
freeSpace = view.findViewById(R.id.freespace)
|
||||
val free = fileUtil.convertFileSize(
|
||||
File(fileUtil.formatPath(downloadItem.downloadPath)).freeSpace)
|
||||
val free = FileUtil.convertFileSize(
|
||||
File(FileUtil.formatPath(downloadItem.downloadPath)).freeSpace)
|
||||
freeSpace.text = String.format( getString(R.string.freespace) + ": " + free)
|
||||
if (free == "?") freeSpace.visibility = View.GONE
|
||||
|
||||
|
|
@ -157,7 +155,6 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
}
|
||||
}
|
||||
formats = allFormats.first().toMutableList()
|
||||
downloadItem.format.container = container.editText?.text.toString()
|
||||
}
|
||||
}
|
||||
formatCard.setOnClickListener{
|
||||
|
|
@ -181,13 +178,13 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
)
|
||||
)
|
||||
|
||||
downloadItem.format.container = if (containerPreference == getString(R.string.defaultValue)) "" else containerPreference!!
|
||||
containerAutoCompleteTextView.setText(downloadItem.format.container.ifEmpty { getString(R.string.defaultValue) }, false)
|
||||
downloadItem.container = if (containerPreference == getString(R.string.defaultValue)) "" else containerPreference!!
|
||||
containerAutoCompleteTextView.setText(downloadItem.container.ifEmpty { getString(R.string.defaultValue) }, false)
|
||||
|
||||
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
|
||||
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
|
||||
downloadItem.format.container = containers[index]
|
||||
if (containers[index] == getString(R.string.defaultValue)) downloadItem.format.container = ""
|
||||
downloadItem.container = containers[index]
|
||||
if (containers[index] == getString(R.string.defaultValue)) downloadItem.container = ""
|
||||
}
|
||||
|
||||
val embedThumb = view.findViewById<Chip>(R.id.embed_thumb)
|
||||
|
|
@ -313,7 +310,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
}
|
||||
cut.setOnClickListener {
|
||||
if (parentFragmentManager.findFragmentByTag("cutVideoSheet") == null){
|
||||
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, cutVideoListener)
|
||||
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, resultItem.urls, resultItem.chapters, cutVideoListener)
|
||||
bottomSheet.show(parentFragmentManager, "cutVideoSheet")
|
||||
}
|
||||
}
|
||||
|
|
@ -340,10 +337,10 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
}
|
||||
downloadItem.downloadPath = result.data?.data.toString()
|
||||
//downloadViewModel.updateDownload(downloadItem)
|
||||
saveDir.editText?.setText(fileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE)
|
||||
saveDir.editText?.setText(FileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE)
|
||||
|
||||
val free = fileUtil.convertFileSize(
|
||||
File(fileUtil.formatPath(downloadItem.downloadPath)).freeSpace)
|
||||
val free = FileUtil.convertFileSize(
|
||||
File(FileUtil.formatPath(downloadItem.downloadPath)).freeSpace)
|
||||
freeSpace.text = String.format( getString(R.string.freespace) + ": " + free)
|
||||
if (free == "?") freeSpace.visibility = View.GONE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
commandTemplateDao = DBManager.getInstance(requireContext()).commandTemplateDao
|
||||
uiUtil = UiUtil(FileUtil())
|
||||
uiUtil = UiUtil()
|
||||
infoUtil = InfoUtil(requireContext())
|
||||
}
|
||||
|
||||
|
|
@ -103,6 +103,13 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
}
|
||||
}
|
||||
|
||||
//check if the item has formats and its audio-only
|
||||
val isAudioOnly = resultItem.formats.isNotEmpty() && resultItem.formats.none { !it.format_note.contains("audio") }
|
||||
if (isAudioOnly){
|
||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.isClickable = true
|
||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.alpha = 0.3f
|
||||
}
|
||||
|
||||
|
||||
val fragmentManager = parentFragmentManager
|
||||
fragmentAdapter = DownloadFragmentAdapter(
|
||||
|
|
@ -121,8 +128,14 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
viewPager2.setCurrentItem(0, false)
|
||||
}
|
||||
Type.video -> {
|
||||
tabLayout.getTabAt(1)!!.select()
|
||||
viewPager2.setCurrentItem(1, false)
|
||||
if (isAudioOnly){
|
||||
tabLayout.getTabAt(0)!!.select()
|
||||
viewPager2.setCurrentItem(0, false)
|
||||
Toast.makeText(context, getString(R.string.audio_only_item), Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
tabLayout.getTabAt(1)!!.select()
|
||||
viewPager2.setCurrentItem(1, false)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
tabLayout.getTabAt(2)!!.select()
|
||||
|
|
@ -138,7 +151,11 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
if (tab!!.position == 2 && commandTemplateNr == 0){
|
||||
tabLayout.selectTab(tabLayout.getTabAt(1))
|
||||
Toast.makeText(context, getString(R.string.add_template_first), Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
}else if (tab.position == 1 && isAudioOnly){
|
||||
tabLayout.selectTab(tabLayout.getTabAt(0))
|
||||
Toast.makeText(context, getString(R.string.audio_only_item), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
else{
|
||||
viewPager2.setCurrentItem(tab.position, false)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var commandTemplateViewModel : CommandTemplateViewModel
|
||||
private lateinit var fileUtil : FileUtil
|
||||
private lateinit var uiUtil : UiUtil
|
||||
private lateinit var saveDir : TextInputLayout
|
||||
private lateinit var freeSpace : TextView
|
||||
|
|
@ -59,8 +58,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(fileUtil)
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +136,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
|
||||
saveDir = view.findViewById(R.id.outputPath)
|
||||
saveDir.editText!!.setText(
|
||||
fileUtil.formatPath(downloadItem.downloadPath)
|
||||
FileUtil.formatPath(downloadItem.downloadPath)
|
||||
)
|
||||
saveDir.editText!!.isFocusable = false
|
||||
saveDir.editText!!.isClickable = true
|
||||
|
|
@ -151,8 +149,8 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
}
|
||||
|
||||
freeSpace = view.findViewById(R.id.freespace)
|
||||
freeSpace.text = String.format(getString(R.string.freespace) + ": " + fileUtil.convertFileSize(
|
||||
File(fileUtil.formatPath(downloadItem.downloadPath)).freeSpace
|
||||
freeSpace.text = String.format(getString(R.string.freespace) + ": " + FileUtil.convertFileSize(
|
||||
File(FileUtil.formatPath(downloadItem.downloadPath)).freeSpace
|
||||
))
|
||||
|
||||
val newTemplate : Chip = view.findViewById(R.id.newTemplate)
|
||||
|
|
@ -226,10 +224,10 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
)
|
||||
}
|
||||
downloadItem.downloadPath = result.data?.data.toString()
|
||||
saveDir.editText?.setText(fileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE)
|
||||
saveDir.editText?.setText(FileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE)
|
||||
|
||||
freeSpace.text = String.format(getString(R.string.freespace) + ": " + fileUtil.convertFileSize(
|
||||
File(fileUtil.formatPath(downloadItem.downloadPath)).freeSpace
|
||||
freeSpace.text = String.format(getString(R.string.freespace) + ": " + FileUtil.convertFileSize(
|
||||
File(FileUtil.formatPath(downloadItem.downloadPath)).freeSpace
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
private lateinit var listAdapter : ConfigureMultipleDownloadsAdapter
|
||||
private lateinit var recyclerView: RecyclerView
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var fileUtil: FileUtil
|
||||
private lateinit var uiUtil: UiUtil
|
||||
private lateinit var bottomAppBar: BottomAppBar
|
||||
|
||||
|
|
@ -69,8 +68,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(fileUtil)
|
||||
uiUtil = UiUtil()
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi", "NotifyDataSetChanged")
|
||||
|
|
@ -291,7 +289,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
items.forEach {
|
||||
it.downloadPath = result.data?.data.toString()
|
||||
}
|
||||
Toast.makeText(requireContext(), "Changed every item's download path to: ${fileUtil.formatPath(result.data!!.data.toString())}", Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(requireContext(), "Changed every item's download path to: ${FileUtil.formatPath(result.data!!.data.toString())}", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var resultViewModel: ResultViewModel
|
||||
private lateinit var fileUtil : FileUtil
|
||||
private lateinit var uiUtil : UiUtil
|
||||
|
||||
private lateinit var title : TextInputLayout
|
||||
|
|
@ -72,8 +71,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this@DownloadVideoFragment)[ResultViewModel::class.java]
|
||||
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(fileUtil)
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +112,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
|
||||
saveDir = view.findViewById(R.id.outputPath)
|
||||
saveDir.editText!!.setText(
|
||||
fileUtil.formatPath(downloadItem.downloadPath)
|
||||
FileUtil.formatPath(downloadItem.downloadPath)
|
||||
)
|
||||
saveDir.editText!!.isFocusable = false
|
||||
saveDir.editText!!.isClickable = true
|
||||
|
|
@ -127,8 +125,8 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
}
|
||||
|
||||
freeSpace = view.findViewById(R.id.freespace)
|
||||
val free = fileUtil.convertFileSize(
|
||||
File(fileUtil.formatPath(downloadItem.downloadPath)).freeSpace)
|
||||
val free = FileUtil.convertFileSize(
|
||||
File(FileUtil.formatPath(downloadItem.downloadPath)).freeSpace)
|
||||
freeSpace.text = String.format( getString(R.string.freespace) + ": " + free)
|
||||
if (free == "?") freeSpace.visibility = View.GONE
|
||||
|
||||
|
|
@ -148,7 +146,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
val formatCard = view.findViewById<MaterialCardView>(R.id.format_card_constraintLayout)
|
||||
|
||||
val chosenFormat = downloadItem.format
|
||||
uiUtil.populateFormatCard(formatCard, chosenFormat, null)
|
||||
uiUtil.populateFormatCard(formatCard, chosenFormat, downloadItem.allFormats.filter { downloadItem.videoPreferences.audioFormatIDs.contains(it.format_id) })
|
||||
val listener = object : OnFormatClickListener {
|
||||
override fun onFormatClick(allFormats: List<List<Format>>, item: List<Format>) {
|
||||
downloadItem.format = item.first()
|
||||
|
|
@ -162,7 +160,6 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
}
|
||||
formats = allFormats.first().toMutableList()
|
||||
uiUtil.populateFormatCard(formatCard, item.first(), item.drop(1))
|
||||
downloadItem.format.container = container.editText?.text.toString()
|
||||
}
|
||||
}
|
||||
formatCard.setOnClickListener{
|
||||
|
|
@ -185,15 +182,15 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
containers
|
||||
)
|
||||
)
|
||||
downloadItem.format.container = if (containerPreference == getString(R.string.defaultValue)) "" else containerPreference!!
|
||||
downloadItem.container = if (containerPreference == getString(R.string.defaultValue)) "" else containerPreference!!
|
||||
containerAutoCompleteTextView!!.setText(
|
||||
downloadItem.format.container.ifEmpty { getString(R.string.defaultValue) },
|
||||
downloadItem.container.ifEmpty { getString(R.string.defaultValue) },
|
||||
false)
|
||||
|
||||
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
|
||||
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
|
||||
downloadItem.format.container = containers[index]
|
||||
if (containers[index] == getString(R.string.defaultValue)) downloadItem.format.container = ""
|
||||
downloadItem.container = containers[index]
|
||||
if (containers[index] == getString(R.string.defaultValue)) downloadItem.container = ""
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -312,7 +309,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
}
|
||||
cut.setOnClickListener {
|
||||
if (parentFragmentManager.findFragmentByTag("cutVideoSheet") == null){
|
||||
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, cutVideoListener)
|
||||
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, resultItem.urls, resultItem.chapters, cutVideoListener)
|
||||
bottomSheet.show(parentFragmentManager, "cutVideoSheet")
|
||||
}
|
||||
}
|
||||
|
|
@ -332,17 +329,17 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
builder.setView(inputLayout)
|
||||
builder.setPositiveButton(
|
||||
getString(R.string.ok)
|
||||
) { dialog: DialogInterface?, which: Int ->
|
||||
) { _: DialogInterface?, _: Int ->
|
||||
downloadItem.customFileNameTemplate = editText.text.toString()
|
||||
}
|
||||
|
||||
// handle the negative button of the alert dialog
|
||||
builder.setNegativeButton(
|
||||
getString(R.string.cancel)
|
||||
) { dialog: DialogInterface?, which: Int -> }
|
||||
) { _: DialogInterface?, _: Int -> }
|
||||
|
||||
val dialog = builder.create()
|
||||
editText.doOnTextChanged { text, start, before, count ->
|
||||
editText.doOnTextChanged { _, _, _, _ ->
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
}
|
||||
dialog.show()
|
||||
|
|
@ -363,7 +360,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
subtitleLanguages.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
saveSubtitles.setOnCheckedChangeListener { compoundButton, b ->
|
||||
saveSubtitles.setOnCheckedChangeListener { _, _ ->
|
||||
if (saveSubtitles.isChecked) subtitleLanguages.visibility = View.VISIBLE
|
||||
else subtitleLanguages.visibility = View.GONE
|
||||
downloadItem.videoPreferences.writeSubs = saveSubtitles.isChecked
|
||||
|
|
@ -376,7 +373,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
}
|
||||
|
||||
val removeAudio = view.findViewById<Chip>(R.id.remove_audio)
|
||||
removeAudio.setOnCheckedChangeListener { compoundButton, b ->
|
||||
removeAudio.setOnCheckedChangeListener { _, _ ->
|
||||
downloadItem.videoPreferences.removeAudio = removeAudio.isChecked
|
||||
}
|
||||
|
||||
|
|
@ -398,11 +395,10 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
)
|
||||
}
|
||||
downloadItem.downloadPath = result.data?.data.toString()
|
||||
//downloadviewmodel.updateDownload(downloadItem)
|
||||
saveDir.editText?.setText(fileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE)
|
||||
saveDir.editText?.setText(FileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE)
|
||||
|
||||
val free = fileUtil.convertFileSize(
|
||||
File(fileUtil.formatPath(downloadItem.downloadPath)).freeSpace)
|
||||
val free = FileUtil.convertFileSize(
|
||||
File(FileUtil.formatPath(downloadItem.downloadPath)).freeSpace)
|
||||
freeSpace.text = String.format( getString(R.string.freespace) + ": " + free)
|
||||
if (free == "?") freeSpace.visibility = View.GONE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import java.util.*
|
|||
|
||||
class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, private var formats: List<List<Format>>, private val listener: OnFormatClickListener) : BottomSheetDialogFragment() {
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var fileUtil: FileUtil
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
private lateinit var uiUtil: UiUtil
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
|
|
@ -48,8 +47,7 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(fileUtil)
|
||||
uiUtil = UiUtil()
|
||||
infoUtil = InfoUtil(requireActivity().applicationContext)
|
||||
formatCollection = mutableListOf()
|
||||
chosenFormats = listOf()
|
||||
|
|
@ -116,11 +114,12 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
}
|
||||
|
||||
val refreshBtn = view.findViewById<Button>(R.id.format_refresh)
|
||||
if (formats.flatten().none { it.filesize == 0L } || items.isEmpty()) refreshBtn.visibility = View.GONE
|
||||
if (!hasGenericFormats || items.isEmpty()) refreshBtn.visibility = View.GONE
|
||||
|
||||
|
||||
refreshBtn.setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
chosenFormats = emptyList()
|
||||
try {
|
||||
refreshBtn.isEnabled = false
|
||||
formatListLinearLayout.visibility = View.GONE
|
||||
|
|
@ -132,9 +131,11 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
val res = withContext(Dispatchers.IO){
|
||||
infoUtil.getFormats(items.first()!!.url)
|
||||
}
|
||||
chosenFormats = res.formats.filter { it.filesize != 0L }
|
||||
res.filter { it.format_note != "storyboard" }
|
||||
if(items.first()?.type == Type.audio){
|
||||
chosenFormats = chosenFormats.filter { it.format_note.contains("audio", ignoreCase = true) }
|
||||
chosenFormats = res.filter { it.format_note.contains("audio", ignoreCase = true) }
|
||||
}else{
|
||||
chosenFormats = res
|
||||
}
|
||||
if (chosenFormats.isEmpty()) throw Exception()
|
||||
//playlist format filtering
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import com.google.android.material.progressindicator.LinearProgressIndicator
|
|||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
|
||||
|
||||
class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickListener, OnClickListener {
|
||||
class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickListener, OnClickListener {
|
||||
private var _binding : FragmentHomeBinding? = null
|
||||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
|
|
@ -34,7 +34,6 @@ class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickL
|
|||
private lateinit var activeDownloads : ActiveDownloadAdapter
|
||||
lateinit var downloadItem: DownloadItem
|
||||
private lateinit var notificationUtil: NotificationUtil
|
||||
private lateinit var fileUtil: FileUtil
|
||||
private lateinit var list: List<DownloadItem>
|
||||
|
||||
|
||||
|
|
@ -47,7 +46,6 @@ class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickL
|
|||
fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false)
|
||||
activity = getActivity()
|
||||
notificationUtil = NotificationUtil(requireContext())
|
||||
fileUtil = FileUtil()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
list = listOf()
|
||||
return fragmentView
|
||||
|
|
@ -102,7 +100,7 @@ class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickL
|
|||
}
|
||||
|
||||
override fun onOutputClick(item: DownloadItem) {
|
||||
val logFile = fileUtil.getLogFile(requireContext(), item)
|
||||
val logFile = FileUtil.getLogFile(requireContext(), item)
|
||||
if (logFile.exists()) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("logpath", logFile.absolutePath)
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
private var selectedObjects: ArrayList<DownloadItem>? = null
|
||||
private var actionMode : ActionMode? = null
|
||||
private lateinit var items : MutableList<DownloadItem>
|
||||
private lateinit var fileUtil: FileUtil
|
||||
private lateinit var uiUtil : UiUtil
|
||||
|
||||
override fun onCreateView(
|
||||
|
|
@ -66,8 +65,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
selectedObjects = arrayListOf()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
items = mutableListOf()
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(fileUtil)
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -163,7 +161,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
codec.text = codecText
|
||||
}
|
||||
|
||||
val fileSizeReadable = fileUtil.convertFileSize(item.format.filesize)
|
||||
val fileSizeReadable = FileUtil.convertFileSize(item.format.filesize)
|
||||
if (fileSizeReadable == "?") fileSize!!.visibility = View.GONE
|
||||
else fileSize!!.text = fileSizeReadable
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||
import com.google.android.material.snackbar.Snackbar
|
||||
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.File
|
||||
|
||||
|
||||
class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener, OnItemClickListener {
|
||||
|
|
@ -54,7 +55,6 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
private lateinit var items : MutableList<DownloadItem>
|
||||
private var selectedObjects: ArrayList<DownloadItem>? = null
|
||||
private var actionMode : ActionMode? = null
|
||||
private lateinit var fileUtil: FileUtil
|
||||
private lateinit var uiUtil : UiUtil
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
|
@ -67,8 +67,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
items = mutableListOf()
|
||||
selectedObjects = arrayListOf()
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(fileUtil)
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +97,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
|
||||
override fun onActionButtonClick(itemID: Long) {
|
||||
val item = items.find { it.id == itemID } ?: return
|
||||
val logFile = fileUtil.getLogFile(requireContext(), item)
|
||||
val logFile = FileUtil.getLogFile(requireContext(), item)
|
||||
if (logFile.exists()) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("logpath", logFile.absolutePath)
|
||||
|
|
@ -165,7 +164,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
codec.text = codecText
|
||||
}
|
||||
|
||||
val fileSizeReadable = fileUtil.convertFileSize(item.format.filesize)
|
||||
val fileSizeReadable = FileUtil.convertFileSize(item.format.filesize)
|
||||
if (fileSizeReadable == "?") fileSize!!.visibility = View.GONE
|
||||
else fileSize!!.text = fileSizeReadable
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
private var historyList: List<HistoryItem?>? = null
|
||||
private var allhistoryList: List<HistoryItem?>? = null
|
||||
private var selectedObjects: ArrayList<HistoryItem>? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var uiUtil: UiUtil? = null
|
||||
private var _binding : FragmentHistoryBinding? = null
|
||||
private var actionMode : ActionMode? = null
|
||||
|
|
@ -113,8 +112,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
noResults = view.findViewById(R.id.no_results)
|
||||
selectionChips = view.findViewById(R.id.history_selection_chips)
|
||||
websiteGroup = view.findViewById(R.id.website_chip_group)
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(FileUtil())
|
||||
uiUtil = UiUtil()
|
||||
uiHandler = Handler(Looper.getMainLooper())
|
||||
selectedObjects = ArrayList()
|
||||
|
||||
|
|
@ -462,7 +460,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
codec.text = codecText
|
||||
}
|
||||
|
||||
val fileSizeReadable = fileUtil!!.convertFileSize(item.format.filesize)
|
||||
val fileSizeReadable = FileUtil.convertFileSize(item.format.filesize)
|
||||
if (fileSizeReadable == "?") fileSize!!.visibility = GONE
|
||||
else fileSize!!.text = fileSizeReadable
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
private var selectedObjects: ArrayList<DownloadItem>? = null
|
||||
private var actionMode : ActionMode? = null
|
||||
private lateinit var items : MutableList<DownloadItem>
|
||||
private lateinit var fileUtil: FileUtil
|
||||
private lateinit var uiUtil: UiUtil
|
||||
|
||||
override fun onCreateView(
|
||||
|
|
@ -78,8 +77,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
items = mutableListOf()
|
||||
selectedObjects = arrayListOf()
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(fileUtil)
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -185,7 +183,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
codec.text = codecText
|
||||
}
|
||||
|
||||
val fileSizeReadable = fileUtil.convertFileSize(item.format.filesize)
|
||||
val fileSizeReadable = FileUtil.convertFileSize(item.format.filesize)
|
||||
if (fileSizeReadable == "?") fileSize!!.visibility = View.GONE
|
||||
else fileSize!!.text = fileSizeReadable
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
|||
itemTouchHelper.attachToRecyclerView(recyclerView)
|
||||
}
|
||||
|
||||
uiUtil = UiUtil(FileUtil())
|
||||
uiUtil = UiUtil()
|
||||
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
commandTemplateViewModel.items.observe(viewLifecycleOwner) {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
|||
val itemTouchHelper = ItemTouchHelper(simpleCallback)
|
||||
itemTouchHelper.attachToRecyclerView(recyclerView)
|
||||
}
|
||||
uiUtil = UiUtil(FileUtil())
|
||||
uiUtil = UiUtil()
|
||||
|
||||
cookiesViewModel = ViewModelProvider(this)[CookieViewModel::class.java]
|
||||
cookiesViewModel.items.observe(viewLifecycleOwner) {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ class TerminalActivity : BaseActivity() {
|
|||
private lateinit var observer: FileObserver
|
||||
private lateinit var imm : InputMethodManager
|
||||
private lateinit var uiUtil: UiUtil
|
||||
private lateinit var fileUtil: FileUtil
|
||||
var context: Context? = null
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -75,8 +74,7 @@ class TerminalActivity : BaseActivity() {
|
|||
downloadFile = File(cacheDir.absolutePath + "/$downloadID.txt")
|
||||
if (! downloadFile.exists()) downloadFile.createNewFile()
|
||||
imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(fileUtil)
|
||||
uiUtil = UiUtil()
|
||||
|
||||
context = baseContext
|
||||
scrollView = findViewById(R.id.custom_command_scrollview)
|
||||
|
|
@ -311,7 +309,7 @@ class TerminalActivity : BaseActivity() {
|
|||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
}
|
||||
input!!.text.insert(input!!.selectionStart, fileUtil.formatPath(result.data?.data.toString()))
|
||||
input!!.text.insert(input!!.selectionStart, FileUtil.formatPath(result.data?.data.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
private var accessAllFiles : Preference? = null
|
||||
private var clearCache: Preference? = null
|
||||
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var activeDownloadCount = 0
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
|
|
@ -33,7 +32,6 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val editor = preferences.edit()
|
||||
fileUtil = FileUtil()
|
||||
|
||||
musicPath = findPreference("music_path")
|
||||
videoPath = findPreference("video_path")
|
||||
|
|
@ -42,13 +40,13 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
clearCache = findPreference("clear_cache")
|
||||
|
||||
if (preferences.getString("music_path", "")!!.isEmpty()) {
|
||||
editor.putString("music_path", getString(R.string.music_path))
|
||||
editor.putString("music_path", FileUtil.getDefautAudioPath())
|
||||
}
|
||||
if (preferences.getString("video_path", "")!!.isEmpty()) {
|
||||
editor.putString("video_path", getString(R.string.video_path))
|
||||
editor.putString("video_path", FileUtil.getDefautVideoPath())
|
||||
}
|
||||
if (preferences.getString("command_path", "")!!.isEmpty()) {
|
||||
editor.putString("command_path", getString(R.string.command_path))
|
||||
editor.putString("command_path", FileUtil.getDefaultCommandPath())
|
||||
}
|
||||
|
||||
if((VERSION.SDK_INT >= 30 && Environment.isExternalStorageManager()) ||
|
||||
|
|
@ -58,7 +56,7 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
|
||||
editor.apply()
|
||||
|
||||
musicPath!!.summary = fileUtil?.formatPath(preferences.getString("music_path", "")!!)
|
||||
musicPath!!.summary = FileUtil.formatPath(preferences.getString("music_path", "")!!)
|
||||
musicPath!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
|
|
@ -68,7 +66,7 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
musicPathResultLauncher.launch(intent)
|
||||
true
|
||||
}
|
||||
videoPath!!.summary = fileUtil?.formatPath(preferences.getString("video_path", "")!!)
|
||||
videoPath!!.summary = FileUtil.formatPath(preferences.getString("video_path", "")!!)
|
||||
videoPath!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
|
|
@ -78,7 +76,7 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
videoPathResultLauncher.launch(intent)
|
||||
true
|
||||
}
|
||||
commandPath!!.summary = fileUtil?.formatPath(preferences.getString("command_path", "")!!)
|
||||
commandPath!!.summary = FileUtil.formatPath(preferences.getString("command_path", "")!!)
|
||||
commandPath!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
|
|
@ -98,14 +96,14 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
}
|
||||
|
||||
var cacheSize = File(requireContext().cacheDir.absolutePath + "/downloads").walkBottomUp().fold(0L) { acc, file -> acc + file.length() }
|
||||
clearCache!!.summary = "(${fileUtil!!.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}"
|
||||
clearCache!!.summary = "(${FileUtil.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}"
|
||||
clearCache!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
if (activeDownloadCount == 0){
|
||||
File(requireContext().cacheDir.absolutePath + "/downloads").deleteRecursively()
|
||||
Snackbar.make(requireView(), getString(R.string.cache_cleared), Snackbar.LENGTH_SHORT).show()
|
||||
cacheSize = File(requireContext().cacheDir.absolutePath + "/downloads").walkBottomUp().fold(0L) { acc, file -> acc + file.length() }
|
||||
clearCache!!.summary = "(${fileUtil!!.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}"
|
||||
clearCache!!.summary = "(${FileUtil.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}"
|
||||
}else{
|
||||
Snackbar.make(requireView(), getString(R.string.downloads_running_try_later), Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
|
|
@ -159,7 +157,7 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
|
||||
private fun changePath(p: Preference?, data: Intent?, requestCode: Int) {
|
||||
val path = data!!.data.toString()
|
||||
p!!.summary = fileUtil?.formatPath(data.data.toString())
|
||||
p!!.summary = FileUtil.formatPath(data.data.toString())
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val editor = sharedPreferences.edit()
|
||||
when (requestCode) {
|
||||
|
|
|
|||
|
|
@ -30,13 +30,11 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
|
|||
private var locale: ListPreference? = null
|
||||
|
||||
private var updateUtil: UpdateUtil? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var activeDownloadCount = 0
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.general_preferences, rootKey)
|
||||
updateUtil = UpdateUtil(requireContext())
|
||||
fileUtil = FileUtil()
|
||||
|
||||
WorkManager.getInstance(requireContext()).getWorkInfosByTagLiveData("download").observe(this){
|
||||
activeDownloadCount = 0
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
private var restore : Preference? = null
|
||||
|
||||
private var updateUtil: UpdateUtil? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var activeDownloadCount = 0
|
||||
|
||||
private lateinit var resultViewModel: ResultViewModel
|
||||
|
|
@ -105,7 +104,6 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
|
||||
//about section -------------------------
|
||||
updateUtil = UpdateUtil(requireContext())
|
||||
fileUtil = FileUtil()
|
||||
|
||||
WorkManager.getInstance(requireContext()).getWorkInfosByTagLiveData("download").observe(this){
|
||||
activeDownloadCount = 0
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import android.media.MediaScannerConnection
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.DocumentsContract
|
||||
import android.util.Log
|
||||
import android.webkit.MimeTypeMap
|
||||
|
|
@ -21,7 +22,7 @@ import kotlin.math.log10
|
|||
import kotlin.math.pow
|
||||
|
||||
|
||||
class FileUtil() {
|
||||
object FileUtil {
|
||||
fun deleteFile(path: String){
|
||||
val file = File(path)
|
||||
if (file.exists()) {
|
||||
|
|
@ -144,13 +145,26 @@ class FileUtil() {
|
|||
|
||||
fun getLogFile(context: Context, item: DownloadItem) : File {
|
||||
val titleRegex = Regex("[^A-Za-z\\d ]")
|
||||
return File(context.filesDir.absolutePath + """/logs/${item.id} - ${titleRegex.replace(item.title, "").take(150)}##${item.type}##${item.format.format_id}.log""")
|
||||
val title = item.title.ifEmpty { item.url }
|
||||
return File(context.filesDir.absolutePath + """/logs/${item.id} - ${titleRegex.replace(title, "").take(150)}##${item.type}##${item.format.format_id}.log""")
|
||||
}
|
||||
fun getLogFileForTerminal(context: Context, command: String) : File {
|
||||
val titleRegex = Regex("[^A-Za-z\\d ]")
|
||||
return File(context.filesDir.absolutePath + """/logs/Terminal - ${titleRegex.replace(command.take(30), "")}##terminal.log""")
|
||||
}
|
||||
|
||||
fun getDefautAudioPath() : String{
|
||||
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath + File.separator + "YTDLnis/Audio"
|
||||
}
|
||||
|
||||
fun getDefautVideoPath() : String{
|
||||
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath + File.separator + "YTDLnis/Video"
|
||||
}
|
||||
|
||||
fun getDefaultCommandPath() : String {
|
||||
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath + File.separator + "YTDLnis/Command"
|
||||
}
|
||||
|
||||
fun convertFileSize(s: Long): String{
|
||||
if (s <= 0) return "?"
|
||||
val units = arrayOf("B", "kB", "MB", "GB", "TB")
|
||||
|
|
|
|||
|
|
@ -9,9 +9,11 @@ import android.widget.Toast
|
|||
import androidx.core.text.HtmlCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.ChapterItem
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||
import org.json.JSONArray
|
||||
|
|
@ -20,6 +22,7 @@ import org.json.JSONObject
|
|||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.lang.reflect.Type
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
|
|
@ -272,7 +275,9 @@ class InfoUtil(private val context: Context) {
|
|||
thumb,
|
||||
"youtube",
|
||||
"",
|
||||
ArrayList()
|
||||
ArrayList(),
|
||||
"",
|
||||
ArrayList()
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.toString())
|
||||
|
|
@ -326,7 +331,9 @@ class InfoUtil(private val context: Context) {
|
|||
thumb,
|
||||
"youtube",
|
||||
"",
|
||||
formats
|
||||
formats,
|
||||
"",
|
||||
ArrayList()
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.toString())
|
||||
|
|
@ -337,13 +344,8 @@ class InfoUtil(private val context: Context) {
|
|||
private fun createVideoFromPipedJSON(obj: JSONObject, id: String): ResultItem? {
|
||||
var video: ResultItem? = null
|
||||
try {
|
||||
val title = obj.getString("title").toString()
|
||||
title.replace("'s", "'")
|
||||
title.replace("&", "&")
|
||||
val author = obj.getString("uploader").toString()
|
||||
author.replace("'s", "'")
|
||||
author.replace("&", "&")
|
||||
|
||||
val title = Html.fromHtml(obj.getString("title").toString()).toString()
|
||||
val author = Html.fromHtml(obj.getString("uploader").toString()).toString()
|
||||
if (author.isBlank()) throw Exception()
|
||||
|
||||
val duration = formatIntegerDuration(obj.getInt("duration"), Locale.getDefault())
|
||||
|
|
@ -360,7 +362,6 @@ class InfoUtil(private val context: Context) {
|
|||
formatObj.acodec = format.getString("codec")
|
||||
val streamURL = format.getString("url")
|
||||
formatObj.format_id = streamURL.substringAfter("itag=").substringBefore("&")
|
||||
formatObj.filesize = (format.getInt("bitrate") / 8 * obj.getInt("duration")).toLong()
|
||||
formatObj.asr = format.getString("quality")
|
||||
if (! format.getString("audioTrackName").equals("null", ignoreCase = true)){
|
||||
formatObj.format_note = format.getString("audioTrackName") + " Audio, " + formatObj.format_note
|
||||
|
|
@ -385,7 +386,6 @@ class InfoUtil(private val context: Context) {
|
|||
formatObj.vcodec = format.getString("codec")
|
||||
val streamURL = format.getString("url")
|
||||
formatObj.format_id = streamURL.substringAfter("itag=").substringBefore("&")
|
||||
formatObj.filesize = (format.getInt("bitrate") / 8 * obj.getInt("duration")).toLong()
|
||||
}catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
|
@ -394,6 +394,17 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
formats.sortBy { it.filesize }
|
||||
|
||||
val chapters = ArrayList<ChapterItem>()
|
||||
if (obj.has("chapters") && obj.getJSONArray("chapters").length() > 0){
|
||||
val chaptersJArray = obj.getJSONArray("chapters")
|
||||
for (c in 0 until chaptersJArray.length()){
|
||||
val chapter = chaptersJArray.getJSONObject(c)
|
||||
val end = if (c == chaptersJArray.length() - 1) obj.getInt("duration") else chaptersJArray.getJSONObject(c+1).getInt("start")
|
||||
val item = ChapterItem(chapter.getInt("start").toLong(), end.toLong(), chapter.getString("title"))
|
||||
chapters.add(item)
|
||||
}
|
||||
}
|
||||
|
||||
video = ResultItem(0,
|
||||
url,
|
||||
title,
|
||||
|
|
@ -402,7 +413,9 @@ class InfoUtil(private val context: Context) {
|
|||
thumb,
|
||||
"youtube",
|
||||
"",
|
||||
formats
|
||||
formats,
|
||||
if (obj.has("hls")) obj.getString("hls") else "",
|
||||
chapters
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.toString())
|
||||
|
|
@ -567,7 +580,7 @@ class InfoUtil(private val context: Context) {
|
|||
return query!!
|
||||
}
|
||||
|
||||
fun getFormats(url: String) : ResultItem {
|
||||
fun getFormats(url: String) : List<Format> {
|
||||
init()
|
||||
val p = Pattern.compile("^(https?)://(www.)?youtu(.be)?")
|
||||
val m = p.matcher(url)
|
||||
|
|
@ -576,14 +589,70 @@ class InfoUtil(private val context: Context) {
|
|||
val id = getIDFromYoutubeURL(url)
|
||||
val res = genericRequest(pipedURL + "streams/" + id)
|
||||
if (res.length() == 0) getFromYTDL(url)[0]!!
|
||||
else createVideoFromPipedJSON(
|
||||
res, id
|
||||
)!!
|
||||
val item = createVideoFromPipedJSON(res, id)
|
||||
item!!.formats
|
||||
}else{
|
||||
getFromYTDL(url)[0]!!
|
||||
getFormatsFromYTDL(url)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFormatsFromYTDL(url: String) : List<Format> {
|
||||
try {
|
||||
val request = YoutubeDLRequest(url)
|
||||
request.addOption("--print", "%(formats)s")
|
||||
request.addOption("--skip-download")
|
||||
request.addOption("-R", "1")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()){
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
}
|
||||
|
||||
val proxy = sharedPreferences.getString("proxy", "")
|
||||
if (proxy!!.isNotBlank()){
|
||||
request.addOption("--proxy", proxy)
|
||||
}
|
||||
|
||||
val res = YoutubeDL.getInstance().execute(request)
|
||||
val results: Array<String?> = try {
|
||||
val lineSeparator = System.getProperty("line.separator")
|
||||
res.out.split(lineSeparator!!).toTypedArray()
|
||||
} catch (e: Exception) {
|
||||
arrayOf(res.out)
|
||||
}
|
||||
val json = results[0]
|
||||
val jsonArray = JSONArray(json)
|
||||
|
||||
val formats : ArrayList<Format> = ArrayList()
|
||||
for (f in 0 until jsonArray.length()){
|
||||
val format = jsonArray.getJSONObject(f)
|
||||
if (format.has("filesize") && format.get("filesize") == "None"){
|
||||
format.remove("filesize")
|
||||
format.put("filesize", 0)
|
||||
}
|
||||
val formatProper = Gson().fromJson(format.toString(), Format::class.java)
|
||||
if (format.has("format_note")){
|
||||
if (!formatProper!!.format_note.contains("audio only", true)) {
|
||||
formatProper.format_note = format.getString("format_note")
|
||||
}else{
|
||||
formatProper.format_note = "${format.getString("format_note")} audio"
|
||||
}
|
||||
}
|
||||
if (formatProper!!.format_note == "storyboard") continue
|
||||
formatProper.container = format.getString("ext")
|
||||
formats.add(formatProper)
|
||||
}
|
||||
|
||||
return formats
|
||||
} catch (e: Exception) {
|
||||
Looper.prepare().run {
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
e.printStackTrace()
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
fun getFormatsMultiple(urls: List<String>, progress: (progress: List<Format>) -> Unit){
|
||||
init()
|
||||
val urlsFile = File(context.cacheDir, "urls.txt")
|
||||
|
|
@ -623,16 +692,19 @@ class InfoUtil(private val context: Context) {
|
|||
try{
|
||||
if (format.getString("filesize") == "None") continue
|
||||
}catch (e: Exception) { continue }
|
||||
val formatProper = Gson().fromJson(format.toString(), Format::class.java)
|
||||
if (formatProper.filesize > 0){
|
||||
if ( !formatProper!!.format_note!!.contains("audio only", true)) {
|
||||
formatProper.format_note = format.getString("format_note")
|
||||
}else{
|
||||
formatProper.format_note = "${format.getString("format_note")} audio"
|
||||
}
|
||||
formatProper.container = format.getString("ext")
|
||||
formats.add(formatProper)
|
||||
if (format.has("filesize") && format.get("filesize") == "None"){
|
||||
format.remove("filesize")
|
||||
format.put("filesize", 0)
|
||||
}
|
||||
val formatProper = Gson().fromJson(format.toString(), Format::class.java)
|
||||
if ( !formatProper!!.format_note.contains("audio only", true)) {
|
||||
formatProper.format_note = format.getString("format_note")
|
||||
}else{
|
||||
formatProper.format_note = "${format.getString("format_note")} audio"
|
||||
}
|
||||
if (formatProper.format_note == "storyboard") continue
|
||||
formatProper.container = format.getString("ext")
|
||||
formats.add(formatProper)
|
||||
}
|
||||
progress(formats)
|
||||
}catch (e: Exception){
|
||||
|
|
@ -725,20 +797,28 @@ class InfoUtil(private val context: Context) {
|
|||
if (formatsInJSON != null) {
|
||||
for (f in 0 until formatsInJSON.length()){
|
||||
val format = formatsInJSON.getJSONObject(f)
|
||||
val formatProper = Gson().fromJson(format.toString(), Format::class.java)
|
||||
if (formatProper.filesize > 0){
|
||||
if (format.has("format_note") && formatProper.format_note != null){
|
||||
if (!formatProper!!.format_note.contains("audio only", true)) {
|
||||
formatProper.format_note = format.getString("format_note")
|
||||
}else{
|
||||
formatProper.format_note = "${format.getString("format_note")} audio"
|
||||
}
|
||||
}
|
||||
formatProper.container = format.getString("ext")
|
||||
formats.add(formatProper)
|
||||
if (format.has("filesize") && format.get("filesize") == "None"){
|
||||
format.remove("filesize")
|
||||
format.put("filesize", 0)
|
||||
}
|
||||
val formatProper = Gson().fromJson(format.toString(), Format::class.java)
|
||||
if (format.has("format_note") && formatProper.format_note != null){
|
||||
if (!formatProper!!.format_note.contains("audio only", true)) {
|
||||
formatProper.format_note = format.getString("format_note")
|
||||
}else{
|
||||
formatProper.format_note = "${format.getString("format_note")} audio"
|
||||
}
|
||||
}
|
||||
if (formatProper.format_note == "storyboard") continue
|
||||
formatProper.container = format.getString("ext")
|
||||
formats.add(formatProper)
|
||||
}
|
||||
}
|
||||
|
||||
val chaptersInJSON = if (jsonObject.has("formats") && jsonObject.get("formats") is JSONArray) jsonObject.getJSONArray("formats") else null
|
||||
val listType: Type = object : TypeToken<List<ChapterItem>>() {}.type
|
||||
val chapters : ArrayList<ChapterItem> = Gson().fromJson(chaptersInJSON?.toString(), listType)
|
||||
|
||||
Log.e("aa", formats.toString())
|
||||
items.add(ResultItem(0,
|
||||
url,
|
||||
|
|
@ -748,7 +828,9 @@ class InfoUtil(private val context: Context) {
|
|||
thumb!!,
|
||||
website,
|
||||
playlistTitle!!,
|
||||
formats
|
||||
formats,
|
||||
jsonObject.getString("urls") ?: "",
|
||||
chapters
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -821,6 +903,8 @@ class InfoUtil(private val context: Context) {
|
|||
jsonObject.getString("extractor"),
|
||||
if (isPlaylist) jsonObject.getString("title") else "",
|
||||
arrayListOf(),
|
||||
"",
|
||||
arrayListOf(),
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
|
|
@ -945,7 +1029,7 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
companion object {
|
||||
private const val TAG = "API MANAGER"
|
||||
private const val invidousURL = "https://invidious.nerdvpn.de/api/v1/"
|
||||
private const val invidousURL = "https://invidious.baczek.me/api/v1/"
|
||||
private const val pipedURL = "https://pipedapi.kavin.rocks/"
|
||||
private var countryCODE: String = ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ import kotlinx.coroutines.withContext
|
|||
import java.io.File
|
||||
import java.util.Calendar
|
||||
|
||||
class UiUtil(private val fileUtil: FileUtil) {
|
||||
class UiUtil() {
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun populateFormatCard(formatCard : MaterialCardView, chosenFormat: Format, audioFormats: List<Format>?){
|
||||
formatCard.findViewById<TextView>(R.id.container).text = chosenFormat.container.uppercase()
|
||||
|
|
@ -79,7 +79,7 @@ class UiUtil(private val fileUtil: FileUtil) {
|
|||
}
|
||||
var filesize = chosenFormat.filesize
|
||||
if (!audioFormats.isNullOrEmpty()) filesize += audioFormats.sumOf { it.filesize }
|
||||
formatCard.findViewById<TextView>(R.id.file_size).text = fileUtil.convertFileSize(filesize)
|
||||
formatCard.findViewById<TextView>(R.id.file_size).text = FileUtil.convertFileSize(filesize)
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ class UiUtil(private val fileUtil: FileUtil) {
|
|||
}
|
||||
}
|
||||
|
||||
commandTemplateViewModel.shortcuts.observe(lifeCycle){ it ->
|
||||
commandTemplateViewModel.shortcuts.observe(lifeCycle){
|
||||
shortcutsChipGroup.removeAllViews()
|
||||
it.forEach {shortcut ->
|
||||
val chip = context.layoutInflater.inflate(R.layout.suggestion_chip, shortcutsChipGroup, false) as Chip
|
||||
|
|
@ -200,7 +200,7 @@ class UiUtil(private val fileUtil: FileUtil) {
|
|||
title.isEndIconVisible = false
|
||||
}
|
||||
|
||||
commandTemplateViewModel.shortcuts.observe(lifeCycle){ it ->
|
||||
commandTemplateViewModel.shortcuts.observe(lifeCycle){
|
||||
shortcutsChipGroup.removeAllViews()
|
||||
it.forEach {shortcut ->
|
||||
val chip = context.layoutInflater.inflate(R.layout.input_chip, shortcutsChipGroup, false) as Chip
|
||||
|
|
@ -324,6 +324,7 @@ class UiUtil(private val fileUtil: FileUtil) {
|
|||
bottomSheet.setContentView(R.layout.format_details_sheet)
|
||||
|
||||
val formatIdParent = bottomSheet.findViewById<LinearLayout>(R.id.format_id_parent)
|
||||
val formatURLParent = bottomSheet.findViewById<LinearLayout>(R.id.format_url_parent)
|
||||
val containerParent = bottomSheet.findViewById<LinearLayout>(R.id.container_parent)
|
||||
val codecParent = bottomSheet.findViewById<LinearLayout>(R.id.codec_parent)
|
||||
val filesizeParent = bottomSheet.findViewById<LinearLayout>(R.id.filesize_parent)
|
||||
|
|
@ -339,6 +340,14 @@ class UiUtil(private val fileUtil: FileUtil) {
|
|||
}
|
||||
}
|
||||
|
||||
if (format.url.isNullOrBlank()) formatURLParent?.visibility = View.GONE
|
||||
else {
|
||||
formatURLParent?.findViewById<TextView>(R.id.format_url_value)?.text = format.url
|
||||
formatURLParent?.setOnClickListener {
|
||||
copyToClipboard(format.url!!, activity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (format.container.isBlank()) containerParent?.visibility = View.GONE
|
||||
else {
|
||||
|
|
@ -367,9 +376,9 @@ class UiUtil(private val fileUtil: FileUtil) {
|
|||
|
||||
if (format.filesize != 0L) filesizeParent?.visibility = View.GONE
|
||||
else {
|
||||
filesizeParent?.findViewById<TextView>(R.id.filesize_value)?.text = fileUtil.convertFileSize(format.filesize)
|
||||
filesizeParent?.findViewById<TextView>(R.id.filesize_value)?.text = FileUtil.convertFileSize(format.filesize)
|
||||
filesizeParent?.setOnClickListener {
|
||||
copyToClipboard(fileUtil.convertFileSize(format.filesize), activity)
|
||||
copyToClipboard(FileUtil.convertFileSize(format.filesize), activity)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ class DownloadWorker(
|
|||
if (itemId == 0L) return Result.failure()
|
||||
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val fileUtil = FileUtil()
|
||||
val infoUtil = InfoUtil(context)
|
||||
val dbManager = DBManager.getInstance(context)
|
||||
val dao = dbManager.downloadDao
|
||||
|
|
@ -68,13 +67,9 @@ class DownloadWorker(
|
|||
}
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
if (sharedPreferences.getBoolean("log_downloads", false)){
|
||||
updateDownloadItem(downloadItem, infoUtil, dao, resultDao, true, notificationUtil)
|
||||
}else{
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
//update item if its incomplete
|
||||
updateDownloadItem(downloadItem, infoUtil, dao, resultDao, false, notificationUtil)
|
||||
}
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
//update item if its incomplete
|
||||
updateDownloadItem(downloadItem, infoUtil, dao, resultDao, false, notificationUtil)
|
||||
}
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
|
|
@ -174,13 +169,13 @@ class DownloadWorker(
|
|||
if (audioQualityId.isBlank() || audioQualityId == "0" || audioQualityId == context.getString(R.string.best_quality) || audioQualityId == "best") audioQualityId = ""
|
||||
else if (audioQualityId == context.getString(R.string.worst_quality) || audioQualityId == "worst") audioQualityId = "worstaudio"
|
||||
|
||||
val ext = downloadItem.format.container
|
||||
val ext = downloadItem.container
|
||||
if (audioQualityId.isNotBlank()) request.addOption("-f", audioQualityId)
|
||||
request.addOption("-x")
|
||||
|
||||
if(ext.isNotBlank()){
|
||||
if(!ext.matches("(webm)|(Default)|(${context.getString(R.string.defaultValue)})".toRegex())){
|
||||
request.addOption("--audio-format", downloadItem.format.container)
|
||||
request.addOption("--audio-format", ext)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -246,10 +241,10 @@ class DownloadWorker(
|
|||
}
|
||||
Log.e(TAG, formatArgument)
|
||||
request.addOption("-f", formatArgument)
|
||||
val format = downloadItem.format.container
|
||||
if(format.isNotEmpty() && format != "Default" && format != context.getString(R.string.defaultValue)){
|
||||
request.addOption("--merge-output-format", format.lowercase())
|
||||
if (format != "webm") {
|
||||
val outputFormat = downloadItem.container
|
||||
if(outputFormat.isNotEmpty() && outputFormat != "Default" && outputFormat != context.getString(R.string.defaultValue)){
|
||||
request.addOption("--merge-output-format", outputFormat.lowercase())
|
||||
if (outputFormat != "webm") {
|
||||
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
||||
if (embedThumb) {
|
||||
request.addOption("--embed-thumbnail")
|
||||
|
|
@ -293,7 +288,7 @@ class DownloadWorker(
|
|||
|
||||
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
|
||||
val logFolder = File(context.filesDir.absolutePath + "/logs")
|
||||
val logFile = fileUtil.getLogFile(context, downloadItem)
|
||||
val logFile = FileUtil.getLogFile(context, downloadItem)
|
||||
|
||||
if (logDownloads){
|
||||
logFolder.mkdirs()
|
||||
|
|
@ -320,11 +315,11 @@ class DownloadWorker(
|
|||
}
|
||||
}.onSuccess {
|
||||
//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, "log" to logDownloads))
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
|
||||
var finalPath : String?
|
||||
try {
|
||||
finalPath = fileUtil.moveFile(tempFileDir.absoluteFile,context, downloadLocation, keepCache){ p ->
|
||||
setProgressAsync(workDataOf("progress" to p, "output" to "Moving file to ${fileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
|
||||
finalPath = FileUtil.moveFile(tempFileDir.absoluteFile,context, downloadLocation, keepCache){ p ->
|
||||
setProgressAsync(workDataOf("progress" to p, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
|
||||
}
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moved file to $finalPath", "id" to downloadItem.id, "log" to logDownloads))
|
||||
}catch (e: Exception){
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ class TerminalDownloadWorker(
|
|||
if (command!!.isEmpty()) return Result.failure()
|
||||
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val fileUtil = FileUtil()
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
|
|
@ -68,7 +67,7 @@ class TerminalDownloadWorker(
|
|||
|
||||
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
|
||||
val logFolder = File(context.filesDir.absolutePath + "/logs")
|
||||
val logFile = fileUtil.getLogFileForTerminal(context, command)
|
||||
val logFile = FileUtil.getLogFileForTerminal(context, command)
|
||||
|
||||
runCatching {
|
||||
if (logDownloads){
|
||||
|
|
@ -94,7 +93,7 @@ class TerminalDownloadWorker(
|
|||
}.onSuccess {
|
||||
//move file from internal to set download directory
|
||||
try {
|
||||
fileUtil.moveFile(tempFileDir.absoluteFile,context, downloadLocation!!, false){ p ->
|
||||
FileUtil.moveFile(tempFileDir.absoluteFile,context, downloadLocation!!, false){ p ->
|
||||
setProgressAsync(workDataOf("progress" to p))
|
||||
}
|
||||
}catch (e: Exception){
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context="com.deniscerri.ytdlnis.ui.more.settings.SettingsActivity">
|
||||
|
||||
|
|
|
|||
|
|
@ -1,217 +1,254 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/format"
|
||||
android:textSize="12sp"
|
||||
android:layout_margin="20dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/format_id_parent"
|
||||
android:layout_width="match_parent"
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:weightSum="100"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:text="@string/format_id"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/format"
|
||||
android:textSize="12sp"
|
||||
android:layout_margin="20dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/format_id_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/format_id_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:weightSum="100"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:text="@string/format_id"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/format_id_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/format_url_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:weightSum="100"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:text="@string/url"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/format_url_value"
|
||||
android:layout_width="0dp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/container_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/container"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/container_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/codec_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/codec"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/codec_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/filesize_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:text="@string/file_size"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/filesize_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/format_note_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:text="@string/quality"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/format_note_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/fps_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:text="FPS"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fps_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/asr_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:text="@string/audio_samplerate"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/asr_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/container_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/container"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/container_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/codec_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/codec"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/codec_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/filesize_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:text="@string/file_size"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/filesize_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/format_note_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:text="@string/quality"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/format_note_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/fps_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:text="FPS"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fps_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/asr_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:weightSum="100"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:text="@string/audio_samplerate"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/asr_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="50"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="10dp"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
|
@ -271,4 +271,6 @@
|
|||
<string name="swipe_gestures_summary">Swipe items for certain actions</string>
|
||||
<string name="crop_thumb">Crop Thumbnail</string>
|
||||
<string name="crop_thumb_summary">Crop the thumbnail into a square for audio downloads</string>
|
||||
<string name="locale">Locale</string>
|
||||
<string name="audio_only_item">This item only contains audio formats</string>
|
||||
</resources>
|
||||
|
|
@ -5,19 +5,16 @@
|
|||
<Preference
|
||||
app:icon="@drawable/ic_music_downloaded"
|
||||
app:key="music_path"
|
||||
app:defaultValue="@string/music_path"
|
||||
app:title="@string/music_directory" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_video_downloaded"
|
||||
app:key="video_path"
|
||||
app:defaultValue="@string/video_path"
|
||||
app:title="@string/video_directory" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_terminal"
|
||||
app:key="command_path"
|
||||
app:defaultValue="@string/command_path"
|
||||
app:title="@string/command_directory" />
|
||||
|
||||
<Preference
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory android:title="Locale">
|
||||
<PreferenceCategory android:title="@string/locale">
|
||||
<ListPreference
|
||||
android:entries="@array/language_values"
|
||||
android:entryValues="@array/language_values"
|
||||
|
|
|
|||
Loading…
Reference in a new issue