add showing available subtitles when configuring subtitles

This commit is contained in:
deniscerri 2025-06-22 19:23:27 +02:00
parent 82365bc920
commit 900728ac28
No known key found for this signature in database
GPG key ID: 95C43D517D830350
27 changed files with 954 additions and 64 deletions

View file

@ -11,8 +11,8 @@ plugins {
def properties = new Properties()
def versionMajor = 1
def versionMinor = 8
def versionPatch = 4
def versionBuild = 1 // bump for dogfood builds, public betas, etc.
def versionPatch = 5
def versionBuild = 0 // bump for dogfood builds, public betas, etc.
def isBeta = true
def versionExt = ""
@ -175,6 +175,7 @@ dependencies {
implementation("androidx.cardview:cardview:1.0.0")
implementation("com.squareup.picasso:picasso:2.71828")
implementation("jp.wasabeef:picasso-transformations:2.4.0")
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.3.0'

View file

@ -0,0 +1,780 @@
{
"formatVersion": 1,
"database": {
"version": 23,
"identityHash": "c154a34aea99b9cbcfcc1dbb3763d314",
"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, `playlistURL` TEXT DEFAULT '', `playlistIndex` INTEGER, `creationTime` INTEGER NOT NULL, `availableSubtitles` TEXT NOT NULL DEFAULT '[]')",
"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": "playlistURL",
"columnName": "playlistURL",
"affinity": "TEXT",
"notNull": false,
"defaultValue": "''"
},
{
"fieldPath": "playlistIndex",
"columnName": "playlistIndex",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "creationTime",
"columnName": "creationTime",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "availableSubtitles",
"columnName": "availableSubtitles",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'[]'"
}
],
"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, `filesize` INTEGER NOT NULL DEFAULT 0, `downloadId` INTEGER NOT NULL DEFAULT 0, `command` TEXT NOT NULL DEFAULT '')",
"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": "filesize",
"columnName": "filesize",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "downloadId",
"columnName": "downloadId",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "command",
"columnName": "command",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
}
],
"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, `extraCommands` TEXT NOT NULL DEFAULT '', `customFileNameTemplate` TEXT NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `downloadStartTime` INTEGER NOT NULL DEFAULT 0, `logID` INTEGER, `playlistURL` TEXT DEFAULT '', `playlistIndex` INTEGER, `incognito` INTEGER NOT NULL DEFAULT 0, `availableSubtitles` TEXT NOT NULL DEFAULT '[]')",
"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": "extraCommands",
"columnName": "extraCommands",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"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"
},
{
"fieldPath": "logID",
"columnName": "logID",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "playlistURL",
"columnName": "playlistURL",
"affinity": "TEXT",
"notNull": false,
"defaultValue": "''"
},
{
"fieldPath": "playlistIndex",
"columnName": "playlistIndex",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "incognito",
"columnName": "incognito",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "availableSubtitles",
"columnName": "availableSubtitles",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'[]'"
}
],
"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, `useAsExtraCommand` INTEGER NOT NULL DEFAULT 0, `useAsExtraCommandAudio` INTEGER NOT NULL DEFAULT 1, `useAsExtraCommandVideo` INTEGER NOT NULL DEFAULT 1, `useAsExtraCommandDataFetching` INTEGER NOT NULL DEFAULT 0, `preferredCommandTemplate` INTEGER NOT NULL DEFAULT 0, `urlRegex` 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
},
{
"fieldPath": "useAsExtraCommand",
"columnName": "useAsExtraCommand",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "useAsExtraCommandAudio",
"columnName": "useAsExtraCommandAudio",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "1"
},
{
"fieldPath": "useAsExtraCommandVideo",
"columnName": "useAsExtraCommandVideo",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "1"
},
{
"fieldPath": "useAsExtraCommandDataFetching",
"columnName": "useAsExtraCommandDataFetching",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "preferredCommandTemplate",
"columnName": "preferredCommandTemplate",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "urlRegex",
"columnName": "urlRegex",
"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": []
},
{
"tableName": "logs",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadType` TEXT NOT NULL, `downloadTime` INTEGER 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
},
{
"fieldPath": "format",
"columnName": "format",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadType",
"columnName": "downloadType",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadTime",
"columnName": "downloadTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "terminalDownloads",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `command` TEXT NOT NULL, `log` TEXT DEFAULT '')",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "command",
"columnName": "command",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "log",
"columnName": "log",
"affinity": "TEXT",
"notNull": false,
"defaultValue": "''"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "sources",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, `downloadItemTemplate` TEXT NOT NULL, `everyNr` INTEGER NOT NULL, `everyCategory` TEXT NOT NULL, `everyTime` INTEGER NOT NULL, `weeklyConfig` TEXT, `monthlyConfig` TEXT, `status` TEXT NOT NULL, `startsTime` INTEGER NOT NULL, `endsDate` INTEGER NOT NULL DEFAULT 0, `endsAfterCount` INTEGER NOT NULL DEFAULT 0, `runCount` INTEGER NOT NULL DEFAULT 0, `getOnlyNewUploads` INTEGER NOT NULL DEFAULT 0, `retryMissingDownloads` INTEGER NOT NULL, `ignoredLinks` TEXT NOT NULL DEFAULT '[]', `alreadyProcessedLinks` TEXT NOT NULL, `syncWithSource` INTEGER NOT NULL DEFAULT 0)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadItemTemplate",
"columnName": "downloadItemTemplate",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "everyNr",
"columnName": "everyNr",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "everyCategory",
"columnName": "everyCategory",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "everyTime",
"columnName": "everyTime",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "weeklyConfig",
"columnName": "weeklyConfig",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "monthlyConfig",
"columnName": "monthlyConfig",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "status",
"columnName": "status",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "startsTime",
"columnName": "startsTime",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "endsDate",
"columnName": "endsDate",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "endsAfterCount",
"columnName": "endsAfterCount",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "runCount",
"columnName": "runCount",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "getOnlyNewUploads",
"columnName": "getOnlyNewUploads",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "retryMissingDownloads",
"columnName": "retryMissingDownloads",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "ignoredLinks",
"columnName": "ignoredLinks",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'[]'"
},
{
"fieldPath": "alreadyProcessedLinks",
"columnName": "alreadyProcessedLinks",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "syncWithSource",
"columnName": "syncWithSource",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
}
],
"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, 'c154a34aea99b9cbcfcc1dbb3763d314')"
]
}
}

View file

@ -41,7 +41,7 @@ import com.deniscerri.ytdl.database.models.TerminalItem
TerminalItem::class,
ObserveSourcesItem::class
],
version = 22,
version = 23,
autoMigrations = [
AutoMigration (from = 1, to = 2),
AutoMigration (from = 2, to = 3),
@ -64,6 +64,7 @@ import com.deniscerri.ytdl.database.models.TerminalItem
AutoMigration (from = 19, to = 20),
//AutoMigration (from = 20, to = 21) MANUALLY HANDLED
//AutoMigration(from = 21, to = 22) MANUALLY HANDLED
//AutoMigration(from = 22, to = 23) MANUALLY HANDLED
]
)
abstract class DBManager : RoomDatabase(){

View file

@ -51,6 +51,15 @@ object Migrations {
// Add `urlRegex` as a JSON string (since lists are not supported in SQLite)
database.execSQL("ALTER TABLE commandTemplates ADD COLUMN urlRegex TEXT NOT NULL DEFAULT '[]'")
},
//add available subtitles list in result and download item
Migration(22, 23) { database ->
//add available subtitles for result item
database.execSQL("ALTER TABLE results ADD COLUMN availableSubtitles TEXT NOT NULL DEFAULT '[]'")
//add available subtitles for download item
database.execSQL("ALTER TABLE downloads ADD COLUMN availableSubtitles TEXT NOT NULL DEFAULT '[]'")
}
)

View file

@ -44,5 +44,7 @@ data class DownloadItem(
@ColumnInfo(defaultValue = "")
var playlistIndex: Int? = null,
@ColumnInfo(defaultValue = "0")
var incognito: Boolean = false
var incognito: Boolean = false,
@ColumnInfo(defaultValue = "[]")
var availableSubtitles: List<String> = listOf()
) : Parcelable

View file

@ -27,4 +27,6 @@ data class ResultItem(
@ColumnInfo(defaultValue = "")
var playlistIndex: Int? = null,
var creationTime: Long = System.currentTimeMillis() / 1000,
@ColumnInfo(defaultValue = "[]")
var availableSubtitles: List<String> = listOf()
) : Parcelable

View file

@ -345,7 +345,8 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
null,
playlistURL = resultItem.playlistURL,
playlistIndex = resultItem.playlistIndex,
incognito = sharedPreferences.getBoolean("incognito", false)
incognito = sharedPreferences.getBoolean("incognito", false),
availableSubtitles = resultItem.availableSubtitles
)
}

View file

@ -22,6 +22,7 @@ import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.util.Extensions.dp
import com.deniscerri.ytdl.util.Extensions.loadBlurryThumbnail
import com.deniscerri.ytdl.util.Extensions.loadThumbnail
import com.deniscerri.ytdl.util.FileUtil
import com.google.android.material.button.MaterialButton
@ -66,7 +67,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
// THUMBNAIL ----------------------------------
val hideThumb = sharedPreferences.getStringSet("hide_thumbnails", emptySet())!!.contains("queue")
uiHandler.post { thumbnail.loadThumbnail(hideThumb, item.thumb) }
uiHandler.post { thumbnail.loadBlurryThumbnail(activity, hideThumb, item.thumb) }
// PROGRESS BAR ----------------------------------------------------
val progressBar = card.findViewById<LinearProgressIndicator>(R.id.progress)

View file

@ -31,7 +31,7 @@ class ProcessingSettingsFragment : BaseSettingsFragment() {
subtitleLanguages?.summary = prefs.getString("subs_lang", "en.*,.*-orig")!!
subtitleLanguages?.setOnPreferenceClickListener {
UiUtil.showSubtitleLanguagesDialog(requireActivity(), prefs.getString("subs_lang", "en.*,.*-orig")!!){
UiUtil.showSubtitleLanguagesDialog(requireActivity(), listOf(), prefs.getString("subs_lang", "en.*,.*-orig")!!){
editor.putString("subs_lang", it)
editor.apply()
subtitleLanguages.summary = it

View file

@ -52,6 +52,7 @@ import com.neoutils.highlight.core.util.UiColor
import com.neoutils.highlight.view.extension.toSpannedString
import com.neoutils.highlight.view.text.HighlightTextWatcher
import com.squareup.picasso.Picasso
import jp.wasabeef.picasso.transformations.BlurTransformation
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@ -64,7 +65,6 @@ import java.util.Calendar
import java.util.Locale
import java.util.regex.Pattern
import kotlin.math.abs
import kotlin.math.pow
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.minutes
@ -314,6 +314,22 @@ object Extensions {
}
}
fun ImageView.loadBlurryThumbnail(context: Context, hideThumb: Boolean, imageURL: String) {
if(!hideThumb){
if (imageURL.isNotEmpty()) {
Picasso.get()
.load(imageURL)
.resize(1280, 0)
.transform(BlurTransformation(context, 10, 1))
.onlyScaleDown()
.into(this)
} else {
Picasso.get().load(R.color.black).into(this)
}
}
}
fun List<DownloadRepository.Status>.toListString() : List<String>{
return this.map { it.toString() }
@ -554,7 +570,7 @@ object Extensions {
combine(flow2, flow3, ::Pair),
combine(flow4, flow5, ::Pair),
combine(flow6, flow7, ::Pair),
) { t1, t2, t3, t4, ->
) { t1, t2, t3, t4 ->
transform(
t1,
t2.first,

View file

@ -1067,7 +1067,7 @@ object UiUtil {
}
@SuppressLint("RestrictedApi")
fun showSubtitleLanguagesDialog(context: Activity, currentValue: String, ok: (newValue: String) -> Unit){
fun showSubtitleLanguagesDialog(context: Activity, availableSubtitles: List<String>, currentValue: String, ok: (newValue: String) -> Unit){
val builder = MaterialAlertDialogBuilder(context)
builder.setTitle(context.getString(R.string.subtitle_languages))
val view = context.layoutInflater.inflate(R.layout.subtitle_dialog, null)
@ -1093,8 +1093,6 @@ object UiUtil {
context.startActivity(browserIntent)
}
view.findViewById<View>(R.id.suggested).visibility = View.GONE
val dialog = builder.create()
dialog.show()
val imm = context.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
@ -1105,9 +1103,12 @@ object UiUtil {
//handle suggestion chips
CoroutineScope(Dispatchers.IO).launch {
val chipGroup = view.findViewById<ChipGroup>(R.id.subtitle_suggested_chipgroup)
val chips = mutableListOf<Chip>()
context.getStringArray(R.array.subtitle_langs).forEachIndexed { index, s ->
val suggestedLinearLayout = view.findViewById<LinearLayout>(R.id.suggestedLinear)
val suggestedChipGroup = view.findViewById<ChipGroup>(R.id.subtitle_suggested_chipgroup)
val allChipGroup = view.findViewById<ChipGroup>(R.id.subtitle_all_chipgroup)
fun buildChip(chipGroup: ChipGroup, s: String, index: Int) : Chip {
val tmp = context.layoutInflater.inflate(R.layout.filter_chip, chipGroup, false) as Chip
s.split("-", ".*").run {
if (s.endsWith(".*")) {
@ -1140,17 +1141,38 @@ object UiUtil {
}
}
chips.add(tmp)
return tmp
}
val suggestedChips = mutableListOf<Chip>()
val allChips = mutableListOf<Chip>()
//populate suggested
if (availableSubtitles.isNotEmpty()) {
suggestedLinearLayout.isVisible = true
availableSubtitles.forEachIndexed { index, s ->
suggestedChips.add(buildChip(suggestedChipGroup, s, index))
}
}
//populate all
context.getStringArray(R.array.subtitle_langs).filter { !availableSubtitles.contains(it) }.forEachIndexed { index, s ->
allChips.add(buildChip(allChipGroup, s, index))
}
withContext(Dispatchers.Main){
view.findViewById<View>(R.id.suggested).visibility = View.VISIBLE
chips.forEach {
suggestedChips.forEach {
it.isChecked = editText.text.split(",").any { it2 -> it2 == it.tag.toString() }
chipGroup!!.addView(it)
suggestedChipGroup!!.addView(it)
}
allChips.forEach {
it.isChecked = editText.text.split(",").any { it2 -> it2 == it.tag.toString() }
allChipGroup!!.addView(it)
}
editText.textChanged {
chipGroup.children.forEach { (it as Chip).isChecked = editText.text.split(",").any { it2 -> it2 == it.tag.toString() } }
suggestedChipGroup.children.forEach { (it as Chip).isChecked = editText.text.split(",").any { it2 -> it2 == it.tag.toString() } }
allChipGroup.children.forEach { (it as Chip).isChecked = editText.text.split(",").any { it2 -> it2 == it.tag.toString() } }
}
}
}
@ -1362,7 +1384,8 @@ object UiUtil {
""
}.ifEmpty { sharedPreferences.getString("subs_lang", "en.*,.*-orig")!! }
showSubtitleLanguagesDialog(context, currentSubtitleLang){
val availabeSubtitles = if (items.size == 1) items[0].availableSubtitles else listOf()
showSubtitleLanguagesDialog(context, availabeSubtitles, currentSubtitleLang){
subtitleLanguagesSet(it)
subtitleLanguagesDescription.text = it
}

View file

@ -87,10 +87,13 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
var extraCommands = commandTemplateDao.getAllTemplatesAsDataFetchingExtraCommands()
if (url != null) {
extraCommands = extraCommands.filter { it.urlRegex.any { u -> Regex(u).containsMatchIn(url) } }
extraCommands = if (url != null) {
extraCommands.filter {
it.urlRegex.any { u -> Regex(u).containsMatchIn(url) } ||
it.urlRegex.isEmpty()
}
}else{
extraCommands = extraCommands.filter { it.urlRegex.isEmpty() }
extraCommands.filter { it.urlRegex.isEmpty() }
}
if (extraCommands.isNotEmpty()){
@ -242,19 +245,28 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
playlistTitle = title
}
val availableSubtitles = mutableListOf<String>()
if (jsonObject.has("automatic_captions")) {
availableSubtitles.addAll(jsonObject.getJSONObject("automatic_captions").keys().asSequence().toList())
}
if (jsonObject.has("subtitles")) {
availableSubtitles.addAll(jsonObject.getJSONObject("subtitles").keys().asSequence().toList())
}
val res = ResultItem(0,
url,
title,
author,
duration,
thumb!!,
website,
playlistTitle,
formats,
urls,
chapters,
playlistURL,
playlistIndex
url = url,
title = title,
author = author,
duration = duration,
thumb = thumb!!,
website = website,
playlistTitle = playlistTitle,
formats = formats,
urls = urls,
chapters = chapters,
playlistURL = playlistURL,
playlistIndex = playlistIndex,
availableSubtitles = availableSubtitles
)
items.add(res)

View file

@ -141,6 +141,7 @@
android:ellipsize="end"
android:gravity="bottom"
android:maxLines="1"
android:textColor="#FFF"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:paddingBottom="5dp"

View file

@ -26,7 +26,7 @@
android:layout_height="wrap_content"
android:singleLine="false"
android:text="@string/command_templates"
android:textSize="25sp"
android:textSize="20sp"
android:maxLines="2"
android:layout_marginEnd="10dp"
app:layout_constraintHorizontal_bias="0.0"

View file

@ -30,7 +30,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/download"
android:textSize="25sp"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

View file

@ -35,7 +35,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/template"
android:textSize="25sp"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

View file

@ -56,7 +56,7 @@
android:layout_marginEnd="20dp"
android:singleLine="false"
android:text="@string/download"
android:textSize="25sp"
android:textSize="20sp"
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_schedule_button"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"

View file

@ -70,7 +70,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/download"
android:textSize="25sp"
android:textSize="20sp"
android:maxLines="2"
android:singleLine="false"
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_schedule_button"

View file

@ -26,7 +26,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Open_File"
android:textSize="25sp"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

View file

@ -31,7 +31,7 @@
android:layout_marginEnd="20dp"
android:singleLine="false"
android:text="@string/format"
android:textSize="25sp"
android:textSize="20sp"
app:layout_constraintEnd_toStartOf="@+id/format_buttons"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"

View file

@ -31,7 +31,7 @@
android:maxLines="2"
android:singleLine="false"
android:text="@string/observe_sources"
android:textSize="25sp"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

View file

@ -67,14 +67,12 @@
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/check_all"
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Primary"
android:layout_width="55dp"
app:elevation="0dp"
android:elevation="0dp"
app:borderWidth="0dp"
android:contentDescription="@string/select_all"
android:layout_height="55dp"
android:backgroundTint="@android:color/transparent"
app:layout_anchor="@id/bottomAppBar"
android:layout_marginHorizontal="5dp"
android:src="@drawable/ic_select_all"
@ -106,7 +104,7 @@
android:maxLines="2"
android:singleLine="false"
android:text="@string/select"
android:textSize="25sp"
android:textSize="20sp"
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_ok_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

View file

@ -24,8 +24,50 @@
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:id="@+id/suggestedLinear"
android:orientation="vertical"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:textColor="?attr/colorPrimary"
android:textStyle="bold"
android:paddingVertical="15dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/subtitle"
android:text="@string/suggested" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="170dp"
app:layout_constraintHeight_max="50dp"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/suggested">
<com.google.android.material.chip.ChipGroup
android:id="@+id/subtitle_suggested_chipgroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:chipSpacingVertical="-7dp"
app:chipSpacingHorizontal="5dp"
app:selectionRequired="false"
app:singleSelection="false">
</com.google.android.material.chip.ChipGroup>
</ScrollView>
</LinearLayout>
<TextView
android:id="@+id/suggested"
android:id="@+id/all_subs"
android:layout_width="match_parent"
android:textColor="?attr/colorPrimary"
android:textStyle="bold"
@ -34,7 +76,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/subtitle"
android:text="@string/suggested" />
android:text="@string/select" />
<ScrollView
android:layout_width="match_parent"
@ -43,18 +85,18 @@
app:layout_constraintVertical_bias="0.0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/suggested">
app:layout_constraintTop_toBottomOf="@id/all_subs">
<com.google.android.material.chip.ChipGroup
android:id="@+id/subtitle_suggested_chipgroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:chipSpacingVertical="-7dp"
app:chipSpacingHorizontal="5dp"
app:selectionRequired="false"
app:singleSelection="false">
<com.google.android.material.chip.ChipGroup
android:id="@+id/subtitle_all_chipgroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:chipSpacingVertical="-7dp"
app:chipSpacingHorizontal="5dp"
app:selectionRequired="false"
app:singleSelection="false">
</com.google.android.material.chip.ChipGroup>
</com.google.android.material.chip.ChipGroup>
</ScrollView>

View file

@ -25,7 +25,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/shortcuts"
android:textSize="25sp"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

View file

@ -25,7 +25,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/shortcuts"
android:textSize="25sp"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

View file

@ -35,7 +35,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/player_client"
android:textSize="25sp"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

View file

@ -21,17 +21,18 @@
android:orientation="horizontal"
android:paddingTop="20dp">
<TextView
android:id="@+id/bottom_sheet_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/ytdl_source"
android:textSize="25sp"
android:textSize="20sp"
app:layout_constraintEnd_toStartOf="@+id/add"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/bottom_sheet_subtitle"
android:layout_width="wrap_content"