diff --git a/app/build.gradle b/app/build.gradle index 36c96741..663980e3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' diff --git a/app/schemas/com.deniscerri.ytdl.database.DBManager/23.json b/app/schemas/com.deniscerri.ytdl.database.DBManager/23.json new file mode 100644 index 00000000..b1a7b3e6 --- /dev/null +++ b/app/schemas/com.deniscerri.ytdl.database.DBManager/23.json @@ -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')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/database/DBManager.kt b/app/src/main/java/com/deniscerri/ytdl/database/DBManager.kt index 36c00fd3..98acddca 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/DBManager.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/DBManager.kt @@ -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(){ diff --git a/app/src/main/java/com/deniscerri/ytdl/database/Migrations.kt b/app/src/main/java/com/deniscerri/ytdl/database/Migrations.kt index 98076fe9..d88cdc88 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/Migrations.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/Migrations.kt @@ -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 '[]'") } ) diff --git a/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItem.kt b/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItem.kt index 20615019..773f0c19 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItem.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItem.kt @@ -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 = listOf() ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/database/models/ResultItem.kt b/app/src/main/java/com/deniscerri/ytdl/database/models/ResultItem.kt index 68d119fa..5dfe6baa 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/models/ResultItem.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/models/ResultItem.kt @@ -27,4 +27,6 @@ data class ResultItem( @ColumnInfo(defaultValue = "") var playlistIndex: Int? = null, var creationTime: Long = System.currentTimeMillis() / 1000, + @ColumnInfo(defaultValue = "[]") + var availableSubtitles: List = listOf() ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt index 2ca3e8b5..f485258f 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt @@ -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 ) } diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadAdapter.kt index 3ca83745..a22bb89b 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadAdapter.kt @@ -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(R.id.progress) diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt index c8d9b81c..181e2b5a 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/ProcessingSettingsFragment.kt @@ -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 diff --git a/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt b/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt index c80a6489..54a9580f 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt @@ -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.toListString() : List{ 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, diff --git a/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt index f5229c0e..5560bb02 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/UiUtil.kt @@ -1067,7 +1067,7 @@ object UiUtil { } @SuppressLint("RestrictedApi") - fun showSubtitleLanguagesDialog(context: Activity, currentValue: String, ok: (newValue: String) -> Unit){ + fun showSubtitleLanguagesDialog(context: Activity, availableSubtitles: List, 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(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(R.id.subtitle_suggested_chipgroup) - val chips = mutableListOf() - context.getStringArray(R.array.subtitle_langs).forEachIndexed { index, s -> + val suggestedLinearLayout = view.findViewById(R.id.suggestedLinear) + val suggestedChipGroup = view.findViewById(R.id.subtitle_suggested_chipgroup) + + val allChipGroup = view.findViewById(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() + val allChips = mutableListOf() + + //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(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 } diff --git a/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt index ce3b7515..adcabb95 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/extractors/YTDLPUtil.kt @@ -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() + 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) diff --git a/app/src/main/res/layout/active_download_card.xml b/app/src/main/res/layout/active_download_card.xml index 7c0ab8b4..5ac74130 100644 --- a/app/src/main/res/layout/active_download_card.xml +++ b/app/src/main/res/layout/active_download_card.xml @@ -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" diff --git a/app/src/main/res/layout/command_template_list.xml b/app/src/main/res/layout/command_template_list.xml index 0f58ed49..97963d5c 100644 --- a/app/src/main/res/layout/command_template_list.xml +++ b/app/src/main/res/layout/command_template_list.xml @@ -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" diff --git a/app/src/main/res/layout/configure_download_bottom_sheet.xml b/app/src/main/res/layout/configure_download_bottom_sheet.xml index 5e87cbc7..8ee6fc5e 100644 --- a/app/src/main/res/layout/configure_download_bottom_sheet.xml +++ b/app/src/main/res/layout/configure_download_bottom_sheet.xml @@ -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" /> diff --git a/app/src/main/res/layout/create_command_template.xml b/app/src/main/res/layout/create_command_template.xml index 6adc4845..dbd7a684 100644 --- a/app/src/main/res/layout/create_command_template.xml +++ b/app/src/main/res/layout/create_command_template.xml @@ -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" /> diff --git a/app/src/main/res/layout/download_bottom_sheet.xml b/app/src/main/res/layout/download_bottom_sheet.xml index 487f896e..3dc1a036 100644 --- a/app/src/main/res/layout/download_bottom_sheet.xml +++ b/app/src/main/res/layout/download_bottom_sheet.xml @@ -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" diff --git a/app/src/main/res/layout/download_multiple_bottom_sheet.xml b/app/src/main/res/layout/download_multiple_bottom_sheet.xml index 27b3b0d3..df6fedfd 100644 --- a/app/src/main/res/layout/download_multiple_bottom_sheet.xml +++ b/app/src/main/res/layout/download_multiple_bottom_sheet.xml @@ -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" diff --git a/app/src/main/res/layout/filepathlist.xml b/app/src/main/res/layout/filepathlist.xml index 3d3514c1..b2bc65f1 100644 --- a/app/src/main/res/layout/filepathlist.xml +++ b/app/src/main/res/layout/filepathlist.xml @@ -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" /> diff --git a/app/src/main/res/layout/format_select_bottom_sheet.xml b/app/src/main/res/layout/format_select_bottom_sheet.xml index fce00445..60f3bc35 100644 --- a/app/src/main/res/layout/format_select_bottom_sheet.xml +++ b/app/src/main/res/layout/format_select_bottom_sheet.xml @@ -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" diff --git a/app/src/main/res/layout/observe_sources_bottom_sheet.xml b/app/src/main/res/layout/observe_sources_bottom_sheet.xml index 093b0e3a..31354014 100644 --- a/app/src/main/res/layout/observe_sources_bottom_sheet.xml +++ b/app/src/main/res/layout/observe_sources_bottom_sheet.xml @@ -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" /> diff --git a/app/src/main/res/layout/select_playlist_items.xml b/app/src/main/res/layout/select_playlist_items.xml index 741c91b1..4f76b865 100644 --- a/app/src/main/res/layout/select_playlist_items.xml +++ b/app/src/main/res/layout/select_playlist_items.xml @@ -67,14 +67,12 @@ diff --git a/app/src/main/res/layout/subtitle_dialog.xml b/app/src/main/res/layout/subtitle_dialog.xml index 5feb7aab..659a9515 100644 --- a/app/src/main/res/layout/subtitle_dialog.xml +++ b/app/src/main/res/layout/subtitle_dialog.xml @@ -24,8 +24,50 @@ + + + + + + + + + + + + + + + android:text="@string/select" /> + app:layout_constraintTop_toBottomOf="@id/all_subs"> - + - + diff --git a/app/src/main/res/layout/template_shortcuts.xml b/app/src/main/res/layout/template_shortcuts.xml index b2b89264..734447d4 100644 --- a/app/src/main/res/layout/template_shortcuts.xml +++ b/app/src/main/res/layout/template_shortcuts.xml @@ -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" /> diff --git a/app/src/main/res/layout/template_shortcuts_list.xml b/app/src/main/res/layout/template_shortcuts_list.xml index 42735e43..4671609f 100644 --- a/app/src/main/res/layout/template_shortcuts_list.xml +++ b/app/src/main/res/layout/template_shortcuts_list.xml @@ -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" /> diff --git a/app/src/main/res/layout/youtube_player_client_create_bottom_sheet.xml b/app/src/main/res/layout/youtube_player_client_create_bottom_sheet.xml index aa342f87..cc94638c 100644 --- a/app/src/main/res/layout/youtube_player_client_create_bottom_sheet.xml +++ b/app/src/main/res/layout/youtube_player_client_create_bottom_sheet.xml @@ -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"/> diff --git a/app/src/main/res/layout/ytdlp_sources_list.xml b/app/src/main/res/layout/ytdlp_sources_list.xml index 644ac5c9..83d7916b 100644 --- a/app/src/main/res/layout/ytdlp_sources_list.xml +++ b/app/src/main/res/layout/ytdlp_sources_list.xml @@ -21,17 +21,18 @@ android:orientation="horizontal" android:paddingTop="20dp"> + -