few changes
-made the download logs not freeze the app -download logs will work on quick downloaded items that were later updated -added app arch and build type in the about section -added "force-keyframes-at-cuts" preference
This commit is contained in:
parent
1783b40608
commit
d659686e01
26 changed files with 869 additions and 280 deletions
|
|
@ -10,11 +10,11 @@ def properties = new Properties()
|
||||||
def versionMajor = 1
|
def versionMajor = 1
|
||||||
def versionMinor = 6
|
def versionMinor = 6
|
||||||
def versionPatch = 3
|
def versionPatch = 3
|
||||||
def versionBuild = 2 // bump for dogfood builds, public betas, etc.
|
def versionBuild = 4 // bump for dogfood builds, public betas, etc.
|
||||||
def versionExt = ""
|
def versionExt = ""
|
||||||
|
|
||||||
if (versionBuild > 0){
|
if (versionBuild > 0){
|
||||||
versionExt = ".${versionBuild}-beta"
|
versionExt = ".${versionBuild}"
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
|
@ -72,7 +72,8 @@ android {
|
||||||
|
|
||||||
beta {
|
beta {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
shrinkResources true
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
debuggable false
|
debuggable false
|
||||||
signingConfig signingConfigs.debug
|
signingConfig signingConfigs.debug
|
||||||
}
|
}
|
||||||
|
|
|
||||||
486
app/schemas/com.deniscerri.ytdlnis.database.DBManager/8.json
Normal file
486
app/schemas/com.deniscerri.ytdlnis.database.DBManager/8.json
Normal file
|
|
@ -0,0 +1,486 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 8,
|
||||||
|
"identityHash": "b21f2aa737d29eef2c1bf6418b314726",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "results",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `website` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `formats` TEXT NOT NULL, `urls` TEXT NOT NULL DEFAULT '', `chapters` TEXT, `creationTime` INTEGER NOT NULL)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "url",
|
||||||
|
"columnName": "url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "title",
|
||||||
|
"columnName": "title",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "author",
|
||||||
|
"columnName": "author",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "duration",
|
||||||
|
"columnName": "duration",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "thumb",
|
||||||
|
"columnName": "thumb",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "website",
|
||||||
|
"columnName": "website",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "playlistTitle",
|
||||||
|
"columnName": "playlistTitle",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "formats",
|
||||||
|
"columnName": "formats",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "urls",
|
||||||
|
"columnName": "urls",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "''"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "chapters",
|
||||||
|
"columnName": "chapters",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "creationTime",
|
||||||
|
"columnName": "creationTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "history",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadId` INTEGER NOT NULL DEFAULT 0)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "url",
|
||||||
|
"columnName": "url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "title",
|
||||||
|
"columnName": "title",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "author",
|
||||||
|
"columnName": "author",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "duration",
|
||||||
|
"columnName": "duration",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "thumb",
|
||||||
|
"columnName": "thumb",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "time",
|
||||||
|
"columnName": "time",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadPath",
|
||||||
|
"columnName": "downloadPath",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "website",
|
||||||
|
"columnName": "website",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "format",
|
||||||
|
"columnName": "format",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadId",
|
||||||
|
"columnName": "downloadId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "downloads",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `format` TEXT NOT NULL, `container` TEXT NOT NULL DEFAULT 'Default', `downloadSections` TEXT NOT NULL DEFAULT '', `allFormats` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `audioPreferences` TEXT NOT NULL, `videoPreferences` TEXT NOT NULL, `customFileNameTemplate` TEXT NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `downloadStartTime` INTEGER NOT NULL DEFAULT 0, `logID` INTEGER)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "url",
|
||||||
|
"columnName": "url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "title",
|
||||||
|
"columnName": "title",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "author",
|
||||||
|
"columnName": "author",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "thumb",
|
||||||
|
"columnName": "thumb",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "duration",
|
||||||
|
"columnName": "duration",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "format",
|
||||||
|
"columnName": "format",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "container",
|
||||||
|
"columnName": "container",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "'Default'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadSections",
|
||||||
|
"columnName": "downloadSections",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "''"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "allFormats",
|
||||||
|
"columnName": "allFormats",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadPath",
|
||||||
|
"columnName": "downloadPath",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "website",
|
||||||
|
"columnName": "website",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadSize",
|
||||||
|
"columnName": "downloadSize",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "playlistTitle",
|
||||||
|
"columnName": "playlistTitle",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "audioPreferences",
|
||||||
|
"columnName": "audioPreferences",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "videoPreferences",
|
||||||
|
"columnName": "videoPreferences",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "customFileNameTemplate",
|
||||||
|
"columnName": "customFileNameTemplate",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "SaveThumb",
|
||||||
|
"columnName": "SaveThumb",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "status",
|
||||||
|
"columnName": "status",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "'Queued'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadStartTime",
|
||||||
|
"columnName": "downloadStartTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "logID",
|
||||||
|
"columnName": "logID",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "commandTemplates",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "title",
|
||||||
|
"columnName": "title",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "content",
|
||||||
|
"columnName": "content",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "searchHistory",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `query` TEXT NOT NULL)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "query",
|
||||||
|
"columnName": "query",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "templateShortcuts",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `content` TEXT NOT NULL)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "content",
|
||||||
|
"columnName": "content",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "cookies",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `content` TEXT NOT NULL)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "url",
|
||||||
|
"columnName": "url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "content",
|
||||||
|
"columnName": "content",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "title",
|
||||||
|
"columnName": "title",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "content",
|
||||||
|
"columnName": "content",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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, 'b21f2aa737d29eef2c1bf6418b314726')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -84,6 +84,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
if (item.author.isNotEmpty()) info += " • "
|
if (item.author.isNotEmpty()) info += " • "
|
||||||
info += item.duration
|
info += item.duration
|
||||||
}
|
}
|
||||||
|
author.text = info
|
||||||
|
|
||||||
val type = card.findViewById<MaterialButton>(R.id.download_type)
|
val type = card.findViewById<MaterialButton>(R.id.download_type)
|
||||||
when(item.type){
|
when(item.type){
|
||||||
|
|
@ -93,7 +94,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
}
|
}
|
||||||
|
|
||||||
val formatDetailsChip = card.findViewById<Chip>(R.id.format_note)
|
val formatDetailsChip = card.findViewById<Chip>(R.id.format_note)
|
||||||
val formatDetailsText = StringBuilder(item.format.format_note.uppercase()+"\t")
|
val formatDetailsText = StringBuilder(item.format.format_note.uppercase())
|
||||||
|
|
||||||
val codecText =
|
val codecText =
|
||||||
if (item.format.encoding != "") {
|
if (item.format.encoding != "") {
|
||||||
|
|
@ -104,11 +105,11 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
item.format.acodec.uppercase()
|
item.format.acodec.uppercase()
|
||||||
}
|
}
|
||||||
if (codecText != "" && codecText != "none"){
|
if (codecText != "" && codecText != "none"){
|
||||||
formatDetailsText.append("\t|\t$codecText")
|
formatDetailsText.append(" \t •\t $codecText")
|
||||||
}
|
}
|
||||||
|
|
||||||
val fileSize = FileUtil.convertFileSize(item.format.filesize)
|
val fileSize = FileUtil.convertFileSize(item.format.filesize)
|
||||||
if (fileSize != "?") formatDetailsText.append("\t|\t$fileSize")
|
if (fileSize != "?") formatDetailsText.append(" \t •\t $fileSize")
|
||||||
|
|
||||||
formatDetailsChip.text = formatDetailsText
|
formatDetailsChip.text = formatDetailsText
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,10 @@ import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class DownloadLogsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<File?, DownloadLogsAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class DownloadLogsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<LogItem?, DownloadLogsAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
|
|
||||||
|
|
@ -42,7 +43,7 @@ class DownloadLogsAdapter(onItemClickListener: OnItemClickListener, activity: Ac
|
||||||
val card = holder.item
|
val card = holder.item
|
||||||
|
|
||||||
val title = card.findViewById<TextView>(R.id.title)
|
val title = card.findViewById<TextView>(R.id.title)
|
||||||
title.text = item?.name
|
title.text = item?.title
|
||||||
|
|
||||||
val delete = card.findViewById<Button>(R.id.delete)
|
val delete = card.findViewById<Button>(R.id.delete)
|
||||||
|
|
||||||
|
|
@ -56,18 +57,18 @@ class DownloadLogsAdapter(onItemClickListener: OnItemClickListener, activity: Ac
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnItemClickListener {
|
interface OnItemClickListener {
|
||||||
fun onItemClick(file: File)
|
fun onItemClick(item: LogItem)
|
||||||
fun onDeleteClick(file: File)
|
fun onDeleteClick(item: LogItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<File> = object : DiffUtil.ItemCallback<File>() {
|
private val DIFF_CALLBACK: DiffUtil.ItemCallback<LogItem> = object : DiffUtil.ItemCallback<LogItem>() {
|
||||||
override fun areItemsTheSame(oldItem: File, newItem: File): Boolean {
|
override fun areItemsTheSame(oldItem: LogItem, newItem: LogItem): Boolean {
|
||||||
return oldItem == newItem
|
return oldItem.id == newItem.id
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: File, newItem: File): Boolean {
|
override fun areContentsTheSame(oldItem: LogItem, newItem: LogItem): Boolean {
|
||||||
return oldItem.absolutePath == newItem.absolutePath
|
return oldItem.content == newItem.content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,7 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
DownloadRepository.Status.Queued.toString() -> actionButton.setIconResource(R.drawable.ic_baseline_delete_outline_24)
|
DownloadRepository.Status.Queued.toString() -> actionButton.setIconResource(R.drawable.ic_baseline_delete_outline_24)
|
||||||
else -> {
|
else -> {
|
||||||
actionButton.setIconResource(R.drawable.ic_baseline_file_open_24)
|
actionButton.setIconResource(R.drawable.ic_baseline_file_open_24)
|
||||||
val logFile = FileUtil.checkLogFileExists(activity, item)
|
if (item.logID == null){
|
||||||
if (logFile == null){
|
|
||||||
actionButton.visibility = View.GONE
|
actionButton.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,16 @@ import com.deniscerri.ytdlnis.database.models.*
|
||||||
|
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
@Database(
|
@Database(
|
||||||
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class, SearchHistoryItem::class, TemplateShortcut::class, CookieItem::class],
|
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class, SearchHistoryItem::class, TemplateShortcut::class, CookieItem::class, LogItem::class],
|
||||||
version = 7,
|
version = 8,
|
||||||
autoMigrations = [
|
autoMigrations = [
|
||||||
AutoMigration (from = 1, to = 2),
|
AutoMigration (from = 1, to = 2),
|
||||||
AutoMigration (from = 2, to = 3),
|
AutoMigration (from = 2, to = 3),
|
||||||
AutoMigration (from = 3, to = 4),
|
AutoMigration (from = 3, to = 4),
|
||||||
AutoMigration (from = 4, to = 5),
|
AutoMigration (from = 4, to = 5),
|
||||||
AutoMigration (from = 5, to = 6),
|
AutoMigration (from = 5, to = 6),
|
||||||
AutoMigration (from = 6, to = 7)
|
AutoMigration (from = 6, to = 7),
|
||||||
|
AutoMigration (from = 7, to = 8)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
abstract class DBManager : RoomDatabase(){
|
abstract class DBManager : RoomDatabase(){
|
||||||
|
|
@ -25,6 +26,7 @@ abstract class DBManager : RoomDatabase(){
|
||||||
abstract val commandTemplateDao : CommandTemplateDao
|
abstract val commandTemplateDao : CommandTemplateDao
|
||||||
abstract val searchHistoryDao: SearchHistoryDao
|
abstract val searchHistoryDao: SearchHistoryDao
|
||||||
abstract val cookieDao: CookieDao
|
abstract val cookieDao: CookieDao
|
||||||
|
abstract val logDao: LogDao
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
//prevents multiple instances of db getting created at the same time
|
//prevents multiple instances of db getting created at the same time
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.deniscerri.ytdlnis.database.dao
|
||||||
|
|
||||||
|
import androidx.room.*
|
||||||
|
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||||
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface LogDao {
|
||||||
|
@Query("SELECT * FROM logs ORDER BY id DESC")
|
||||||
|
fun getAllLogs() : List<LogItem>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM logs ORDER BY id DESC")
|
||||||
|
fun getAllLogsFlow() : Flow<List<LogItem>>
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
suspend fun insert(item: LogItem) : Long
|
||||||
|
|
||||||
|
@Query("DELETE FROM logs")
|
||||||
|
suspend fun deleteAll()
|
||||||
|
|
||||||
|
@Query("DELETE FROM logs WHERE id=:itemId")
|
||||||
|
suspend fun delete(itemId: Long)
|
||||||
|
|
||||||
|
@Update(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun update(item: LogItem)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM logs WHERE id=:id LIMIT 1")
|
||||||
|
fun getByID(id: Long) : LogItem
|
||||||
|
}
|
||||||
|
|
@ -32,5 +32,6 @@ data class DownloadItem(
|
||||||
@ColumnInfo(defaultValue = "Queued")
|
@ColumnInfo(defaultValue = "Queued")
|
||||||
var status: String,
|
var status: String,
|
||||||
@ColumnInfo(defaultValue = "0")
|
@ColumnInfo(defaultValue = "0")
|
||||||
var downloadStartTime: Long
|
var downloadStartTime: Long,
|
||||||
|
var logID: Long?
|
||||||
)
|
)
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.deniscerri.ytdlnis.database.models
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(tableName = "logs")
|
||||||
|
data class LogItem(
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
var id: Long,
|
||||||
|
var title: String,
|
||||||
|
var content: String
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package com.deniscerri.ytdlnis.database.repository
|
||||||
|
|
||||||
|
import com.deniscerri.ytdlnis.database.dao.LogDao
|
||||||
|
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||||
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
class LogRepository(private val logDao: LogDao) {
|
||||||
|
val items : Flow<List<LogItem>> = logDao.getAllLogsFlow()
|
||||||
|
|
||||||
|
fun getAll() : List<LogItem> {
|
||||||
|
return logDao.getAllLogs()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun insert(item: LogItem) : Long{
|
||||||
|
return logDao.insert(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun delete(item: LogItem){
|
||||||
|
logDao.delete(item.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun deleteAll(){
|
||||||
|
logDao.deleteAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getItem(id: Long) : LogItem{
|
||||||
|
return logDao.getByID(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun update(newLine: String, id: Long){
|
||||||
|
val item = getItem(id)
|
||||||
|
item.content += "${newLine}\n"
|
||||||
|
logDao.update(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -180,7 +180,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
sharedPreferences.getString("video_format", "Default")!!,
|
sharedPreferences.getString("video_format", "Default")!!,
|
||||||
"",
|
"",
|
||||||
resultItem.formats,
|
resultItem.formats,
|
||||||
downloadPath!!, resultItem.website, "", resultItem.playlistTitle, audioPreferences, videoPreferences,customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Processing.toString(), 0
|
downloadPath!!, resultItem.website, "", resultItem.playlistTitle, audioPreferences, videoPreferences,customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Processing.toString(), 0, null
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -302,7 +302,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
container,
|
container,
|
||||||
"",
|
"",
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
path, historyItem.website, "", "", audioPreferences, videoPreferences,customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Processing.toString(), 0
|
path, historyItem.website, "", "", audioPreferences, videoPreferences,customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Processing.toString(), 0, null
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package com.deniscerri.ytdlnis.database.viewmodel
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.asLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.deniscerri.ytdlnis.database.DBManager
|
||||||
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
|
import com.deniscerri.ytdlnis.database.repository.LogRepository
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class LogViewModel(private val application: Application) : AndroidViewModel(application) {
|
||||||
|
private val repository: LogRepository
|
||||||
|
val items: LiveData<List<LogItem>>
|
||||||
|
|
||||||
|
init {
|
||||||
|
val dao = DBManager.getInstance(application).logDao
|
||||||
|
repository = LogRepository(dao)
|
||||||
|
items = repository.items.asLiveData()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getItemById(id: Long): LogItem{
|
||||||
|
return repository.getItem(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAll(): List<LogItem> {
|
||||||
|
return repository.getAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun insert(item: LogItem) : Long {
|
||||||
|
return repository.insert(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun delete(item: LogItem) = viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
repository.delete(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteAll() = viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
repository.deleteAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(newLine: String, id: Long) = viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
repository.update(newLine, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -18,8 +18,6 @@ import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import com.yausername.youtubedl_android.YoutubeDL
|
import com.yausername.youtubedl_android.YoutubeDL
|
||||||
|
|
@ -98,10 +96,9 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOutputClick(item: DownloadItem) {
|
override fun onOutputClick(item: DownloadItem) {
|
||||||
val logFile = FileUtil.getLogFile(requireContext(), item)
|
if (item.logID != null) {
|
||||||
if (logFile.exists()) {
|
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putString("logpath", logFile.absolutePath)
|
bundle.putLong("logID", item.logID!!)
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
R.id.downloadLogFragment,
|
R.id.downloadLogFragment,
|
||||||
bundle
|
bundle
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
|
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
|
||||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
import com.deniscerri.ytdlnis.util.UiUtil
|
||||||
|
|
@ -42,7 +41,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
|
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
|
|
||||||
class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener, OnItemClickListener {
|
class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener, OnItemClickListener {
|
||||||
|
|
@ -93,10 +91,9 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
||||||
|
|
||||||
override fun onActionButtonClick(itemID: Long) {
|
override fun onActionButtonClick(itemID: Long) {
|
||||||
val item = items.find { it.id == itemID } ?: return
|
val item = items.find { it.id == itemID } ?: return
|
||||||
val logFile = FileUtil.getLogFile(requireContext(), item)
|
if (item.logID != null) {
|
||||||
if (logFile.exists()) {
|
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putString("logpath", logFile.absolutePath)
|
bundle.putLong("logID", item.logID!!)
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
R.id.downloadLogFragment,
|
R.id.downloadLogFragment,
|
||||||
bundle
|
bundle
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.ui.more.downloadLogs
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context.CLIPBOARD_SERVICE
|
import android.content.Context.CLIPBOARD_SERVICE
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.FileObserver
|
import android.os.FileObserver
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
|
@ -12,14 +11,21 @@ import android.view.ViewGroup
|
||||||
import android.widget.ScrollView
|
import android.widget.ScrollView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.map
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
|
import com.deniscerri.ytdlnis.database.viewmodel.LogViewModel
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
import com.neo.highlight.core.Highlight
|
import com.neo.highlight.core.Highlight
|
||||||
import com.neo.highlight.util.listener.HighlightTextWatcher
|
import com.neo.highlight.util.listener.HighlightTextWatcher
|
||||||
import com.neo.highlight.util.scheme.ColorScheme
|
import com.neo.highlight.util.scheme.ColorScheme
|
||||||
import java.io.File
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -27,9 +33,9 @@ class DownloadLogFragment : Fragment() {
|
||||||
private lateinit var content: TextView
|
private lateinit var content: TextView
|
||||||
private lateinit var contentScrollView : ScrollView
|
private lateinit var contentScrollView : ScrollView
|
||||||
private lateinit var topAppBar: MaterialToolbar
|
private lateinit var topAppBar: MaterialToolbar
|
||||||
private lateinit var observer: FileObserver
|
|
||||||
private lateinit var copyLog : ExtendedFloatingActionButton
|
private lateinit var copyLog : ExtendedFloatingActionButton
|
||||||
private lateinit var mainActivity: MainActivity
|
private lateinit var mainActivity: MainActivity
|
||||||
|
private lateinit var logViewModel: LogViewModel
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
|
@ -61,41 +67,27 @@ class DownloadLogFragment : Fragment() {
|
||||||
clipboard.setText(content.text)
|
clipboard.setText(content.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
val path = arguments?.getString("logpath")
|
val id = arguments?.getLong("logID")
|
||||||
if (path == null) {
|
if (id == null) {
|
||||||
mainActivity.onBackPressedDispatcher.onBackPressed()
|
mainActivity.onBackPressedDispatcher.onBackPressed()
|
||||||
}else{
|
}else{
|
||||||
arguments?.remove("logpath")
|
arguments?.remove("logID")
|
||||||
}
|
}
|
||||||
|
|
||||||
val file = File(path!!)
|
|
||||||
topAppBar.title = file.name
|
|
||||||
content.text = file.readText()
|
|
||||||
|
|
||||||
if(Build.VERSION.SDK_INT < 29){
|
logViewModel = ViewModelProvider(this)[LogViewModel::class.java]
|
||||||
observer = object : FileObserver(file.absolutePath, MODIFY) {
|
logViewModel.items.map { it.find { log -> log.id == id } }.observe(viewLifecycleOwner) { logItem ->
|
||||||
override fun onEvent(event: Int, p: String?) {
|
mainActivity.runOnUiThread{
|
||||||
mainActivity.runOnUiThread{
|
content.text = logItem?.content
|
||||||
val newText = File(path).readText()
|
content.scrollTo(0, content.height)
|
||||||
content.text = newText
|
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
||||||
content.scrollTo(0, content.height)
|
|
||||||
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
observer.startWatching();
|
}
|
||||||
}else{
|
|
||||||
observer = object : FileObserver(file, MODIFY) {
|
|
||||||
override fun onEvent(event: Int, p: String?) {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
mainActivity.runOnUiThread{
|
val logItem = logViewModel.getItemById(id!!)
|
||||||
val newText = File(path).readText()
|
topAppBar.title = logItem.title
|
||||||
content.text = newText
|
|
||||||
content.scrollTo(0, content.height)
|
|
||||||
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
observer.startWatching();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//init syntax highlighter
|
//init syntax highlighter
|
||||||
|
|
@ -119,11 +111,6 @@ class DownloadLogFragment : Fragment() {
|
||||||
content.addTextChangedListener(highlightWatcher)
|
content.addTextChangedListener(highlightWatcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
observer.stopWatching()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "DownloadLogActivity"
|
private const val TAG = "DownloadLogActivity"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
package com.deniscerri.ytdlnis.ui.more.downloadLogs
|
package com.deniscerri.ytdlnis.ui.more.downloadLogs
|
||||||
|
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.FileObserver
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
@ -11,12 +9,15 @@ import android.view.ViewGroup
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.DownloadLogsAdapter
|
import com.deniscerri.ytdlnis.adapter.DownloadLogsAdapter
|
||||||
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
|
import com.deniscerri.ytdlnis.database.viewmodel.LogViewModel
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
@ -28,8 +29,9 @@ class DownloadLogListFragment : Fragment(), DownloadLogsAdapter.OnItemClickListe
|
||||||
private lateinit var noResults: RelativeLayout
|
private lateinit var noResults: RelativeLayout
|
||||||
private lateinit var fileList: MutableList<File>
|
private lateinit var fileList: MutableList<File>
|
||||||
private lateinit var topAppBar: MaterialToolbar
|
private lateinit var topAppBar: MaterialToolbar
|
||||||
private lateinit var logFolder : File
|
|
||||||
private lateinit var mainActivity: MainActivity
|
private lateinit var mainActivity: MainActivity
|
||||||
|
private lateinit var logViewModel: LogViewModel
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
|
|
@ -56,32 +58,17 @@ class DownloadLogListFragment : Fragment(), DownloadLogsAdapter.OnItemClickListe
|
||||||
noResults = view.findViewById(R.id.no_results)
|
noResults = view.findViewById(R.id.no_results)
|
||||||
noResults.visibility = View.GONE
|
noResults.visibility = View.GONE
|
||||||
|
|
||||||
logFolder = File(requireContext().filesDir.absolutePath + "/logs")
|
logViewModel = ViewModelProvider(this)[LogViewModel::class.java]
|
||||||
updateList(logFolder)
|
logViewModel.items.observe(viewLifecycleOwner) {
|
||||||
|
if (it.isEmpty()) noResults.visibility = View.VISIBLE
|
||||||
if(Build.VERSION.SDK_INT < 29){
|
else noResults.visibility = View.GONE
|
||||||
val observer: FileObserver = object : FileObserver(logFolder.absolutePath) {
|
downloadLogAdapter.submitList(it)
|
||||||
override fun onEvent(event: Int, path: String?) {
|
|
||||||
when(event) {
|
|
||||||
CREATE, DELETE -> updateList(logFolder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
observer.startWatching()
|
|
||||||
}else{
|
|
||||||
val observer: FileObserver = object : FileObserver(logFolder) {
|
|
||||||
override fun onEvent(event: Int, path: String?) {
|
|
||||||
when(event) {
|
|
||||||
CREATE, DELETE -> updateList(logFolder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
observer.startWatching()
|
|
||||||
}
|
}
|
||||||
initMenu(logFolder)
|
|
||||||
|
initMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initMenu(logFolder: File) {
|
private fun initMenu() {
|
||||||
topAppBar.setOnMenuItemClickListener { m: MenuItem ->
|
topAppBar.setOnMenuItemClickListener { m: MenuItem ->
|
||||||
val itemId = m.itemId
|
val itemId = m.itemId
|
||||||
if (itemId == R.id.remove_logs) {
|
if (itemId == R.id.remove_logs) {
|
||||||
|
|
@ -91,11 +78,7 @@ class DownloadLogListFragment : Fragment(), DownloadLogsAdapter.OnItemClickListe
|
||||||
deleteDialog.setMessage(getString(R.string.confirm_delete_logs_desc))
|
deleteDialog.setMessage(getString(R.string.confirm_delete_logs_desc))
|
||||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||||
logFolder.listFiles()!!.forEach {
|
logViewModel.deleteAll()
|
||||||
it.delete()
|
|
||||||
}.run {
|
|
||||||
updateList(logFolder)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
deleteDialog.show()
|
deleteDialog.show()
|
||||||
}catch (e: Exception){
|
}catch (e: Exception){
|
||||||
|
|
@ -106,43 +89,22 @@ class DownloadLogListFragment : Fragment(), DownloadLogsAdapter.OnItemClickListe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateList(logFolder: File){
|
override fun onItemClick(item: LogItem) {
|
||||||
fileList = mutableListOf()
|
|
||||||
try{
|
|
||||||
fileList.addAll(logFolder.listFiles()!!)
|
|
||||||
fileList.sortByDescending { it.lastModified()}
|
|
||||||
}catch (e: Exception){
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
downloadLogAdapter.submitList(fileList.toList())
|
|
||||||
mainActivity.runOnUiThread{
|
|
||||||
if (fileList.isNotEmpty()) {
|
|
||||||
noResults.visibility = View.GONE
|
|
||||||
topAppBar.menu.findItem(R.id.remove_logs).isVisible = true
|
|
||||||
}else{
|
|
||||||
topAppBar.menu.findItem(R.id.remove_logs).isVisible = false
|
|
||||||
noResults.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onItemClick(file: File) {
|
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putString("logpath", file.absolutePath)
|
bundle.putLong("logID", item.id)
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
R.id.downloadLogFragment,
|
R.id.downloadLogFragment,
|
||||||
bundle
|
bundle
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDeleteClick(file: File) {
|
override fun onDeleteClick(item: LogItem) {
|
||||||
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
|
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
|
||||||
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + file.name + "\"!")
|
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + item.title + "\"!")
|
||||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||||
file.delete().run {
|
logViewModel.delete(item)
|
||||||
updateList(logFolder)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
deleteDialog.show()
|
deleteDialog.show()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
|
||||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
|
@ -65,6 +64,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
||||||
private lateinit var cookieViewModel: CookieViewModel
|
private lateinit var cookieViewModel: CookieViewModel
|
||||||
private lateinit var commandTemplateViewModel: CommandTemplateViewModel
|
private lateinit var commandTemplateViewModel: CommandTemplateViewModel
|
||||||
|
|
||||||
|
private var arch: Preference? = null
|
||||||
private var version: Preference? = null
|
private var version: Preference? = null
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
|
@ -200,7 +200,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
||||||
}
|
}
|
||||||
|
|
||||||
version = findPreference("version")
|
version = findPreference("version")
|
||||||
version!!.summary = BuildConfig.VERSION_NAME
|
version!!.summary = "${BuildConfig.VERSION_NAME} [${Build.SUPPORTED_ABIS[0]}] ${BuildConfig.BUILD_TYPE}"
|
||||||
|
|
||||||
version!!.onPreferenceClickListener =
|
version!!.onPreferenceClickListener =
|
||||||
Preference.OnPreferenceClickListener {
|
Preference.OnPreferenceClickListener {
|
||||||
|
|
@ -223,11 +223,13 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
||||||
val prefs = preferences.all
|
val prefs = preferences.all
|
||||||
val arr = JsonArray()
|
val arr = JsonArray()
|
||||||
prefs.forEach {
|
prefs.forEach {
|
||||||
val obj = JsonObject()
|
if (it.key != "app_language"){
|
||||||
obj.addProperty("key", it.key)
|
val obj = JsonObject()
|
||||||
obj.addProperty("value", it.value.toString())
|
obj.addProperty("key", it.key)
|
||||||
obj.addProperty("type", it.value!!::class.simpleName)
|
obj.addProperty("value", it.value.toString())
|
||||||
arr.add(obj)
|
obj.addProperty("type", it.value!!::class.simpleName)
|
||||||
|
arr.add(obj)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,25 +152,6 @@ object FileUtil {
|
||||||
return listOf(context.getString(R.string.unfound_file))
|
return listOf(context.getString(R.string.unfound_file))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLogFile(context: Context, item: DownloadItem) : File {
|
|
||||||
val titleRegex = Regex("[^A-Za-z\\d ]")
|
|
||||||
val title = item.title.ifEmpty { item.url }
|
|
||||||
return File(context.filesDir.absolutePath + """/logs/${item.id} - ${titleRegex.replace(title, "").take(150)}##${item.type}##${item.format.format_id}.log""")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun checkLogFileExists(context: Context, item: DownloadItem) : File? {
|
|
||||||
return try {
|
|
||||||
val dir = File(context.filesDir.absolutePath + "/logs/")
|
|
||||||
dir.listFiles()?.toList()?.first { it.name.startsWith(item.id.toString()) }
|
|
||||||
}catch (e: Exception){
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getLogFileForTerminal(context: Context, command: String) : File {
|
|
||||||
val titleRegex = Regex("[^A-Za-z\\d ]")
|
|
||||||
return File(context.filesDir.absolutePath + """/logs/Terminal - ${titleRegex.replace(command.take(30), "")}##terminal.log""")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getDefaultAudioPath() : String{
|
fun getDefaultAudioPath() : String{
|
||||||
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath + File.separator + "YTDLnis/Audio"
|
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath + File.separator + "YTDLnis/Audio"
|
||||||
|
|
|
||||||
|
|
@ -279,48 +279,51 @@ class InfoUtil(private val context: Context) {
|
||||||
val thumb = "https://i.ytimg.com/vi/$id/hqdefault.jpg"
|
val thumb = "https://i.ytimg.com/vi/$id/hqdefault.jpg"
|
||||||
val url = "https://www.youtube.com/watch?v=$id"
|
val url = "https://www.youtube.com/watch?v=$id"
|
||||||
val formats : ArrayList<Format> = ArrayList()
|
val formats : ArrayList<Format> = ArrayList()
|
||||||
if (obj.has("audioStreams")){
|
|
||||||
val formatsInJSON = obj.getJSONArray("audioStreams")
|
if(sharedPreferences.getString("formats_source", "yt-dlp") == "piped"){
|
||||||
for (f in 0 until formatsInJSON.length()){
|
if (obj.has("audioStreams")){
|
||||||
val format = formatsInJSON.getJSONObject(f)
|
val formatsInJSON = obj.getJSONArray("audioStreams")
|
||||||
if (format.getInt("bitrate") == 0) continue
|
for (f in 0 until formatsInJSON.length()){
|
||||||
val formatObj = Gson().fromJson(format.toString(), Format::class.java)
|
val format = formatsInJSON.getJSONObject(f)
|
||||||
try{
|
if (format.getInt("bitrate") == 0) continue
|
||||||
formatObj.acodec = format.getString("codec")
|
val formatObj = Gson().fromJson(format.toString(), Format::class.java)
|
||||||
formatObj.asr = format.getString("quality")
|
try{
|
||||||
if (! format.getString("audioTrackName").equals("null", ignoreCase = true)){
|
formatObj.acodec = format.getString("codec")
|
||||||
formatObj.format_note = format.getString("audioTrackName") + " Audio, " + formatObj.format_note
|
formatObj.asr = format.getString("quality")
|
||||||
}else{
|
if (! format.getString("audioTrackName").equals("null", ignoreCase = true)){
|
||||||
formatObj.format_note = formatObj.format_note + " Audio"
|
formatObj.format_note = format.getString("audioTrackName") + " Audio, " + formatObj.format_note
|
||||||
|
}else{
|
||||||
|
formatObj.format_note = formatObj.format_note + " Audio"
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
formats.add(formatObj)
|
||||||
}catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
}
|
||||||
formats.add(formatObj)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (obj.has("videoStreams")){
|
if (obj.has("videoStreams")){
|
||||||
val formatsInJSON = obj.getJSONArray("videoStreams")
|
val formatsInJSON = obj.getJSONArray("videoStreams")
|
||||||
for (f in 0 until formatsInJSON.length()){
|
for (f in 0 until formatsInJSON.length()){
|
||||||
val format = formatsInJSON.getJSONObject(f)
|
val format = formatsInJSON.getJSONObject(f)
|
||||||
if (format.getInt("bitrate") == 0) continue
|
if (format.getInt("bitrate") == 0) continue
|
||||||
val formatObj = Gson().fromJson(format.toString(), Format::class.java)
|
val formatObj = Gson().fromJson(format.toString(), Format::class.java)
|
||||||
try{
|
try{
|
||||||
formatObj.vcodec = format.getString("codec")
|
formatObj.vcodec = format.getString("codec")
|
||||||
}catch (e: Exception) {
|
}catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
formats.add(formatObj)
|
||||||
}
|
}
|
||||||
formats.add(formatObj)
|
|
||||||
}
|
}
|
||||||
}
|
formats.sortBy { it.filesize }
|
||||||
formats.sortBy { it.filesize }
|
formats.groupBy { it.format_id }.forEach {
|
||||||
formats.groupBy { it.format_id }.forEach {
|
if (it.value.count() > 1) {
|
||||||
if (it.value.count() > 1) {
|
it.value.filter { f-> !f.format_note.contains("original", true) }.forEachIndexed { index, format -> format.format_id = format.format_id.split("-")[0] + "-${index}" }
|
||||||
it.value.filter { f-> !f.format_note.contains("original", true) }.forEachIndexed { index, format -> format.format_id = format.format_id.split("-")[0] + "-${index}" }
|
val engDefault = it.value.find { f -> f.format_note.contains("original", true) }
|
||||||
val engDefault = it.value.find { f -> f.format_note.contains("original", true) }
|
engDefault?.format_id = (engDefault?.format_id?.split("-")?.get(0) ?: "") + "-${it.value.size-1}"
|
||||||
engDefault?.format_id = (engDefault?.format_id?.split("-")?.get(0) ?: "") + "-${it.value.size-1}"
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import com.deniscerri.ytdlnis.receiver.PauseDownloadNotificationReceiver
|
||||||
import com.deniscerri.ytdlnis.receiver.ResumeActivity
|
import com.deniscerri.ytdlnis.receiver.ResumeActivity
|
||||||
import com.deniscerri.ytdlnis.receiver.ShareFileActivity
|
import com.deniscerri.ytdlnis.receiver.ShareFileActivity
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlin.math.log
|
||||||
|
|
||||||
|
|
||||||
class NotificationUtil(var context: Context) {
|
class NotificationUtil(var context: Context) {
|
||||||
|
|
@ -231,13 +232,15 @@ class NotificationUtil(var context: Context) {
|
||||||
|
|
||||||
fun createDownloadErrored(title: String?,
|
fun createDownloadErrored(title: String?,
|
||||||
error: String?,
|
error: String?,
|
||||||
logFile: File?,
|
logID: Long?,
|
||||||
channel: String
|
channel: String
|
||||||
) {
|
) {
|
||||||
val notificationBuilder = getBuilder(channel)
|
val notificationBuilder = getBuilder(channel)
|
||||||
|
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putString("logpath", logFile?.absolutePath)
|
if (logID != null){
|
||||||
|
bundle.putLong("logID", logID)
|
||||||
|
}
|
||||||
|
|
||||||
val errorPendingIntent = NavDeepLinkBuilder(context)
|
val errorPendingIntent = NavDeepLinkBuilder(context)
|
||||||
.setGraph(R.navigation.nav_graph)
|
.setGraph(R.navigation.nav_graph)
|
||||||
|
|
@ -268,7 +271,7 @@ class NotificationUtil(var context: Context) {
|
||||||
.setPriority(NotificationCompat.PRIORITY_MAX)
|
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
.clearActions()
|
.clearActions()
|
||||||
if (logFile != null){
|
if (logID != null){
|
||||||
notificationBuilder.setContentIntent(errorPendingIntent)
|
notificationBuilder.setContentIntent(errorPendingIntent)
|
||||||
notificationBuilder.addAction(0, context.getString(R.string.logs), errorPendingIntent)
|
notificationBuilder.addAction(0, context.getString(R.string.logs), errorPendingIntent)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.deniscerri.ytdlnis.work
|
package com.deniscerri.ytdlnis.work
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
|
@ -19,7 +18,9 @@ import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
||||||
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||||
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
|
import com.deniscerri.ytdlnis.database.repository.LogRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||||
|
|
@ -48,6 +49,7 @@ class DownloadWorker(
|
||||||
val repository = DownloadRepository(dao)
|
val repository = DownloadRepository(dao)
|
||||||
val historyDao = dbManager.historyDao
|
val historyDao = dbManager.historyDao
|
||||||
val resultDao = dbManager.resultDao
|
val resultDao = dbManager.resultDao
|
||||||
|
val logRepo = LogRepository(dbManager.logDao)
|
||||||
val handler = Handler(Looper.getMainLooper())
|
val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -92,16 +94,6 @@ class DownloadWorker(
|
||||||
tempFileDir.delete()
|
tempFileDir.delete()
|
||||||
tempFileDir.mkdirs()
|
tempFileDir.mkdirs()
|
||||||
|
|
||||||
var useCacheFolder = true
|
|
||||||
val downloadLocationFile = File(downloadLocation)
|
|
||||||
if (downloadLocationFile.canWrite()) {
|
|
||||||
File(downloadLocation).mkdirs()
|
|
||||||
if(Build.VERSION.SDK_INT > 23) request.addOption("-P", "temp:" + tempFileDir.absolutePath)
|
|
||||||
useCacheFolder = false
|
|
||||||
}
|
|
||||||
val pathUsed = if (useCacheFolder) tempFileDir.absolutePath else downloadLocation
|
|
||||||
|
|
||||||
|
|
||||||
val aria2 = sharedPreferences.getBoolean("aria2", false)
|
val aria2 = sharedPreferences.getBoolean("aria2", false)
|
||||||
if (aria2) {
|
if (aria2) {
|
||||||
request.addOption("--downloader", "libaria2c.so")
|
request.addOption("--downloader", "libaria2c.so")
|
||||||
|
|
@ -159,6 +151,10 @@ class DownloadWorker(
|
||||||
request.addOption("--download-sections", "*$it")
|
request.addOption("--download-sections", "*$it")
|
||||||
else
|
else
|
||||||
request.addOption("--download-sections", it)
|
request.addOption("--download-sections", it)
|
||||||
|
|
||||||
|
if (sharedPreferences.getBoolean("force_keyframes", false)){
|
||||||
|
request.addOption("--force-keyframes-at-cuts")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
downloadItem.customFileNameTemplate += " %(section_title)s %(autonumber)s"
|
downloadItem.customFileNameTemplate += " %(section_title)s %(autonumber)s"
|
||||||
request.addOption("--output-na-placeholder", " ")
|
request.addOption("--output-na-placeholder", " ")
|
||||||
|
|
@ -233,9 +229,9 @@ class DownloadWorker(
|
||||||
|
|
||||||
if (downloadItem.audioPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
if (downloadItem.audioPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
||||||
request.addOption("--split-chapters")
|
request.addOption("--split-chapters")
|
||||||
request.addOption("-P", pathUsed)
|
request.addOption("-P", tempFileDir.absolutePath)
|
||||||
}else{
|
}else{
|
||||||
request.addOption("-o", pathUsed + "/${downloadItem.customFileNameTemplate}.%(ext)s")
|
request.addOption("-o", tempFileDir.absolutePath + "/${downloadItem.customFileNameTemplate}.%(ext)s")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -262,7 +258,7 @@ class DownloadWorker(
|
||||||
else if (videoFormatID == context.resources.getString(R.string.worst_quality) || videoFormatID == "worst") videoFormatID = "worst"
|
else if (videoFormatID == context.resources.getString(R.string.worst_quality) || videoFormatID == "worst") videoFormatID = "worst"
|
||||||
else if (defaultFormats.contains(videoFormatID)) videoFormatID = "bestvideo[height<="+videoFormatID.substring(0, videoFormatID.length -1)+"]"
|
else if (defaultFormats.contains(videoFormatID)) videoFormatID = "bestvideo[height<="+videoFormatID.substring(0, videoFormatID.length -1)+"]"
|
||||||
|
|
||||||
formatArgument = if (downloadItem.videoPreferences.audioFormatIDs.isNotEmpty()){
|
formatArgument = if (downloadItem.videoPreferences.audioFormatIDs.isNotEmpty() && ! downloadItem.videoPreferences.removeAudio){
|
||||||
val audioIds = downloadItem.videoPreferences.audioFormatIDs.joinToString("+")
|
val audioIds = downloadItem.videoPreferences.audioFormatIDs.joinToString("+")
|
||||||
"$videoFormatID+$audioIds/best/$videoFormatID"
|
"$videoFormatID+$audioIds/best/$videoFormatID"
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -292,16 +288,15 @@ class DownloadWorker(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downloadItem.videoPreferences.removeAudio &&
|
if (downloadItem.videoPreferences.removeAudio){
|
||||||
(downloadItem.format.acodec.isNotEmpty() && downloadItem.format.acodec != "none")){
|
|
||||||
request.addOption("--ppa", "ffmpeg:-an")
|
request.addOption("--ppa", "ffmpeg:-an")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downloadItem.videoPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
if (downloadItem.videoPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
||||||
request.addOption("--split-chapters")
|
request.addOption("--split-chapters")
|
||||||
request.addOption("-P", pathUsed)
|
request.addOption("-P", tempFileDir.absolutePath)
|
||||||
}else{
|
}else{
|
||||||
request.addOption("-o", pathUsed + "/${downloadItem.customFileNameTemplate}.%(ext)s")
|
request.addOption("-o", tempFileDir.absolutePath + "/${downloadItem.customFileNameTemplate}.%(ext)s")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -312,24 +307,32 @@ class DownloadWorker(
|
||||||
writeText(downloadItem.format.format_note)
|
writeText(downloadItem.format.format_note)
|
||||||
}.absolutePath
|
}.absolutePath
|
||||||
)
|
)
|
||||||
request.addOption("-P", pathUsed)
|
request.addOption("-P", tempFileDir.absolutePath)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
|
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
|
||||||
val logFolder = File(context.filesDir.absolutePath + "/logs")
|
|
||||||
val logFile = FileUtil.getLogFile(context, downloadItem)
|
|
||||||
|
|
||||||
if (logDownloads){
|
val logItem = LogItem(
|
||||||
logFolder.mkdirs()
|
0,
|
||||||
logFile.createNewFile()
|
downloadItem.title,
|
||||||
logFile.writeText("Downloading:\n" +
|
"Downloading:\n" +
|
||||||
"Title: ${downloadItem.title}\n" +
|
"Title: ${downloadItem.title}\n" +
|
||||||
"URL: ${downloadItem.url}\n" +
|
"URL: ${downloadItem.url}\n" +
|
||||||
"Type: ${downloadItem.type}\n" +
|
"Type: ${downloadItem.type}\n" +
|
||||||
"Format: ${downloadItem.format}\n\n" +
|
"Format: ${downloadItem.format}\n\n" +
|
||||||
"Command: ${java.lang.String.join(" ", request.buildCommand())}\n\n")
|
"Command: ${java.lang.String.join(" ", request.buildCommand())}\n\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if (logDownloads){
|
||||||
|
runBlocking {
|
||||||
|
logItem.id = logRepo.insert(logItem)
|
||||||
|
downloadItem.logID = logItem.id
|
||||||
|
dao.update(downloadItem)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
runCatching {
|
runCatching {
|
||||||
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
|
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
|
||||||
|
|
@ -340,48 +343,41 @@ class DownloadWorker(
|
||||||
line, progress.toInt(), 0, title,
|
line, progress.toInt(), 0, title,
|
||||||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
||||||
)
|
)
|
||||||
if (logDownloads && logFile.exists()){
|
if (logDownloads){
|
||||||
logFile.appendText("${line}\n")
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
logRepo.update(line, logItem.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
val wasQuickDownloaded = updateDownloadItem(downloadItem, infoUtil, dao, resultDao)
|
val wasQuickDownloaded = updateDownloadItem(downloadItem, infoUtil, dao, resultDao)
|
||||||
var finalPaths: List<String>
|
|
||||||
if (useCacheFolder){
|
|
||||||
//move file from internal to set download directory
|
|
||||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
|
|
||||||
try {
|
|
||||||
finalPaths = FileUtil.moveFile(tempFileDir.absoluteFile,context, downloadLocation, keepCache){ p ->
|
|
||||||
setProgressAsync(workDataOf("progress" to p, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
|
|
||||||
}
|
|
||||||
if (finalPaths.isNotEmpty()){
|
|
||||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moved file to $downloadLocation", "id" to downloadItem.id, "log" to logDownloads))
|
|
||||||
}else{
|
|
||||||
finalPaths = listOf(context.getString(R.string.unfound_file))
|
|
||||||
}
|
|
||||||
}catch (e: Exception){
|
|
||||||
finalPaths = listOf(context.getString(R.string.unfound_file))
|
|
||||||
e.printStackTrace()
|
|
||||||
handler.postDelayed({
|
|
||||||
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
finalPaths = downloadLocationFile
|
|
||||||
.walkTopDown()
|
|
||||||
.filter { it.isFile && it.absolutePath.contains(downloadItem.title) && it.lastModified() > now - 10000000}
|
|
||||||
.map { it.absolutePath }
|
|
||||||
.toList()
|
|
||||||
|
|
||||||
if (finalPaths.isEmpty()) finalPaths = listOf(context.getString(R.string.unfound_file))
|
var finalPaths : List<String>?
|
||||||
|
//move file from internal to set download directory
|
||||||
|
setProgressAsync(workDataOf("progress" to 100, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
|
||||||
|
try {
|
||||||
|
finalPaths = FileUtil.moveFile(tempFileDir.absoluteFile,context, downloadLocation, keepCache){ p ->
|
||||||
|
setProgressAsync(workDataOf("progress" to p, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
|
||||||
|
}
|
||||||
|
if (finalPaths.isNotEmpty()){
|
||||||
|
setProgressAsync(workDataOf("progress" to 100, "output" to "Moved file to $downloadLocation", "id" to downloadItem.id, "log" to logDownloads))
|
||||||
|
}else{
|
||||||
|
finalPaths = listOf(context.getString(R.string.unfound_file))
|
||||||
|
}
|
||||||
|
}catch (e: Exception){
|
||||||
|
finalPaths = listOf(context.getString(R.string.unfound_file))
|
||||||
|
e.printStackTrace()
|
||||||
|
handler.postDelayed({
|
||||||
|
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
|
||||||
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//put download in history
|
//put download in history
|
||||||
val incognito = sharedPreferences.getBoolean("incognito", false)
|
val incognito = sharedPreferences.getBoolean("incognito", false)
|
||||||
if (!incognito) {
|
if (!incognito) {
|
||||||
val unixtime = System.currentTimeMillis() / 1000
|
val unixtime = System.currentTimeMillis() / 1000
|
||||||
val file = File(finalPaths.first()!!)
|
val file = File(finalPaths?.first()!!)
|
||||||
downloadItem.format.filesize = file.length()
|
downloadItem.format.filesize = file.length()
|
||||||
val historyItem = HistoryItem(0, downloadItem.url, downloadItem.title, downloadItem.author, downloadItem.duration, downloadItem.thumb, downloadItem.type, unixtime, finalPaths.first() , downloadItem.website, downloadItem.format, downloadItem.id)
|
val historyItem = HistoryItem(0, downloadItem.url, downloadItem.title, downloadItem.author, downloadItem.duration, downloadItem.thumb, downloadItem.type, unixtime, finalPaths.first() , downloadItem.website, downloadItem.format, downloadItem.id)
|
||||||
runBlocking {
|
runBlocking {
|
||||||
|
|
@ -421,8 +417,12 @@ class DownloadWorker(
|
||||||
Data.Builder().putString("output", "Download has been cancelled!").build()
|
Data.Builder().putString("output", "Download has been cancelled!").build()
|
||||||
)
|
)
|
||||||
}else{
|
}else{
|
||||||
if (logDownloads && logFile.exists()){
|
if (logDownloads){
|
||||||
logFile.appendText("${it.message}\n")
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
if(it.message != null){
|
||||||
|
logRepo.update(it.message!!, logItem.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tempFileDir.delete()
|
tempFileDir.delete()
|
||||||
|
|
@ -440,7 +440,7 @@ class DownloadWorker(
|
||||||
|
|
||||||
notificationUtil.createDownloadErrored(
|
notificationUtil.createDownloadErrored(
|
||||||
downloadItem.title, it.message,
|
downloadItem.title, it.message,
|
||||||
if (logDownloads) logFile else null,
|
if (logDownloads) logItem.id else null,
|
||||||
NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID
|
NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,22 @@ import androidx.work.WorkerParameters
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
|
import com.deniscerri.ytdlnis.database.DBManager
|
||||||
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
|
import com.deniscerri.ytdlnis.database.repository.LogRepository
|
||||||
import com.deniscerri.ytdlnis.ui.more.TerminalActivity
|
import com.deniscerri.ytdlnis.ui.more.TerminalActivity
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
import com.yausername.youtubedl_android.YoutubeDL
|
import com.yausername.youtubedl_android.YoutubeDL
|
||||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
|
||||||
class TerminalDownloadWorker(
|
class TerminalDownloadWorker(
|
||||||
|
|
@ -32,6 +42,9 @@ class TerminalDownloadWorker(
|
||||||
if (itemId == 0) return Result.failure()
|
if (itemId == 0) return Result.failure()
|
||||||
if (command!!.isEmpty()) return Result.failure()
|
if (command!!.isEmpty()) return Result.failure()
|
||||||
|
|
||||||
|
val dbManager = DBManager.getInstance(context)
|
||||||
|
val logRepo = LogRepository(dbManager.logDao)
|
||||||
|
|
||||||
val notificationUtil = NotificationUtil(context)
|
val notificationUtil = NotificationUtil(context)
|
||||||
val handler = Handler(Looper.getMainLooper())
|
val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
|
@ -67,16 +80,20 @@ class TerminalDownloadWorker(
|
||||||
request.addOption("-P", tempFileDir.absolutePath)
|
request.addOption("-P", tempFileDir.absolutePath)
|
||||||
|
|
||||||
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
|
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
|
||||||
val logFolder = File(context.filesDir.absolutePath + "/logs")
|
|
||||||
val logFile = FileUtil.getLogFileForTerminal(context, command)
|
val logItem = LogItem(
|
||||||
|
0,
|
||||||
|
"Terminal Download at " + Calendar.getInstance().time,
|
||||||
|
"Downloading:\n" +
|
||||||
|
"Terminal Download\n" +
|
||||||
|
"Command: ${command}\n\n"
|
||||||
|
)
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
if (logDownloads){
|
if (logDownloads){
|
||||||
logFolder.mkdirs()
|
runBlocking {
|
||||||
logFile.createNewFile()
|
logItem.id = logRepo.insert(logItem)
|
||||||
logFile.writeText("Downloading:\n" +
|
}
|
||||||
"Terminal Download\n" +
|
|
||||||
"Command: ${command}\n\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
YoutubeDL.getInstance().execute(request, itemId.toString()){ progress, _, line ->
|
YoutubeDL.getInstance().execute(request, itemId.toString()){ progress, _, line ->
|
||||||
|
|
@ -87,8 +104,10 @@ class TerminalDownloadWorker(
|
||||||
line, progress.toInt(), 0, title,
|
line, progress.toInt(), 0, title,
|
||||||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
||||||
)
|
)
|
||||||
if (logDownloads && logFile.exists()){
|
if (logDownloads){
|
||||||
logFile.appendText("${line}\n")
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
logRepo.update(line, logItem.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
|
|
@ -106,8 +125,10 @@ class TerminalDownloadWorker(
|
||||||
|
|
||||||
if (it.out.length > 200){
|
if (it.out.length > 200){
|
||||||
outputFile.appendText("${it.out}\n")
|
outputFile.appendText("${it.out}\n")
|
||||||
if (logDownloads && logFile.exists()){
|
if (logDownloads){
|
||||||
logFile.appendText("${it.out}\n")
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
logRepo.update(it.out, logItem.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
notificationUtil.cancelDownloadNotification(itemId)
|
notificationUtil.cancelDownloadNotification(itemId)
|
||||||
|
|
@ -117,8 +138,12 @@ class TerminalDownloadWorker(
|
||||||
return Result.failure()
|
return Result.failure()
|
||||||
}
|
}
|
||||||
outputFile.appendText("${it.message}\n")
|
outputFile.appendText("${it.message}\n")
|
||||||
if (logDownloads && logFile.exists()){
|
if (logDownloads){
|
||||||
logFile.appendText("${it.message}\n")
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
if (it.message != null){
|
||||||
|
logRepo.update(it.message!!, logItem.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tempFileDir.delete()
|
tempFileDir.delete()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -282,4 +282,6 @@
|
||||||
<string name="retries">Retries</string>
|
<string name="retries">Retries</string>
|
||||||
<string name="fragment_retries">Fragment Retries</string>
|
<string name="fragment_retries">Fragment Retries</string>
|
||||||
<string name="format_order">Format Order</string>
|
<string name="format_order">Format Order</string>
|
||||||
|
<string name="force_keyframes">Force Keyframes At Cuts</string>
|
||||||
|
<string name="force_keyframes_summary">Accurate Video Cuts. Slower</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/locale">
|
<PreferenceCategory android:title="@string/appearance">
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:entries="@array/language_values"
|
android:entries="@array/language_values"
|
||||||
android:entryValues="@array/language_values"
|
android:entryValues="@array/language_values"
|
||||||
|
|
@ -11,18 +11,7 @@
|
||||||
app:summary="en"
|
app:summary="en"
|
||||||
app:title="@string/language" />
|
app:title="@string/language" />
|
||||||
|
|
||||||
<ListPreference
|
|
||||||
android:defaultValue=""
|
|
||||||
android:entries="@array/countries"
|
|
||||||
android:entryValues="@array/countries_values"
|
|
||||||
app:icon="@drawable/ic_language"
|
|
||||||
app:useSimpleSummaryProvider="true"
|
|
||||||
app:dependency="home_recommendations"
|
|
||||||
app:key="locale"
|
|
||||||
app:title="@string/preferred_locale" />
|
|
||||||
</PreferenceCategory>
|
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/appearance">
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:entries="@array/themes"
|
android:entries="@array/themes"
|
||||||
android:entryValues="@array/themes_values"
|
android:entryValues="@array/themes_values"
|
||||||
|
|
@ -60,6 +49,17 @@
|
||||||
app:summary="@string/video_recommendations_summary"
|
app:summary="@string/video_recommendations_summary"
|
||||||
app:title="@string/video_recommendations" />
|
app:title="@string/video_recommendations" />
|
||||||
|
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue=""
|
||||||
|
android:entries="@array/countries"
|
||||||
|
android:entryValues="@array/countries_values"
|
||||||
|
app:icon="@drawable/ic_language"
|
||||||
|
app:useSimpleSummaryProvider="true"
|
||||||
|
app:dependency="home_recommendations"
|
||||||
|
app:key="locale"
|
||||||
|
app:title="@string/preferred_locale" />
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="Home"
|
android:defaultValue="Home"
|
||||||
android:entries="@array/start_destination"
|
android:entries="@array/start_destination"
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,14 @@
|
||||||
app:summary="@string/crop_thumb_summary"
|
app:summary="@string/crop_thumb_summary"
|
||||||
app:title="@string/crop_thumb" />
|
app:title="@string/crop_thumb" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:widgetLayout="@layout/preferece_material_switch"
|
||||||
|
app:defaultValue="false"
|
||||||
|
app:icon="@drawable/ic_cut"
|
||||||
|
app:key="force_keyframes"
|
||||||
|
app:summary="@string/force_keyframes_summary"
|
||||||
|
app:title="@string/force_keyframes" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:widgetLayout="@layout/preferece_material_switch"
|
android:widgetLayout="@layout/preferece_material_switch"
|
||||||
app:defaultValue="true"
|
app:defaultValue="true"
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
app:title="@string/update_formats" />
|
app:title="@string/update_formats" />
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="yt-dlp"
|
android:defaultValue="piped"
|
||||||
android:entries="@array/formats_source"
|
android:entries="@array/formats_source"
|
||||||
android:entryValues="@array/formats_source_values"
|
android:entryValues="@array/formats_source_values"
|
||||||
android:icon="@drawable/baseline_manage_search_24"
|
android:icon="@drawable/baseline_manage_search_24"
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
<EditTextPreference
|
<EditTextPreference
|
||||||
app:key="piped_instance"
|
app:key="piped_instance"
|
||||||
app:defaultValue="https://pipedapi.kavin.rocks"
|
app:defaultValue="https://pipedapi.syncpundit.io"
|
||||||
android:summary="@string/piped_instance_summary"
|
android:summary="@string/piped_instance_summary"
|
||||||
app:title="@string/piped_instance" />
|
app:title="@string/piped_instance" />
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue