more stuff
This commit is contained in:
parent
29fff7e24c
commit
37aec538cc
37 changed files with 1400 additions and 172 deletions
|
|
@ -2,7 +2,7 @@
|
|||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 21,
|
||||
"identityHash": "3be2d00eeed0d077b84c352d10f6628f",
|
||||
"identityHash": "60367016912c1948d70c556647e93114",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "results",
|
||||
|
|
@ -384,7 +384,7 @@
|
|||
},
|
||||
{
|
||||
"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)",
|
||||
"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 DEFAULT '[]')",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
|
|
@ -431,6 +431,20 @@
|
|||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
},
|
||||
{
|
||||
"fieldPath": "preferredCommandTemplate",
|
||||
"columnName": "preferredCommandTemplate",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
},
|
||||
{
|
||||
"fieldPath": "urlRegex",
|
||||
"columnName": "urlRegex",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true,
|
||||
"defaultValue": "'[]'"
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
|
|
@ -747,7 +761,7 @@
|
|||
"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, '3be2d00eeed0d077b84c352d10f6628f')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '60367016912c1948d70c556647e93114')"
|
||||
]
|
||||
}
|
||||
}
|
||||
766
app/schemas/com.deniscerri.ytdl.database.DBManager/22.json
Normal file
766
app/schemas/com.deniscerri.ytdl.database.DBManager/22.json
Normal file
|
|
@ -0,0 +1,766 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 22,
|
||||
"identityHash": "a7ed801eeaef776e0fb063303b9892df",
|
||||
"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)",
|
||||
"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
|
||||
}
|
||||
],
|
||||
"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)",
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"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, 'a7ed801eeaef776e0fb063303b9892df')"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ import com.deniscerri.ytdl.database.models.TerminalItem
|
|||
TerminalItem::class,
|
||||
ObserveSourcesItem::class
|
||||
],
|
||||
version = 21,
|
||||
version = 22,
|
||||
autoMigrations = [
|
||||
AutoMigration (from = 1, to = 2),
|
||||
AutoMigration (from = 2, to = 3),
|
||||
|
|
@ -63,6 +63,7 @@ import com.deniscerri.ytdl.database.models.TerminalItem
|
|||
AutoMigration (from = 18, to = 19),
|
||||
AutoMigration (from = 19, to = 20),
|
||||
//AutoMigration (from = 20, to = 21) MANUALLY HANDLED
|
||||
//AutoMigration(from = 21, to = 22) MANUALLY HANDLED
|
||||
]
|
||||
)
|
||||
abstract class DBManager : RoomDatabase(){
|
||||
|
|
|
|||
|
|
@ -42,6 +42,15 @@ object Migrations {
|
|||
database.execSQL("UPDATE history SET filesize = ${parsed.filesize} WHERE id = $id")
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//add preferred command template and url regexes
|
||||
Migration(21, 22) { database ->
|
||||
// Add the `preferredCommandTemplate` column as INTEGER (since SQLite does not support BOOLEAN)
|
||||
database.execSQL("ALTER TABLE commandTemplates ADD COLUMN preferredCommandTemplate INTEGER NOT NULL DEFAULT 0")
|
||||
|
||||
// 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 '[]'")
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -38,11 +38,14 @@ interface CommandTemplateDao {
|
|||
@Query("SELECT content FROM commandTemplates WHERE useAsExtraCommand is 1")
|
||||
fun getAllTemplatesAsExtraCommands() : List<String>
|
||||
|
||||
@Query("SELECT content FROM commandTemplates WHERE useAsExtraCommand is 1 AND useAsExtraCommandAudio = 1")
|
||||
fun getAllTemplatesAsExtraCommandsForAudio() : List<String>
|
||||
@Query("SELECT * FROM commandTemplates WHERE useAsExtraCommandDataFetching is 1")
|
||||
fun getAllTemplatesAsDataFetchingExtraCommands() : List<CommandTemplate>
|
||||
|
||||
@Query("SELECT content FROM commandTemplates WHERE useAsExtraCommand is 1 AND useAsExtraCommandVideo = 1")
|
||||
fun getAllTemplatesAsExtraCommandsForVideo() : List<String>
|
||||
@Query("SELECT * FROM commandTemplates WHERE useAsExtraCommand is 1 AND useAsExtraCommandAudio = 1")
|
||||
fun getAllTemplatesAsExtraCommandsForAudio() : List<CommandTemplate>
|
||||
|
||||
@Query("SELECT * FROM commandTemplates WHERE useAsExtraCommand is 1 AND useAsExtraCommandVideo = 1")
|
||||
fun getAllTemplatesAsExtraCommandsForVideo() : List<CommandTemplate>
|
||||
|
||||
@Query("SELECT * FROM templateShortcuts ORDER BY id DESC")
|
||||
fun getAllShortcutsFlow() : Flow<List<TemplateShortcut>>
|
||||
|
|
@ -65,6 +68,9 @@ interface CommandTemplateDao {
|
|||
@Query("SELECT * FROM commandTemplates ORDER BY id DESC LIMIT 1")
|
||||
fun getFirst() : CommandTemplate?
|
||||
|
||||
@Query("SELECT * FROM commandTemplates WHERE preferredCommandTemplate is 1")
|
||||
fun getPreferredCommandTemplates() : List<CommandTemplate>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insert(item: CommandTemplate)
|
||||
|
||||
|
|
|
|||
|
|
@ -19,5 +19,8 @@ data class CommandTemplate(
|
|||
@ColumnInfo(defaultValue = "1")
|
||||
var useAsExtraCommandVideo: Boolean,
|
||||
@ColumnInfo(defaultValue = "0")
|
||||
var useAsExtraCommandDataFetching: Boolean
|
||||
var useAsExtraCommandDataFetching: Boolean,
|
||||
@ColumnInfo(defaultValue = "0")
|
||||
var preferredCommandTemplate : Boolean = false,
|
||||
var urlRegex: MutableList<String> = mutableListOf()
|
||||
)
|
||||
|
|
@ -4,8 +4,9 @@ data class YoutubePlayerClientItem(
|
|||
var playerClient: String,
|
||||
var poTokens: MutableList<YoutubePoTokenItem>,
|
||||
var enabled: Boolean = true,
|
||||
var useOnlyPoToken: Boolean = false
|
||||
)
|
||||
var useOnlyPoToken: Boolean = false,
|
||||
var urlRegex: MutableList<String> = mutableListOf()
|
||||
)
|
||||
|
||||
data class YoutubePoTokenItem(
|
||||
var context: String,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.deniscerri.ytdl.database.repository
|
|||
import android.content.Context
|
||||
import android.util.Patterns
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdl.database.dao.CommandTemplateDao
|
||||
import com.deniscerri.ytdl.database.dao.ResultDao
|
||||
import com.deniscerri.ytdl.database.models.ChapterItem
|
||||
import com.deniscerri.ytdl.database.models.DownloadItem
|
||||
|
|
@ -21,7 +22,7 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class ResultRepository(private val resultDao: ResultDao, private val context: Context) {
|
||||
class ResultRepository(private val resultDao: ResultDao, private val commandTemplateDao: CommandTemplateDao, private val context: Context) {
|
||||
val YTDLNIS_SEARCH = "YTDLNIS_SEARCH"
|
||||
val allResults : Flow<List<ResultItem>> = resultDao.getResults()
|
||||
var itemCount = MutableStateFlow(-1)
|
||||
|
|
@ -31,7 +32,7 @@ class ResultRepository(private val resultDao: ResultDao, private val context: Co
|
|||
}
|
||||
|
||||
private val youtubeApiUtil = YoutubeApiUtil(context)
|
||||
private val ytdlpUtil = YTDLPUtil(context)
|
||||
private val ytdlpUtil = YTDLPUtil(context, commandTemplateDao)
|
||||
private var newPipeUtil = NewPipeUtil(context)
|
||||
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import androidx.lifecycle.MediatorLiveData
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.media3.common.Player.Command
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.filter
|
||||
import androidx.paging.map
|
||||
|
|
@ -76,7 +77,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
private val commandTemplateDao: CommandTemplateDao
|
||||
private val formatUtil = FormatUtil(application)
|
||||
private val notificationUtil = NotificationUtil(application)
|
||||
private val ytdlpUtil = YTDLPUtil(application)
|
||||
private val ytdlpUtil: YTDLPUtil
|
||||
private val resources : Resources
|
||||
|
||||
val allDownloads : Flow<PagingData<DownloadItem>>
|
||||
|
|
@ -115,8 +116,8 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
mutableListOf()
|
||||
)
|
||||
|
||||
private var extraCommandsForAudio: String = ""
|
||||
private var extraCommandsForVideo: String = ""
|
||||
private var extraCommandsForAudio: List<CommandTemplate> = listOf()
|
||||
private var extraCommandsForVideo: List<CommandTemplate> = listOf()
|
||||
|
||||
private val dao: DownloadDao
|
||||
private val historyRepository: HistoryRepository
|
||||
|
|
@ -138,11 +139,12 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
init {
|
||||
dbManager = DBManager.getInstance(application)
|
||||
dao = dbManager.downloadDao
|
||||
commandTemplateDao = DBManager.getInstance(application).commandTemplateDao
|
||||
repository = DownloadRepository(dao)
|
||||
historyRepository = HistoryRepository(dbManager.historyDao)
|
||||
resultRepository = ResultRepository(dbManager.resultDao, application)
|
||||
resultRepository = ResultRepository(dbManager.resultDao, commandTemplateDao, application)
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(application)
|
||||
commandTemplateDao = DBManager.getInstance(application).commandTemplateDao
|
||||
ytdlpUtil = YTDLPUtil(application, commandTemplateDao)
|
||||
|
||||
activeDownloadsCount = repository.activeDownloadsCount
|
||||
activePausedDownloadsCount = repository.activePausedDownloadsCount
|
||||
|
|
@ -164,8 +166,8 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
erroredDownloads = repository.erroredDownloads.flow
|
||||
viewModelScope.launch(Dispatchers.IO){
|
||||
if (sharedPreferences.getBoolean("use_extra_commands", false)){
|
||||
extraCommandsForAudio = commandTemplateDao.getAllTemplatesAsExtraCommandsForAudio().joinToString(" ")
|
||||
extraCommandsForVideo = commandTemplateDao.getAllTemplatesAsExtraCommandsForVideo().joinToString(" ")
|
||||
extraCommandsForAudio = commandTemplateDao.getAllTemplatesAsExtraCommandsForAudio()
|
||||
extraCommandsForVideo = commandTemplateDao.getAllTemplatesAsExtraCommandsForVideo()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -320,8 +322,12 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
val extraCommands = when(type){
|
||||
Type.audio -> extraCommandsForAudio
|
||||
Type.video -> extraCommandsForVideo
|
||||
else -> ""
|
||||
}
|
||||
else -> listOf()
|
||||
}.filter {
|
||||
it.urlRegex.isEmpty() || it.urlRegex.any { u ->
|
||||
Regex(u).containsMatchIn(resultItem.url)
|
||||
}
|
||||
}.joinToString(" ") { it.content }
|
||||
|
||||
return DownloadItem(0,
|
||||
resultItem.url,
|
||||
|
|
@ -330,7 +336,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
resultItem.thumb,
|
||||
resultItem.duration,
|
||||
type,
|
||||
getFormat(resultItem.formats, type),
|
||||
getFormat(resultItem.formats, type, resultItem.url),
|
||||
container!!,
|
||||
"",
|
||||
resultItem.formats,
|
||||
|
|
@ -412,7 +418,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
fun switchDownloadType(list: List<DownloadItem>, type: Type) : List<DownloadItem>{
|
||||
|
||||
list.forEach {
|
||||
val format = getFormat(it.allFormats, type)
|
||||
val format = getFormat(it.allFormats, type, it.url)
|
||||
it.format = format
|
||||
|
||||
var updatedDownloadPath = ""
|
||||
|
|
@ -475,11 +481,15 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
|
||||
val sponsorblock = sharedPreferences.getStringSet("sponsorblock_filters", emptySet())
|
||||
|
||||
val extraCommands = when(historyItem.type){
|
||||
val extraCommands = when (historyItem.type) {
|
||||
Type.audio -> extraCommandsForAudio
|
||||
Type.video -> extraCommandsForVideo
|
||||
else -> ""
|
||||
}
|
||||
else -> listOf()
|
||||
}.filter {
|
||||
it.urlRegex.isEmpty() || it.urlRegex.any { u ->
|
||||
Regex(u).containsMatchIn(historyItem.url)
|
||||
}
|
||||
}.joinToString(" ") { it.content }
|
||||
|
||||
val audioPreferences = AudioPreferences(embedThumb, cropThumb,false, ArrayList(sponsorblock!!))
|
||||
val videoPreferences = VideoPreferences(embedSubs, addChapters, false, ArrayList(sponsorblock), saveSubs, saveAutoSubs, subsLanguages, recodeVideo = recodeVideo)
|
||||
|
|
@ -521,7 +531,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
}
|
||||
|
||||
|
||||
fun getFormat(formats: List<Format>, type: Type) : Format {
|
||||
fun getFormat(formats: List<Format>, type: Type, url: String? = null) : Format {
|
||||
when(type) {
|
||||
Type.audio -> {
|
||||
return cloneFormat (
|
||||
|
|
@ -550,19 +560,27 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
)
|
||||
}
|
||||
else -> {
|
||||
val preferredTemplateContent =
|
||||
sharedPreferences.getString("preferred_command_template", "")!!.ifEmpty {
|
||||
sharedPreferences.getString("lastCommandTemplateUsed", "")!!
|
||||
}
|
||||
|
||||
val c = if (preferredTemplateContent.isNotBlank()) {
|
||||
commandTemplateDao.getTemplateByContent(preferredTemplateContent)
|
||||
}else {
|
||||
commandTemplateDao.getFirst()
|
||||
val preferredCommandTemplates = commandTemplateDao.getPreferredCommandTemplates()
|
||||
var template : CommandTemplate? = null
|
||||
if (url != null) {
|
||||
template = preferredCommandTemplates.firstOrNull { it.urlRegex.isEmpty() || it.urlRegex.any { u ->
|
||||
Regex(u).containsMatchIn(url)
|
||||
} }
|
||||
}
|
||||
|
||||
if (template == null) {
|
||||
template = commandTemplateDao.getFirst()
|
||||
}
|
||||
return generateCommandFormat(
|
||||
c ?: CommandTemplate(0, "", preferredTemplateContent, useAsExtraCommand = false, useAsExtraCommandAudio = false, useAsExtraCommandVideo = false, useAsExtraCommandDataFetching = false)
|
||||
template ?: CommandTemplate(
|
||||
0,
|
||||
"",
|
||||
sharedPreferences.getString("lastCommandTemplateUsed", "") ?: "",
|
||||
useAsExtraCommand = false,
|
||||
useAsExtraCommandAudio = false,
|
||||
useAsExtraCommandVideo = false,
|
||||
useAsExtraCommandDataFetching = false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1128,7 +1146,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
val item = repository.getItemByID(id)
|
||||
item.allFormats.clear()
|
||||
item.allFormats.addAll(list)
|
||||
item.format = getFormat(list, item.type)
|
||||
item.format = getFormat(list, item.type, item.url)
|
||||
|
||||
runCatching {
|
||||
resultRepository.getAllByURL(item.url).forEach {
|
||||
|
|
@ -1144,7 +1162,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
items.forEach { item ->
|
||||
item.allFormats.clear()
|
||||
item.allFormats.addAll(list)
|
||||
item.format = getFormat(list, item.type)
|
||||
item.format = getFormat(list, item.type, item.url)
|
||||
repository.update(item)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,8 +71,10 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
|
|||
private val sharedPreferences: SharedPreferences
|
||||
|
||||
init {
|
||||
dao = DBManager.getInstance(application).resultDao
|
||||
repository = ResultRepository(dao, getApplication<Application>().applicationContext)
|
||||
val dbManager = DBManager.getInstance(application)
|
||||
dao = dbManager.resultDao
|
||||
val commandTemplateDao = dbManager.commandTemplateDao
|
||||
repository = ResultRepository(dao, commandTemplateDao, getApplication<Application>().applicationContext)
|
||||
searchHistoryRepository = SearchHistoryRepository(DBManager.getInstance(application).searchHistoryDao)
|
||||
|
||||
items = repository.allResults.asLiveData()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
package com.deniscerri.ytdl.database.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.os.Build
|
||||
import android.os.Parcelable
|
||||
import android.util.DisplayMetrics
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.filter
|
||||
import androidx.paging.map
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.work.Data
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdl.App
|
||||
import com.deniscerri.ytdl.R
|
||||
import com.deniscerri.ytdl.database.DBManager
|
||||
import com.deniscerri.ytdl.database.dao.CommandTemplateDao
|
||||
import com.deniscerri.ytdl.database.dao.DownloadDao
|
||||
import com.deniscerri.ytdl.database.models.AudioPreferences
|
||||
import com.deniscerri.ytdl.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdl.database.models.DownloadItem
|
||||
import com.deniscerri.ytdl.database.models.DownloadItemConfigureMultiple
|
||||
import com.deniscerri.ytdl.database.models.DownloadItemSimple
|
||||
import com.deniscerri.ytdl.database.models.Format
|
||||
import com.deniscerri.ytdl.database.models.HistoryItem
|
||||
import com.deniscerri.ytdl.database.models.ResultItem
|
||||
import com.deniscerri.ytdl.database.models.VideoPreferences
|
||||
import com.deniscerri.ytdl.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdl.database.repository.HistoryRepository
|
||||
import com.deniscerri.ytdl.database.repository.ResultRepository
|
||||
import com.deniscerri.ytdl.ui.downloadcard.MultipleItemFormatTuple
|
||||
import com.deniscerri.ytdl.util.Extensions.needsDataUpdating
|
||||
import com.deniscerri.ytdl.util.Extensions.toListString
|
||||
import com.deniscerri.ytdl.util.FileUtil
|
||||
import com.deniscerri.ytdl.util.FormatUtil
|
||||
import com.deniscerri.ytdl.util.NotificationUtil
|
||||
import com.deniscerri.ytdl.util.extractors.YTDLPUtil
|
||||
import com.deniscerri.ytdl.work.AlarmScheduler
|
||||
import com.deniscerri.ytdl.work.UpdateMultipleDownloadsDataWorker
|
||||
import com.deniscerri.ytdl.work.UpdateMultipleDownloadsFormatsWorker
|
||||
import com.google.gson.Gson
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
class YTDLPViewModel(private val application: Application) : AndroidViewModel(application) {
|
||||
private val dbManager: DBManager
|
||||
private val commandTemplateDao: CommandTemplateDao
|
||||
private val ytdlpUtil: YTDLPUtil
|
||||
|
||||
init {
|
||||
dbManager = DBManager.getInstance(application)
|
||||
commandTemplateDao = DBManager.getInstance(application).commandTemplateDao
|
||||
ytdlpUtil = YTDLPUtil(application, commandTemplateDao)
|
||||
}
|
||||
|
||||
fun parseYTDLRequestString(item: DownloadItem) : String {
|
||||
val req = ytdlpUtil.buildYoutubeDLRequest(item)
|
||||
return ytdlpUtil.parseYTDLRequestString(req)
|
||||
}
|
||||
|
||||
fun getVersion(channel: String) : String {
|
||||
return ytdlpUtil.getVersion(application, channel)
|
||||
}
|
||||
}
|
||||
|
|
@ -76,8 +76,7 @@ class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activ
|
|||
}
|
||||
|
||||
card.findViewById<TextView>(R.id.preferredTemplate).apply {
|
||||
val preferred = sharedPreferences.getString("preferred_command_template", "")
|
||||
isVisible = preferred == item.content
|
||||
isVisible = item.preferredCommandTemplate
|
||||
}
|
||||
|
||||
if (checkedItems.contains(item.id)) {
|
||||
|
|
@ -170,7 +169,9 @@ class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activ
|
|||
oldItem.useAsExtraCommand == newItem.useAsExtraCommand &&
|
||||
oldItem.useAsExtraCommandAudio == newItem.useAsExtraCommandAudio &&
|
||||
oldItem.useAsExtraCommandVideo == newItem.useAsExtraCommandVideo &&
|
||||
oldItem.useAsExtraCommandDataFetching == newItem.useAsExtraCommandDataFetching
|
||||
oldItem.useAsExtraCommandDataFetching == newItem.useAsExtraCommandDataFetching &&
|
||||
oldItem.preferredCommandTemplate == newItem.preferredCommandTemplate &&
|
||||
oldItem.urlRegex.joinToString("") == newItem.urlRegex.joinToString("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,11 +115,10 @@ class YoutubePlayerClientAdapter(onItemClickListener: OnItemClickListener, activ
|
|||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: YoutubePlayerClientItem, newItem: YoutubePlayerClientItem): Boolean {
|
||||
return oldItem.playerClient == newItem.playerClient && oldItem.enabled == newItem.enabled && oldItem.poTokens.joinToString(
|
||||
"\n"
|
||||
) { it.token } == newItem.poTokens.joinToString(
|
||||
"\n"
|
||||
) { it.token }
|
||||
return oldItem.playerClient == newItem.playerClient &&
|
||||
oldItem.enabled == newItem.enabled &&
|
||||
oldItem.poTokens.joinToString("\n") { it.token } == newItem.poTokens.joinToString("\n") { it.token } &&
|
||||
oldItem.urlRegex.joinToString("\n") == newItem.urlRegex.joinToString("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import androidx.preference.PreferenceManager
|
|||
import com.deniscerri.ytdl.R
|
||||
import com.deniscerri.ytdl.database.models.DownloadItem
|
||||
import com.deniscerri.ytdl.database.viewmodel.CommandTemplateViewModel
|
||||
import com.deniscerri.ytdl.database.viewmodel.YTDLPViewModel
|
||||
import com.deniscerri.ytdl.util.Extensions.enableTextHighlight
|
||||
import com.deniscerri.ytdl.util.UiUtil
|
||||
import com.deniscerri.ytdl.util.extractors.YTDLPUtil
|
||||
|
|
@ -31,15 +32,15 @@ import kotlinx.coroutines.withContext
|
|||
|
||||
|
||||
class AddExtraCommandsDialog(private val item: DownloadItem? = null, private val callback: ExtraCommandsListener? = null) : BottomSheetDialogFragment() {
|
||||
private lateinit var ytdlpUtil: YTDLPUtil
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
private lateinit var commandTemplateViewModel: CommandTemplateViewModel
|
||||
private lateinit var ytdlpViewModel: YTDLPViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ytdlpUtil = YTDLPUtil(requireActivity().applicationContext)
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
ytdlpViewModel = ViewModelProvider(this)[YTDLPViewModel::class.java]
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
|
|
@ -86,7 +87,7 @@ class AddExtraCommandsDialog(private val item: DownloadItem? = null, private val
|
|||
val currentText = view.findViewById<TextView>(R.id.currentText)
|
||||
|
||||
if (item != null){
|
||||
val currentCommand = ytdlpUtil.parseYTDLRequestString(ytdlpUtil.buildYoutubeDLRequest(item))
|
||||
val currentCommand = ytdlpViewModel.parseYTDLRequestString(item)
|
||||
currentText?.text = currentCommand
|
||||
}else{
|
||||
view.findViewById<View>(R.id.current).visibility = View.GONE
|
||||
|
|
|
|||
|
|
@ -549,15 +549,15 @@ class ObserveSourcesBottomSheetDialog : BottomSheetDialogFragment() {
|
|||
val url = url.editText?.text?.isNotBlank() == true
|
||||
val category = ObserveSourcesRepository.EveryCategory.values()[categoryAdapter.getPosition(everyCat.text.toString())]
|
||||
|
||||
val everyNr = everyNr.editText?.text?.isNotBlank() == true
|
||||
val everyNrBool = everyNr.editText!!.text.isNotBlank() && everyNr.editText!!.text.toString() != "0"
|
||||
val everyTime = everyTime.editText?.text?.isNotBlank() == true
|
||||
|
||||
val every = when(category){
|
||||
ObserveSourcesRepository.EveryCategory.HOUR -> {
|
||||
everyNr
|
||||
everyNrBool
|
||||
}
|
||||
else -> {
|
||||
everyNr && everyTime
|
||||
everyNrBool && everyTime
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import com.deniscerri.ytdl.database.models.ResultItem
|
|||
import com.deniscerri.ytdl.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdl.database.viewmodel.YTDLPViewModel
|
||||
import com.deniscerri.ytdl.ui.adapter.ActiveDownloadMinifiedAdapter
|
||||
import com.deniscerri.ytdl.ui.adapter.GenericDownloadAdapter
|
||||
import com.deniscerri.ytdl.util.Extensions.setFullScreen
|
||||
|
|
@ -79,6 +80,7 @@ class ResultCardDetailsDialog : BottomSheetDialogFragment(), GenericDownloadAdap
|
|||
private lateinit var videoView: PlayerView
|
||||
private lateinit var downloadViewModel: DownloadViewModel
|
||||
private lateinit var resultViewModel: ResultViewModel
|
||||
private lateinit var ytdlpViewModel: YTDLPViewModel
|
||||
|
||||
private lateinit var activeAdapter: ActiveDownloadMinifiedAdapter
|
||||
private lateinit var queuedAdapter: GenericDownloadAdapter
|
||||
|
|
@ -94,6 +96,7 @@ class ResultCardDetailsDialog : BottomSheetDialogFragment(), GenericDownloadAdap
|
|||
notificationUtil = NotificationUtil(requireActivity())
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
ytdlpViewModel = ViewModelProvider(this)[YTDLPViewModel::class.java]
|
||||
downloadManager = requireContext().getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
}
|
||||
|
|
@ -446,6 +449,7 @@ class ResultCardDetailsDialog : BottomSheetDialogFragment(), GenericDownloadAdap
|
|||
item,
|
||||
requireActivity(),
|
||||
DownloadRepository.Status.valueOf(item.status),
|
||||
ytdlpViewModel,
|
||||
removeItem = { it: DownloadItem, sheet: BottomSheetDialog ->
|
||||
sheet.hide()
|
||||
removeQueuedItem(itemID)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import com.deniscerri.ytdl.R
|
|||
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.database.viewmodel.YTDLPViewModel
|
||||
import com.deniscerri.ytdl.ui.adapter.GenericDownloadAdapter
|
||||
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
|
||||
import com.deniscerri.ytdl.util.Extensions.forceFastScrollMode
|
||||
|
|
@ -60,6 +61,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var ytdlpViewModel : YTDLPViewModel
|
||||
private lateinit var cancelledRecyclerView : RecyclerView
|
||||
private lateinit var preferences : SharedPreferences
|
||||
private lateinit var adapter : GenericDownloadAdapter
|
||||
|
|
@ -79,6 +81,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
fragmentView = inflater.inflate(R.layout.generic_list, container, false)
|
||||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
||||
ytdlpViewModel = ViewModelProvider(requireActivity())[YTDLPViewModel::class.java]
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
return fragmentView
|
||||
}
|
||||
|
|
@ -174,6 +177,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
item,
|
||||
requireActivity(),
|
||||
DownloadRepository.Status.valueOf(item.status),
|
||||
ytdlpViewModel,
|
||||
removeItem = { it: DownloadItem, sheet: BottomSheetDialog ->
|
||||
removeItem(it, sheet)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import com.deniscerri.ytdl.R
|
|||
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.database.viewmodel.YTDLPViewModel
|
||||
import com.deniscerri.ytdl.ui.adapter.GenericDownloadAdapter
|
||||
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
|
||||
import com.deniscerri.ytdl.util.Extensions.forceFastScrollMode
|
||||
|
|
@ -58,6 +59,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var ytdlpViewModel : YTDLPViewModel
|
||||
private lateinit var erroredRecyclerView : RecyclerView
|
||||
private lateinit var preferences : SharedPreferences
|
||||
private lateinit var noResults : RelativeLayout
|
||||
|
|
@ -77,6 +79,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
fragmentView = inflater.inflate(R.layout.generic_list, container, false)
|
||||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
||||
ytdlpViewModel = ViewModelProvider(requireActivity())[YTDLPViewModel::class.java]
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
return fragmentView
|
||||
}
|
||||
|
|
@ -174,6 +177,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
item,
|
||||
requireActivity(),
|
||||
DownloadRepository.Status.valueOf(item.status),
|
||||
ytdlpViewModel,
|
||||
removeItem = { it: DownloadItem, sheet: BottomSheetDialog ->
|
||||
removeItem(it, sheet)
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import com.deniscerri.ytdl.R
|
|||
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.database.viewmodel.YTDLPViewModel
|
||||
import com.deniscerri.ytdl.ui.adapter.QueuedDownloadAdapter
|
||||
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
|
||||
import com.deniscerri.ytdl.util.Extensions.forceFastScrollMode
|
||||
|
|
@ -61,6 +62,7 @@ class QueuedDownloadsFragment : Fragment(), QueuedDownloadAdapter.OnItemClickLis
|
|||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var ytdlpViewModel : YTDLPViewModel
|
||||
private lateinit var queuedRecyclerView : RecyclerView
|
||||
private lateinit var adapter : QueuedDownloadAdapter
|
||||
private lateinit var noResults : RelativeLayout
|
||||
|
|
@ -80,6 +82,7 @@ class QueuedDownloadsFragment : Fragment(), QueuedDownloadAdapter.OnItemClickLis
|
|||
activity = getActivity()
|
||||
notificationUtil = NotificationUtil(requireContext())
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
ytdlpViewModel = ViewModelProvider(this)[YTDLPViewModel::class.java]
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -450,6 +453,7 @@ class QueuedDownloadsFragment : Fragment(), QueuedDownloadAdapter.OnItemClickLis
|
|||
item,
|
||||
requireActivity(),
|
||||
DownloadRepository.Status.valueOf(item.status),
|
||||
ytdlpViewModel,
|
||||
removeItem = { it: DownloadItem, sheet: BottomSheetDialog ->
|
||||
sheet.hide()
|
||||
removeItem(it.id)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import com.deniscerri.ytdl.R
|
|||
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.database.viewmodel.YTDLPViewModel
|
||||
import com.deniscerri.ytdl.ui.adapter.GenericDownloadAdapter
|
||||
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
|
||||
import com.deniscerri.ytdl.util.Extensions.forceFastScrollMode
|
||||
|
|
@ -57,6 +58,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var ytdlpViewModel : YTDLPViewModel
|
||||
private lateinit var savedRecyclerView: RecyclerView
|
||||
private lateinit var adapter: GenericDownloadAdapter
|
||||
private lateinit var preferences: SharedPreferences
|
||||
|
|
@ -76,6 +78,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
fragmentView = inflater.inflate(R.layout.generic_list, container, false)
|
||||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
||||
ytdlpViewModel = ViewModelProvider(requireActivity())[YTDLPViewModel::class.java]
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
return fragmentView
|
||||
}
|
||||
|
|
@ -183,6 +186,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
item,
|
||||
requireActivity(),
|
||||
DownloadRepository.Status.valueOf(item.status),
|
||||
ytdlpViewModel,
|
||||
removeItem = { it: DownloadItem, sheet: BottomSheetDialog ->
|
||||
removeItem(it, sheet)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import com.deniscerri.ytdl.R
|
|||
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.database.viewmodel.YTDLPViewModel
|
||||
import com.deniscerri.ytdl.ui.adapter.GenericDownloadAdapter
|
||||
import com.deniscerri.ytdl.ui.adapter.ScheduledDownloadAdapter
|
||||
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
|
||||
|
|
@ -58,6 +59,7 @@ class ScheduledDownloadsFragment : Fragment(), ScheduledDownloadAdapter.OnItemCl
|
|||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var ytdlpViewModel : YTDLPViewModel
|
||||
private lateinit var scheduledRecyclerView : RecyclerView
|
||||
private lateinit var preferences : SharedPreferences
|
||||
private lateinit var adapter : ScheduledDownloadAdapter
|
||||
|
|
@ -77,6 +79,7 @@ class ScheduledDownloadsFragment : Fragment(), ScheduledDownloadAdapter.OnItemCl
|
|||
fragmentView = inflater.inflate(R.layout.generic_list, container, false)
|
||||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
ytdlpViewModel = ViewModelProvider(this)[YTDLPViewModel::class.java]
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
return fragmentView
|
||||
}
|
||||
|
|
@ -179,6 +182,7 @@ class ScheduledDownloadsFragment : Fragment(), ScheduledDownloadAdapter.OnItemCl
|
|||
item,
|
||||
requireActivity(),
|
||||
DownloadRepository.Status.valueOf(item.status),
|
||||
ytdlpViewModel,
|
||||
removeItem = { it: DownloadItem, sheet: BottomSheetDialog ->
|
||||
sheet.hide()
|
||||
removeItem(it, sheet)
|
||||
|
|
|
|||
|
|
@ -29,15 +29,20 @@ import com.deniscerri.ytdl.database.viewmodel.LogViewModel
|
|||
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
|
||||
import com.deniscerri.ytdl.util.Extensions.enableTextHighlight
|
||||
import com.deniscerri.ytdl.util.Extensions.setCustomTextSize
|
||||
import com.deniscerri.ytdl.work.DownloadWorker
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.bottomappbar.BottomAppBar
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import com.google.android.material.slider.Slider
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
|
||||
class DownloadLogFragment : Fragment() {
|
||||
|
|
@ -48,6 +53,7 @@ class DownloadLogFragment : Fragment() {
|
|||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var logViewModel: LogViewModel
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
private var logID: Long? = null
|
||||
|
||||
private var autoScroll : Boolean = true
|
||||
private var scrollDownBtn : MenuItem? = null
|
||||
|
|
@ -95,8 +101,8 @@ class DownloadLogFragment : Fragment() {
|
|||
.show()
|
||||
}
|
||||
|
||||
val id = arguments?.getLong("logID")
|
||||
if (id == null || id == 0L) {
|
||||
logID = arguments?.getLong("logID")
|
||||
if (logID == null || logID == 0L) {
|
||||
mainActivity.onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
|
|
@ -105,7 +111,7 @@ class DownloadLogFragment : Fragment() {
|
|||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
runCatching {
|
||||
val logItem = logViewModel.getItemById(id!!)
|
||||
val logItem = logViewModel.getItemById(logID!!)
|
||||
withContext(Dispatchers.Main){
|
||||
topAppBar.title = logItem.title
|
||||
}
|
||||
|
|
@ -202,7 +208,7 @@ class DownloadLogFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
logViewModel.getLogFlowByID(id!!).observe(viewLifecycleOwner){logItem ->
|
||||
logViewModel.getLogFlowByID(logID!!).observe(viewLifecycleOwner){logItem ->
|
||||
kotlin.runCatching {
|
||||
requireActivity().runOnUiThread{
|
||||
if (logItem != null){
|
||||
|
|
@ -227,6 +233,26 @@ class DownloadLogFragment : Fragment() {
|
|||
scrollDownBtn?.isVisible = canVerticallyScroll
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
|
||||
//dont remove
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onDownloadProgressEvent(event: DownloadWorker.WorkerProgress) {
|
||||
val progressBar = requireView().findViewById<LinearProgressIndicator>(R.id.progress)
|
||||
if (event.logItemID == logID) {
|
||||
progressBar.isVisible = true
|
||||
progressBar.setProgress(event.progress, true)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DownloadLogActivity"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.view.get
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceManager
|
||||
|
|
@ -36,6 +37,8 @@ import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
|||
import com.deniscerri.ytdl.BuildConfig
|
||||
import com.deniscerri.ytdl.R
|
||||
import com.deniscerri.ytdl.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdl.database.viewmodel.YTDLPViewModel
|
||||
import com.deniscerri.ytdl.util.UiUtil
|
||||
import com.deniscerri.ytdl.util.UiUtil.showShortcutsSheet
|
||||
import com.deniscerri.ytdl.util.UpdateUtil
|
||||
|
|
@ -64,7 +67,7 @@ class UpdateSettingsFragment : BaseSettingsFragment() {
|
|||
private var updateUtil: UpdateUtil? = null
|
||||
private var version: Preference? = null
|
||||
private lateinit var preferences: SharedPreferences
|
||||
private lateinit var ytdlpUtil: YTDLPUtil
|
||||
private lateinit var ytdlpViewModel: YTDLPViewModel
|
||||
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
|
|
@ -74,7 +77,9 @@ class UpdateSettingsFragment : BaseSettingsFragment() {
|
|||
updateYTDL = findPreference("update_ytdl")
|
||||
ytdlVersion = findPreference("ytdl-version")
|
||||
ytdlSource = findPreference("ytdlp_source_label")
|
||||
ytdlpUtil = YTDLPUtil(requireContext())
|
||||
|
||||
ytdlpViewModel = ViewModelProvider(this)[YTDLPViewModel::class.java]
|
||||
|
||||
ytdlSource?.apply {
|
||||
summary = preferences.getString("ytdlp_source_label", "")
|
||||
setOnPreferenceClickListener {
|
||||
|
|
@ -141,7 +146,7 @@ class UpdateSettingsFragment : BaseSettingsFragment() {
|
|||
lifecycleScope.launch {
|
||||
ytdlVersion!!.summary = getString(R.string.loading)
|
||||
val version = withContext(Dispatchers.IO){
|
||||
ytdlpUtil.getVersion(requireContext(), preferences.getString("ytdlp_source", "stable")!!)
|
||||
ytdlpViewModel.getVersion(preferences.getString("ytdlp_source", "stable")!!)
|
||||
}
|
||||
preferences.edit().apply {
|
||||
putString("ytdl-version", version)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import android.animation.ObjectAnimator
|
|||
import android.animation.ValueAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
|
|
@ -15,11 +14,9 @@ import android.content.SharedPreferences
|
|||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.text.Editable
|
||||
import android.text.InputType
|
||||
import android.text.TextWatcher
|
||||
import android.text.format.DateFormat
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
|
@ -35,20 +32,14 @@ import android.widget.PopupMenu
|
|||
import android.widget.RadioButton
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.DimenRes
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.core.text.parseAsHtml
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.marginBottom
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.fragment.app.FragmentManager
|
||||
|
|
@ -56,7 +47,6 @@ import androidx.lifecycle.LifecycleOwner
|
|||
import androidx.preference.PreferenceManager
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.textChanged
|
||||
import com.deniscerri.ytdl.MainActivity
|
||||
import com.deniscerri.ytdl.R
|
||||
import com.deniscerri.ytdl.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdl.database.models.DownloadItem
|
||||
|
|
@ -68,8 +58,8 @@ import com.deniscerri.ytdl.database.models.YoutubePoTokenItem
|
|||
import com.deniscerri.ytdl.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdl.database.viewmodel.CommandTemplateViewModel
|
||||
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdl.database.viewmodel.YTDLPViewModel
|
||||
import com.deniscerri.ytdl.ui.downloadcard.VideoCutListener
|
||||
import com.deniscerri.ytdl.ui.more.WebViewActivity
|
||||
import com.deniscerri.ytdl.util.Extensions.enableTextHighlight
|
||||
import com.deniscerri.ytdl.util.Extensions.getMediaDuration
|
||||
import com.deniscerri.ytdl.util.Extensions.toStringDuration
|
||||
|
|
@ -91,21 +81,17 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.google.android.material.materialswitch.MaterialSwitch
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.google.android.material.textfield.TextInputLayout.END_ICON_CUSTOM
|
||||
import com.google.android.material.textfield.TextInputLayout.END_ICON_NONE
|
||||
import com.google.android.material.timepicker.MaterialTimePicker
|
||||
import com.google.android.material.timepicker.TimeFormat
|
||||
import com.google.gson.Gson
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
|
|
@ -214,6 +200,8 @@ object UiUtil {
|
|||
val extraCommandsDataFetchingSwitch : MaterialSwitch = bottomSheet.findViewById(R.id.extraCommandDataFetching)!!
|
||||
val shortcutsChipGroup : ChipGroup = bottomSheet.findViewById(R.id.shortcutsChipGroup)!!
|
||||
val editShortcuts : Button = bottomSheet.findViewById(R.id.edit_shortcuts)!!
|
||||
val urlRegex : TextInputLayout = bottomSheet.findViewById(R.id.url_regex)!!
|
||||
val urlRegexChips : ChipGroup = bottomSheet.findViewById(R.id.urlRegexChipGroup)!!
|
||||
|
||||
extraCommandsDataFetchingSwitch.isVisible = sharedPreferences.getBoolean("enable_data_fetching_extra_commands", false)
|
||||
|
||||
|
|
@ -274,7 +262,7 @@ object UiUtil {
|
|||
}
|
||||
|
||||
if (item != null){
|
||||
preferredCommandSwitch.isChecked = item.content == sharedPreferences.getString("preferred_command_template", "")
|
||||
preferredCommandSwitch.isChecked = item.preferredCommandTemplate
|
||||
extraCommandsDataFetchingSwitch.isChecked = item.useAsExtraCommandDataFetching && extraCommandsDataFetchingSwitch.isVisible
|
||||
|
||||
extraCommandsSwitch.isChecked = item.useAsExtraCommand
|
||||
|
|
@ -289,15 +277,40 @@ object UiUtil {
|
|||
extraCommandsVideo.isVisible = false
|
||||
extraCommandsVideo.isChecked = false
|
||||
}
|
||||
|
||||
val canUseURLRegex = item.useAsExtraCommand || item.useAsExtraCommandDataFetching || item.preferredCommandTemplate
|
||||
urlRegex.isVisible = canUseURLRegex
|
||||
urlRegexChips.isVisible = canUseURLRegex
|
||||
|
||||
for(chip in item.urlRegex) {
|
||||
val tmp = context.layoutInflater.inflate(R.layout.input_chip, urlRegexChips, false) as Chip
|
||||
tmp.text = chip
|
||||
tmp.setOnClickListener {
|
||||
urlRegexChips.removeView(tmp)
|
||||
}
|
||||
urlRegexChips.addView(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
preferredCommandSwitch.setOnCheckedChangeListener { compoundButton, b ->
|
||||
val canUseURLRegex = extraCommandsSwitch.isChecked || extraCommandsDataFetchingSwitch.isChecked || preferredCommandSwitch.isChecked
|
||||
urlRegex.isVisible = canUseURLRegex
|
||||
urlRegexChips.isVisible = canUseURLRegex
|
||||
}
|
||||
|
||||
extraCommandsSwitch.setOnCheckedChangeListener { compoundButton, b ->
|
||||
extraCommandsAudio.isVisible = extraCommandsSwitch.isChecked
|
||||
extraCommandsAudio.isChecked = true
|
||||
extraCommandsVideo.isVisible = extraCommandsSwitch.isChecked
|
||||
extraCommandsVideo.isChecked = true
|
||||
|
||||
val canUseURLRegex = extraCommandsSwitch.isChecked || extraCommandsDataFetchingSwitch.isChecked || preferredCommandSwitch.isChecked
|
||||
urlRegex.isVisible = canUseURLRegex
|
||||
urlRegexChips.isVisible = canUseURLRegex
|
||||
}
|
||||
|
||||
|
||||
|
||||
extraCommandsAudio.setOnCheckedChangeListener { compoundButton, b ->
|
||||
ok.isEnabled = (extraCommandsAudio.isChecked || extraCommandsVideo.isChecked) && title.editText!!.text.isNotEmpty() && content.editText!!.text.isNotEmpty()
|
||||
}
|
||||
|
|
@ -306,6 +319,28 @@ object UiUtil {
|
|||
ok.isEnabled = (extraCommandsAudio.isChecked || extraCommandsVideo.isChecked) && title.editText!!.text.isNotEmpty() && content.editText!!.text.isNotEmpty()
|
||||
}
|
||||
|
||||
extraCommandsDataFetchingSwitch.setOnCheckedChangeListener { compoundButton, b ->
|
||||
val canUseURLRegex = extraCommandsSwitch.isChecked || extraCommandsDataFetchingSwitch.isChecked || preferredCommandSwitch.isChecked
|
||||
urlRegex.isVisible = canUseURLRegex
|
||||
urlRegexChips.isVisible = canUseURLRegex
|
||||
}
|
||||
|
||||
urlRegex.isEndIconVisible = false
|
||||
urlRegex.editText!!.doOnTextChanged { text, start, before, count ->
|
||||
urlRegex.isEndIconVisible = urlRegex.editText!!.text.isNotBlank()
|
||||
}
|
||||
|
||||
urlRegex.setEndIconOnClickListener {
|
||||
val text = urlRegex.editText!!.text
|
||||
urlRegex.editText!!.setText("")
|
||||
val tmp = context.layoutInflater.inflate(R.layout.input_chip, urlRegexChips, false) as Chip
|
||||
tmp.text = text
|
||||
tmp.setOnClickListener {
|
||||
urlRegexChips.removeView(tmp)
|
||||
}
|
||||
urlRegexChips.addView(tmp)
|
||||
}
|
||||
|
||||
commandTemplateViewModel.shortcuts.observe(lifeCycle){
|
||||
shortcutsChipGroup.removeAllViews()
|
||||
it.forEach {shortcut ->
|
||||
|
|
@ -323,15 +358,20 @@ object UiUtil {
|
|||
}
|
||||
|
||||
ok.setOnClickListener {
|
||||
if (preferredCommandSwitch.isChecked) {
|
||||
sharedPreferences.edit().putString("preferred_command_template", content.editText!!.text.toString()).apply()
|
||||
}else if (sharedPreferences.getString("preferred_command_template", "") == item?.content){
|
||||
sharedPreferences.edit().putString("preferred_command_template", "").apply()
|
||||
}
|
||||
|
||||
|
||||
val urlRegexes = urlRegexChips.children.map { (it as Chip).text.toString() }.toMutableList()
|
||||
if (item == null){
|
||||
val t = CommandTemplate(0, title.editText!!.text.toString(), content.editText!!.text.toString(), extraCommandsSwitch.isChecked, extraCommandsAudio.isChecked, extraCommandsVideo.isChecked, extraCommandsDataFetchingSwitch.isChecked)
|
||||
|
||||
val t = CommandTemplate(
|
||||
0,
|
||||
title.editText!!.text.toString(),
|
||||
content.editText!!.text.toString(),
|
||||
extraCommandsSwitch.isChecked,
|
||||
extraCommandsAudio.isChecked,
|
||||
extraCommandsVideo.isChecked,
|
||||
extraCommandsDataFetchingSwitch.isChecked,
|
||||
preferredCommandSwitch.isChecked,
|
||||
urlRegexes
|
||||
)
|
||||
commandTemplateViewModel.insert(t)
|
||||
newTemplate(t)
|
||||
}else{
|
||||
|
|
@ -341,6 +381,8 @@ object UiUtil {
|
|||
item.useAsExtraCommandAudio = extraCommandsAudio.isChecked
|
||||
item.useAsExtraCommandVideo = extraCommandsVideo.isChecked
|
||||
item.useAsExtraCommandDataFetching = extraCommandsDataFetchingSwitch.isChecked
|
||||
item.preferredCommandTemplate = preferredCommandSwitch.isChecked
|
||||
item.urlRegex = urlRegexes
|
||||
commandTemplateViewModel.update(item)
|
||||
newTemplate(item)
|
||||
}
|
||||
|
|
@ -490,6 +532,7 @@ object UiUtil {
|
|||
item: DownloadItem,
|
||||
context: Activity,
|
||||
status: DownloadRepository.Status,
|
||||
ytdlpViewModel: YTDLPViewModel,
|
||||
removeItem : (DownloadItem, BottomSheetDialog) -> Unit,
|
||||
downloadItem: (DownloadItem) -> Unit,
|
||||
longClickDownloadButton: (DownloadItem) -> Unit,
|
||||
|
|
@ -598,10 +641,8 @@ object UiUtil {
|
|||
if (fileSizeReadable == "?") fileSize!!.visibility = View.GONE
|
||||
else fileSize!!.text = fileSizeReadable
|
||||
|
||||
val ytdlpUtil = YTDLPUtil(context)
|
||||
|
||||
command?.setOnClickListener {
|
||||
showGeneratedCommand(context, ytdlpUtil.parseYTDLRequestString(ytdlpUtil.buildYoutubeDLRequest(item)))
|
||||
showGeneratedCommand(context, ytdlpViewModel.parseYTDLRequestString(item))
|
||||
}
|
||||
|
||||
val link = bottomSheet.findViewById<Button>(R.id.bottom_sheet_link)
|
||||
|
|
@ -2314,7 +2355,7 @@ object UiUtil {
|
|||
fun showYoutubePlayerClientSheet(context: Activity, preferences: SharedPreferences, currentValue: YoutubePlayerClientItem?, newValue: (item: YoutubePlayerClientItem) -> Unit, deleted: () -> Unit){
|
||||
val bottomSheet = BottomSheetDialog(context)
|
||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet.setContentView(R.layout.youtube_player_clients)
|
||||
bottomSheet.setContentView(R.layout.youtube_player_client_create_bottom_sheet)
|
||||
|
||||
val title : TextInputLayout = bottomSheet.findViewById(R.id.title)!!
|
||||
val chipGroup : ChipGroup = bottomSheet.findViewById(R.id.chipGroup)!!
|
||||
|
|
@ -2376,6 +2417,35 @@ object UiUtil {
|
|||
okBtn.text = context.getString(R.string.edit)
|
||||
}
|
||||
|
||||
val urlRegexInput = contentLinear.findViewById<TextInputLayout>(R.id.url_regex)
|
||||
urlRegexInput.isEndIconVisible = false
|
||||
urlRegexInput.editText!!.doOnTextChanged { text, start, before, count ->
|
||||
urlRegexInput.isEndIconVisible = urlRegexInput.editText!!.text.isNotBlank()
|
||||
}
|
||||
|
||||
val urlRegexChips = contentLinear.findViewById<ChipGroup>(R.id.urlRegexChipGroup)
|
||||
currentValue?.apply {
|
||||
for(chip in this.urlRegex) {
|
||||
val tmp = context.layoutInflater.inflate(R.layout.input_chip, urlRegexChips, false) as Chip
|
||||
tmp.text = chip
|
||||
tmp.setOnClickListener {
|
||||
urlRegexChips.removeView(tmp)
|
||||
}
|
||||
urlRegexChips.addView(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
urlRegexInput.setEndIconOnClickListener {
|
||||
val text = urlRegexInput.editText!!.text
|
||||
urlRegexInput.editText!!.setText("")
|
||||
val tmp = context.layoutInflater.inflate(R.layout.input_chip, urlRegexChips, false) as Chip
|
||||
tmp.text = text
|
||||
tmp.setOnClickListener {
|
||||
urlRegexChips.removeView(tmp)
|
||||
}
|
||||
urlRegexChips.addView(tmp)
|
||||
}
|
||||
|
||||
okBtn.setOnClickListener {
|
||||
val titleVal = title.editText!!.text.toString()
|
||||
if (titleVal.isBlank()) {
|
||||
|
|
@ -2397,6 +2467,10 @@ object UiUtil {
|
|||
poTokenInputs.filter { it.editText!!.text.isNotBlank() && it.tag.toString().startsWith("potoken") }.forEach {
|
||||
obj.poTokens.add(YoutubePoTokenItem(it.tag.toString().split("potoken_")[1], it.editText!!.text.toString()))
|
||||
}
|
||||
|
||||
val urlRegexes = urlRegexChips.children.map { (it as Chip).text.toString() }
|
||||
obj.urlRegex.addAll(urlRegexes)
|
||||
|
||||
bottomSheet.cancel()
|
||||
newValue(obj)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import androidx.preference.PreferenceManager
|
|||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||
import com.anggrayudi.storage.extension.count
|
||||
import com.deniscerri.ytdl.R
|
||||
import com.deniscerri.ytdl.database.dao.CommandTemplateDao
|
||||
import com.deniscerri.ytdl.database.models.ChapterItem
|
||||
import com.deniscerri.ytdl.database.models.DownloadItem
|
||||
import com.deniscerri.ytdl.database.models.Format
|
||||
|
|
@ -21,6 +22,7 @@ import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
|
|||
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdl.util.Extensions.getIntByAny
|
||||
import com.deniscerri.ytdl.util.Extensions.getStringByAny
|
||||
import com.deniscerri.ytdl.util.Extensions.isURL
|
||||
import com.deniscerri.ytdl.util.Extensions.isYoutubeURL
|
||||
import com.deniscerri.ytdl.util.Extensions.isYoutubeWatchVideosURL
|
||||
import com.deniscerri.ytdl.util.Extensions.toStringDuration
|
||||
|
|
@ -42,12 +44,12 @@ import java.util.Locale
|
|||
import java.util.StringJoiner
|
||||
import java.util.UUID
|
||||
|
||||
class YTDLPUtil(private val context: Context) {
|
||||
class YTDLPUtil(private val context: Context, private val commandTemplateDao: CommandTemplateDao) {
|
||||
private var sharedPreferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
private val formatUtil = FormatUtil(context)
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private fun YoutubeDLRequest.applyDefaultOptionsForFetchingData() {
|
||||
private fun YoutubeDLRequest.applyDefaultOptionsForFetchingData(url: String?) {
|
||||
addOption("--skip-download")
|
||||
addOption("-R", "1")
|
||||
addOption("--compat-options", "manifest-filesize-approx")
|
||||
|
|
@ -80,10 +82,17 @@ class YTDLPUtil(private val context: Context) {
|
|||
addOption("--no-check-certificates")
|
||||
}
|
||||
|
||||
val extraCommands = sharedPreferences.getString("data_fetching_extra_commands", "")!!
|
||||
if (extraCommands.isNotBlank()){
|
||||
var extraCommands = commandTemplateDao.getAllTemplatesAsDataFetchingExtraCommands()
|
||||
|
||||
if (url != null) {
|
||||
extraCommands = extraCommands.filter { it.urlRegex.any { u -> Regex(u).containsMatchIn(url) } }
|
||||
}else{
|
||||
extraCommands = extraCommands.filter { it.urlRegex.isEmpty() }
|
||||
}
|
||||
|
||||
if (extraCommands.isNotEmpty()){
|
||||
//addCommands(extraCommands.split(" ", "\t", "\n"))
|
||||
addConfig(extraCommands)
|
||||
addConfig(extraCommands.joinToString(" ") { it.content })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -114,12 +123,12 @@ class YTDLPUtil(private val context: Context) {
|
|||
}
|
||||
}
|
||||
if (searchEngine == "ytsearch" || query.isYoutubeURL()) {
|
||||
request.setYoutubeExtractorArgs()
|
||||
request.setYoutubeExtractorArgs(query)
|
||||
}
|
||||
|
||||
request.addOption("--flat-playlist")
|
||||
request.addOption(if (singleItem) "-J" else "-j")
|
||||
request.applyDefaultOptionsForFetchingData()
|
||||
request.applyDefaultOptionsForFetchingData(if (query.isURL()) query else null)
|
||||
|
||||
println(parseYTDLRequestString(request))
|
||||
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
|
||||
|
|
@ -249,15 +258,15 @@ class YTDLPUtil(private val context: Context) {
|
|||
items.add(res)
|
||||
}
|
||||
|
||||
return items;
|
||||
return items
|
||||
}
|
||||
|
||||
fun getYoutubeWatchLater() : ArrayList<ResultItem> {
|
||||
val request = YoutubeDLRequest(listOf())
|
||||
request.setYoutubeExtractorArgs()
|
||||
request.setYoutubeExtractorArgs(null)
|
||||
request.addOption( "-j")
|
||||
request.addOption("--flat-playlist")
|
||||
request.applyDefaultOptionsForFetchingData()
|
||||
request.applyDefaultOptionsForFetchingData(null)
|
||||
request.addOption(":ytwatchlater")
|
||||
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
|
||||
val results: List<String?> = try {
|
||||
|
|
@ -273,10 +282,10 @@ class YTDLPUtil(private val context: Context) {
|
|||
|
||||
fun getYoutubeRecommendations() : ArrayList<ResultItem> {
|
||||
val request = YoutubeDLRequest(listOf())
|
||||
request.setYoutubeExtractorArgs()
|
||||
request.setYoutubeExtractorArgs(null)
|
||||
request.addOption( "-j")
|
||||
request.addOption("--flat-playlist")
|
||||
request.applyDefaultOptionsForFetchingData()
|
||||
request.applyDefaultOptionsForFetchingData(null)
|
||||
request.addOption(":ytrec")
|
||||
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
|
||||
val results: List<String?> = try {
|
||||
|
|
@ -292,10 +301,10 @@ class YTDLPUtil(private val context: Context) {
|
|||
|
||||
fun getYoutubeLikedVideos() : ArrayList<ResultItem> {
|
||||
val request = YoutubeDLRequest(listOf())
|
||||
request.setYoutubeExtractorArgs()
|
||||
request.setYoutubeExtractorArgs(null)
|
||||
request.addOption( "-j")
|
||||
request.addOption("--flat-playlist")
|
||||
request.applyDefaultOptionsForFetchingData()
|
||||
request.applyDefaultOptionsForFetchingData(null)
|
||||
request.addOption(":ytfav")
|
||||
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
|
||||
val results: List<String?> = try {
|
||||
|
|
@ -311,10 +320,10 @@ class YTDLPUtil(private val context: Context) {
|
|||
|
||||
fun getYoutubeWatchHistory() : ArrayList<ResultItem> {
|
||||
val request = YoutubeDLRequest(listOf())
|
||||
request.setYoutubeExtractorArgs()
|
||||
request.setYoutubeExtractorArgs(null)
|
||||
request.addOption( "-j")
|
||||
request.addOption("--flat-playlist")
|
||||
request.applyDefaultOptionsForFetchingData()
|
||||
request.applyDefaultOptionsForFetchingData(null)
|
||||
request.addOption(":ythis")
|
||||
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
|
||||
val results: List<String?> = try {
|
||||
|
|
@ -344,9 +353,9 @@ class YTDLPUtil(private val context: Context) {
|
|||
val request = YoutubeDLRequest(emptyList())
|
||||
request.addOption("--print", "formats")
|
||||
request.addOption("-a", urlsFile.absolutePath)
|
||||
request.applyDefaultOptionsForFetchingData()
|
||||
request.applyDefaultOptionsForFetchingData(urls.firstOrNull { it.isURL() })
|
||||
if (urls.all { it.isYoutubeURL() }) {
|
||||
request.setYoutubeExtractorArgs()
|
||||
request.setYoutubeExtractorArgs(urls[0])
|
||||
}
|
||||
|
||||
val txt = parseYTDLRequestString(request)
|
||||
|
|
@ -416,9 +425,9 @@ class YTDLPUtil(private val context: Context) {
|
|||
val request = YoutubeDLRequest(url)
|
||||
request.addOption("--print", "%(formats)s")
|
||||
request.addOption("--print", "%(duration)s")
|
||||
request.applyDefaultOptionsForFetchingData()
|
||||
request.applyDefaultOptionsForFetchingData(url)
|
||||
if (url.isYoutubeURL()) {
|
||||
request.setYoutubeExtractorArgs()
|
||||
request.setYoutubeExtractorArgs(url)
|
||||
}
|
||||
|
||||
val res = YoutubeDL.getInstance().execute(request)
|
||||
|
|
@ -501,9 +510,9 @@ class YTDLPUtil(private val context: Context) {
|
|||
val request = YoutubeDLRequest(url)
|
||||
request.addOption("--get-url")
|
||||
request.addOption("--print", "%(.{urls,chapters})s")
|
||||
request.applyDefaultOptionsForFetchingData()
|
||||
request.applyDefaultOptionsForFetchingData(url)
|
||||
if (url.isYoutubeURL()) {
|
||||
request.setYoutubeExtractorArgs()
|
||||
request.setYoutubeExtractorArgs(url)
|
||||
}
|
||||
|
||||
val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
|
||||
|
|
@ -752,7 +761,7 @@ class YTDLPUtil(private val context: Context) {
|
|||
}
|
||||
|
||||
if (downloadItem.url.isYoutubeURL()) {
|
||||
ytDlRequest.setYoutubeExtractorArgs()
|
||||
ytDlRequest.setYoutubeExtractorArgs(downloadItem.url)
|
||||
}
|
||||
|
||||
//TODO REVIEW TO ADD THIS AGAIN LATER?
|
||||
|
|
@ -1242,7 +1251,7 @@ class YTDLPUtil(private val context: Context) {
|
|||
return YoutubeDL.getInstance().execute(req).out.trim()
|
||||
}
|
||||
|
||||
private fun YoutubeDLRequest.setYoutubeExtractorArgs() {
|
||||
private fun YoutubeDLRequest.setYoutubeExtractorArgs(url: String?) {
|
||||
val extractorArgs = mutableListOf<String>()
|
||||
val playerClients = mutableListOf<String>()
|
||||
val poTokens = mutableListOf<String>()
|
||||
|
|
@ -1256,8 +1265,15 @@ class YTDLPUtil(private val context: Context) {
|
|||
playerClients.add(value.playerClient)
|
||||
}
|
||||
|
||||
value.poTokens.forEach { pt ->
|
||||
poTokens.add("${value.playerClient}.${pt.context}+${pt.token}")
|
||||
var canUsePoToken = true
|
||||
if (value.urlRegex.isNotEmpty() && url != null) {
|
||||
canUsePoToken = value.urlRegex.any { url.matches(it.toRegex()) }
|
||||
}
|
||||
|
||||
if (canUsePoToken) {
|
||||
value.poTokens.forEach { pt ->
|
||||
poTokens.add("${value.playerClient}.${pt.context}+${pt.token}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,12 +65,13 @@ class DownloadWorker(
|
|||
}
|
||||
|
||||
val notificationUtil = NotificationUtil(App.instance)
|
||||
val ytdlpUtil = YTDLPUtil(context)
|
||||
val dbManager = DBManager.getInstance(context)
|
||||
val dao = dbManager.downloadDao
|
||||
val historyDao = dbManager.historyDao
|
||||
val commandTemplateDao = dbManager.commandTemplateDao
|
||||
val logRepo = LogRepository(dbManager.logDao)
|
||||
val resultRepo = ResultRepository(dbManager.resultDao, context)
|
||||
val resultRepo = ResultRepository(dbManager.resultDao, commandTemplateDao, context)
|
||||
val ytdlpUtil = YTDLPUtil(context, commandTemplateDao)
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
val alarmScheduler = AlarmScheduler(context)
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
|
@ -187,7 +188,7 @@ class DownloadWorker(
|
|||
"Title: ${downloadItem.title}\n" +
|
||||
"URL: ${downloadItem.url}\n" +
|
||||
"Type: ${downloadItem.type}\n" +
|
||||
"Command: \n $commandString \n\n"
|
||||
"Command:\n$commandString \n\n"
|
||||
val logString = StringBuilder(initialLogDetails)
|
||||
val logItem = LogItem(
|
||||
0,
|
||||
|
|
@ -210,7 +211,7 @@ class DownloadWorker(
|
|||
runCatching {
|
||||
YoutubeDL.getInstance().destroyProcessById(downloadItem.id.toString())
|
||||
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
|
||||
eventBus.post(WorkerProgress(progress.toInt(), line, downloadItem.id))
|
||||
eventBus.post(WorkerProgress(progress.toInt(), line, downloadItem.id, downloadItem.logID))
|
||||
val title: String = downloadItem.title.ifEmpty { downloadItem.url }
|
||||
notificationUtil.updateDownloadNotification(
|
||||
downloadItem.id.toInt(),
|
||||
|
|
@ -233,7 +234,7 @@ class DownloadWorker(
|
|||
var finalPaths = mutableListOf<String>()
|
||||
|
||||
if (noCache){
|
||||
eventBus.post(WorkerProgress(100, "Scanning Files", downloadItem.id))
|
||||
eventBus.post(WorkerProgress(100, "Scanning Files", downloadItem.id, downloadItem.logID))
|
||||
val outputSequence = it.out.split("\n")
|
||||
finalPaths =
|
||||
outputSequence.asSequence()
|
||||
|
|
@ -255,16 +256,16 @@ class DownloadWorker(
|
|||
FileUtil.scanMedia(finalPaths, context)
|
||||
}else{
|
||||
//move file from internal to set download directory
|
||||
eventBus.post(WorkerProgress(100, "Moving file to ${FileUtil.formatPath(downloadLocation)}", downloadItem.id))
|
||||
eventBus.post(WorkerProgress(100, "Moving file to ${FileUtil.formatPath(downloadLocation)}", downloadItem.id, downloadItem.logID))
|
||||
try {
|
||||
finalPaths = withContext(Dispatchers.IO){
|
||||
FileUtil.moveFile(tempFileDir.absoluteFile,context, downloadLocation, keepCache){ p ->
|
||||
eventBus.post(WorkerProgress(p, "Moving file to ${FileUtil.formatPath(downloadLocation)}", downloadItem.id))
|
||||
eventBus.post(WorkerProgress(p, "Moving file to ${FileUtil.formatPath(downloadLocation)}", downloadItem.id, downloadItem.logID))
|
||||
}
|
||||
}.filter { !it.matches("\\.(description)|(txt)\$".toRegex()) }.toMutableList()
|
||||
|
||||
if (finalPaths.isNotEmpty()){
|
||||
eventBus.post(WorkerProgress(100, "Moved file to ${FileUtil.formatPath(downloadLocation)}", downloadItem.id))
|
||||
eventBus.post(WorkerProgress(100, "Moved file to ${FileUtil.formatPath(downloadLocation)}", downloadItem.id, downloadItem.logID))
|
||||
}
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
|
|
@ -346,7 +347,7 @@ class DownloadWorker(
|
|||
dao.delete(downloadItem.id)
|
||||
|
||||
if (logDownloads){
|
||||
logRepo.update(initialLogDetails + "\n" + it.out, logItem.id, true)
|
||||
logRepo.update(initialLogDetails + it.out, logItem.id, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -395,7 +396,7 @@ class DownloadWorker(
|
|||
resources
|
||||
)
|
||||
|
||||
eventBus.post(WorkerProgress(100, it.toString(), downloadItem.id))
|
||||
eventBus.post(WorkerProgress(100, it.toString(), downloadItem.id, downloadItem.logID))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -423,7 +424,8 @@ class DownloadWorker(
|
|||
class WorkerProgress(
|
||||
val progress: Int,
|
||||
val output: String,
|
||||
val downloadItemID: Long
|
||||
val downloadItemID: Long,
|
||||
val logItemID: Long?
|
||||
)
|
||||
|
||||
}
|
||||
|
|
@ -43,10 +43,10 @@ class ObserveSourceWorker(
|
|||
if (sourceID == 0L) return Result.failure()
|
||||
val dbManager = DBManager.getInstance(context)
|
||||
val repo = ObserveSourcesRepository(dbManager.observeSourcesDao)
|
||||
val resultsRepo = ResultRepository(dbManager.resultDao, App.instance)
|
||||
val historyRepo = HistoryRepository(dbManager.historyDao)
|
||||
val downloadRepo = DownloadRepository(dbManager.downloadDao)
|
||||
val ytdlpUtil = YTDLPUtil(context)
|
||||
val commandTemplateDao = dbManager.commandTemplateDao
|
||||
val ytdlpUtil = YTDLPUtil(context, commandTemplateDao)
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
val item = repo.getByID(sourceID)
|
||||
|
|
@ -193,16 +193,9 @@ class ObserveSourceWorker(
|
|||
|
||||
item.runCount += 1
|
||||
|
||||
if (item.runCount > item.endsAfterCount && item.endsAfterCount > 0){
|
||||
item.status = ObserveSourcesRepository.SourceStatus.STOPPED
|
||||
withContext(Dispatchers.IO){
|
||||
repo.update(item)
|
||||
}
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
val currentTime = System.currentTimeMillis()
|
||||
if (item.endsDate >= currentTime || item.endsAfterCount == item.runCount){
|
||||
val isFinished = (item.endsAfterCount > 0 && item.runCount >= item.endsAfterCount) || item.endsDate >= currentTime
|
||||
if (isFinished) {
|
||||
item.status = ObserveSourcesRepository.SourceStatus.STOPPED
|
||||
withContext(Dispatchers.IO){
|
||||
repo.update(item)
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class TerminalDownloadWorker(
|
|||
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
|
||||
|
||||
val initialLogDetails = "Terminal Task\n" +
|
||||
"Command: \n ${command}\n\n"
|
||||
"Command:\n${command.trim()}\n\n"
|
||||
val logItem = LogItem(
|
||||
0,
|
||||
"Terminal Task",
|
||||
|
|
@ -122,7 +122,7 @@ class TerminalDownloadWorker(
|
|||
|
||||
YoutubeDL.getInstance().execute(request, itemId.toString()){ progress, _, line ->
|
||||
runBlocking {
|
||||
eventBus.post(DownloadWorker.WorkerProgress(progress.toInt(), line, itemId.toLong()))
|
||||
eventBus.post(DownloadWorker.WorkerProgress(progress.toInt(), line, itemId.toLong(), logItem.id))
|
||||
}
|
||||
|
||||
val title: String = command.take(65)
|
||||
|
|
@ -142,7 +142,7 @@ class TerminalDownloadWorker(
|
|||
//move file from internal to set download directory
|
||||
try {
|
||||
FileUtil.moveFile(File(FileUtil.getCachePath(context) + "/TERMINAL/" + itemId),context, downloadLocation!!, false){ p ->
|
||||
eventBus.post(DownloadWorker.WorkerProgress(p, "", itemId.toLong()))
|
||||
eventBus.post(DownloadWorker.WorkerProgress(p, "", itemId.toLong(), logItem.id))
|
||||
}
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ class UpdateMultipleDownloadsDataWorker(
|
|||
val dbManager = DBManager.getInstance(context)
|
||||
val dao = dbManager.downloadDao
|
||||
val resDao = dbManager.resultDao
|
||||
val resultRepo = ResultRepository(resDao, context)
|
||||
val commandTemplateDao = dbManager.commandTemplateDao
|
||||
val resultRepo = ResultRepository(resDao,commandTemplateDao, context)
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val ids = inputData.getLongArray("ids")!!.toMutableList()
|
||||
val workID = inputData.getInt("id", 0)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ class UpdateMultipleDownloadsFormatsWorker(
|
|||
val dbManager = DBManager.getInstance(context)
|
||||
val dao = dbManager.downloadDao
|
||||
val resDao = dbManager.resultDao
|
||||
val resultRepo = ResultRepository(resDao, context)
|
||||
val commandTemplateDao = dbManager.commandTemplateDao
|
||||
val resultRepo = ResultRepository(resDao, commandTemplateDao, context)
|
||||
val vm = DownloadViewModel(App.instance)
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val ids = inputData.getLongArray("ids")!!.toMutableList()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
|
|
@ -172,6 +173,35 @@
|
|||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/url_regex"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="url_regex"
|
||||
android:hint="URL Regex"
|
||||
android:visibility="gone"
|
||||
app:endIconDrawable="@drawable/ic_plus"
|
||||
app:endIconMode="custom"
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/urlRegexChipGroup"
|
||||
android:layout_width="wrap_content"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:singleSelection="true"
|
||||
app:chipSpacing="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="false" />
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.facebook.shimmer.ShimmerFrameLayout
|
||||
|
|
@ -131,8 +131,7 @@
|
|||
android:id="@+id/download_tablayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_margin="10dp"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
app:tabGravity="start"
|
||||
app:tabMinWidth="0dp"
|
||||
|
|
|
|||
|
|
@ -22,12 +22,11 @@
|
|||
<TextView
|
||||
android:id="@+id/container"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/rounded_corner"
|
||||
android:backgroundTint="?attr/colorPrimaryInverse"
|
||||
android:textColor="@color/white"
|
||||
android:clickable="false"
|
||||
app:layout_constraintDimensionRatio="H,1:1"
|
||||
android:layout_height="55dp"
|
||||
android:gravity="center"
|
||||
android:minWidth="30dp"
|
||||
app:cornerRadius="10dp"
|
||||
|
|
|
|||
|
|
@ -82,6 +82,13 @@
|
|||
|
||||
</FrameLayout>
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/coordinatorLayout3"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/coordinatorLayout3"
|
||||
android:layout_width="0dp"
|
||||
|
|
|
|||
|
|
@ -488,34 +488,141 @@
|
|||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/get_new_uploads"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="false"
|
||||
android:text="@string/get_new_uploads"/>
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/sync_with_source"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="false"
|
||||
android:text="@string/sync_with_source"/>
|
||||
<TextView
|
||||
android:id="@+id/textView9"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/get_new_uploads"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/get_new_uploads"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/retry_missing_downloads"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="false"
|
||||
android:text="@string/retry_missing_downloads"/>
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/get_new_uploads"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/reset_processed_links"
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="false"
|
||||
android:text="@string/reset_processed_links"/>
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView10"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/retry_missing_downloads"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@+id/retry_missing_downloads"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView11"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/retry_missing_downloads_desc"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/retry_missing_downloads"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView10" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/retry_missing_downloads"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView12"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/sync_with_source"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@+id/sync_with_source"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView13"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/sync_with_source_desc"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/sync_with_source"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView12" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/sync_with_source"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView14"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/reset_processed_links"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@+id/reset_processed_links"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView15"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/reset_processed_links_desc"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/reset_processed_links"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView14" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/reset_processed_links"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -170,6 +170,34 @@
|
|||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/url_regex"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="url_regex"
|
||||
android:hint="PO Token URL Regex"
|
||||
app:endIconDrawable="@drawable/ic_plus"
|
||||
app:endIconMode="custom"
|
||||
android:paddingBottom="10dp"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/urlRegexChipGroup"
|
||||
android:layout_width="wrap_content"
|
||||
app:chipSpacingVertical="-10dp"
|
||||
app:singleSelection="true"
|
||||
app:chipSpacing="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:singleLine="false" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/use_only_po_token"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -357,6 +357,7 @@
|
|||
<string name="week">Week</string>
|
||||
<string name="month">Month</string>
|
||||
<string name="retry_missing_downloads">Retry Missing Downloads</string>
|
||||
<string name="retry_missing_downloads_desc">Re-download items not present in the download history</string>
|
||||
<string name="bitrate">Bitrate</string>
|
||||
<string name="save_auto_subs">Save Automatic Subtitles</string>
|
||||
<string name="not_deleted">Not Deleted</string>
|
||||
|
|
@ -365,7 +366,7 @@
|
|||
<string name="swipe_gestures_download_card">Swipe Gestures in download card</string>
|
||||
<string name="show_download_count">Show counts in the download queue screen</string>
|
||||
<string name="thumbnail_format">Thumbnail Format</string>
|
||||
<string name="get_new_uploads">Get New Uploads Only</string>
|
||||
<string name="get_new_uploads">Get Future Uploads Only (Ignore Existing Items)</string>
|
||||
<string name="also_download_audio">Also Download as Audio</string>
|
||||
<string name="wrap_text">Wrap Text</string>
|
||||
<string name="scroll_down">Scroll to the Bottom</string>
|
||||
|
|
@ -375,6 +376,7 @@
|
|||
<string name="all_queries_finished">All Queries have been processed</string>
|
||||
<string name="select_between">Select Items Between</string>
|
||||
<string name="reset_processed_links">Reset Already Processed Links</string>
|
||||
<string name="reset_processed_links_desc">Re-download all items again</string>
|
||||
<string name="no_download_fragments">Don\'t download as Fragments</string>
|
||||
<string name="no_download_fragments_summary">Don\'t use .part files and write directly into output file</string>
|
||||
<string name="my_filename_templates">My Filename Templates</string>
|
||||
|
|
@ -405,6 +407,7 @@
|
|||
<string name="label_visibility">Label Visibility</string>
|
||||
<string name="always">Always</string>
|
||||
<string name="sync_with_source">Sync With Source</string>
|
||||
<string name="sync_with_source_desc">Delete downloaded items if they are missing in the source</string>
|
||||
<string name="queue">Queue</string>
|
||||
<string name="reset">Reset</string>
|
||||
<string name="restore_info">Press \'Restore\' to merge the saved data with your current data.\nPress \'Reset\' to erase and only use the saved data in the file.</string>
|
||||
|
|
|
|||
Loading…
Reference in a new issue