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 versionMinor = 6
|
||||
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 = ""
|
||||
|
||||
if (versionBuild > 0){
|
||||
versionExt = ".${versionBuild}-beta"
|
||||
versionExt = ".${versionBuild}"
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
@ -72,7 +72,8 @@ android {
|
|||
|
||||
beta {
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
debuggable false
|
||||
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 += " • "
|
||||
info += item.duration
|
||||
}
|
||||
author.text = info
|
||||
|
||||
val type = card.findViewById<MaterialButton>(R.id.download_type)
|
||||
when(item.type){
|
||||
|
|
@ -93,7 +94,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
}
|
||||
|
||||
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 =
|
||||
if (item.format.encoding != "") {
|
||||
|
|
@ -104,11 +105,11 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
item.format.acodec.uppercase()
|
||||
}
|
||||
if (codecText != "" && codecText != "none"){
|
||||
formatDetailsText.append("\t|\t$codecText")
|
||||
formatDetailsText.append(" \t •\t $codecText")
|
||||
}
|
||||
|
||||
val fileSize = FileUtil.convertFileSize(item.format.filesize)
|
||||
if (fileSize != "?") formatDetailsText.append("\t|\t$fileSize")
|
||||
if (fileSize != "?") formatDetailsText.append(" \t •\t $fileSize")
|
||||
|
||||
formatDetailsChip.text = formatDetailsText
|
||||
|
||||
|
|
|
|||
|
|
@ -12,9 +12,10 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||
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 activity: Activity
|
||||
|
||||
|
|
@ -42,7 +43,7 @@ class DownloadLogsAdapter(onItemClickListener: OnItemClickListener, activity: Ac
|
|||
val card = holder.item
|
||||
|
||||
val title = card.findViewById<TextView>(R.id.title)
|
||||
title.text = item?.name
|
||||
title.text = item?.title
|
||||
|
||||
val delete = card.findViewById<Button>(R.id.delete)
|
||||
|
||||
|
|
@ -56,18 +57,18 @@ class DownloadLogsAdapter(onItemClickListener: OnItemClickListener, activity: Ac
|
|||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
fun onItemClick(file: File)
|
||||
fun onDeleteClick(file: File)
|
||||
fun onItemClick(item: LogItem)
|
||||
fun onDeleteClick(item: LogItem)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<File> = object : DiffUtil.ItemCallback<File>() {
|
||||
override fun areItemsTheSame(oldItem: File, newItem: File): Boolean {
|
||||
return oldItem == newItem
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<LogItem> = object : DiffUtil.ItemCallback<LogItem>() {
|
||||
override fun areItemsTheSame(oldItem: LogItem, newItem: LogItem): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: File, newItem: File): Boolean {
|
||||
return oldItem.absolutePath == newItem.absolutePath
|
||||
override fun areContentsTheSame(oldItem: LogItem, newItem: LogItem): Boolean {
|
||||
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)
|
||||
else -> {
|
||||
actionButton.setIconResource(R.drawable.ic_baseline_file_open_24)
|
||||
val logFile = FileUtil.checkLogFileExists(activity, item)
|
||||
if (logFile == null){
|
||||
if (item.logID == null){
|
||||
actionButton.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,15 +7,16 @@ import com.deniscerri.ytdlnis.database.models.*
|
|||
|
||||
@TypeConverters(Converters::class)
|
||||
@Database(
|
||||
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class, SearchHistoryItem::class, TemplateShortcut::class, CookieItem::class],
|
||||
version = 7,
|
||||
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class, SearchHistoryItem::class, TemplateShortcut::class, CookieItem::class, LogItem::class],
|
||||
version = 8,
|
||||
autoMigrations = [
|
||||
AutoMigration (from = 1, to = 2),
|
||||
AutoMigration (from = 2, to = 3),
|
||||
AutoMigration (from = 3, to = 4),
|
||||
AutoMigration (from = 4, to = 5),
|
||||
AutoMigration (from = 5, to = 6),
|
||||
AutoMigration (from = 6, to = 7)
|
||||
AutoMigration (from = 6, to = 7),
|
||||
AutoMigration (from = 7, to = 8)
|
||||
]
|
||||
)
|
||||
abstract class DBManager : RoomDatabase(){
|
||||
|
|
@ -25,6 +26,7 @@ abstract class DBManager : RoomDatabase(){
|
|||
abstract val commandTemplateDao : CommandTemplateDao
|
||||
abstract val searchHistoryDao: SearchHistoryDao
|
||||
abstract val cookieDao: CookieDao
|
||||
abstract val logDao: LogDao
|
||||
|
||||
companion object {
|
||||
//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")
|
||||
var status: String,
|
||||
@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")!!,
|
||||
"",
|
||||
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,
|
||||
"",
|
||||
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.repository.DownloadRepository
|
||||
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.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
|
|
@ -98,10 +96,9 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
}
|
||||
|
||||
override fun onOutputClick(item: DownloadItem) {
|
||||
val logFile = FileUtil.getLogFile(requireContext(), item)
|
||||
if (logFile.exists()) {
|
||||
if (item.logID != null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("logpath", logFile.absolutePath)
|
||||
bundle.putLong("logID", item.logID!!)
|
||||
findNavController().navigate(
|
||||
R.id.downloadLogFragment,
|
||||
bundle
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import com.deniscerri.ytdlnis.R
|
|||
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
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 it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.File
|
||||
|
||||
|
||||
class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener, OnItemClickListener {
|
||||
|
|
@ -93,10 +91,9 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
|
||||
override fun onActionButtonClick(itemID: Long) {
|
||||
val item = items.find { it.id == itemID } ?: return
|
||||
val logFile = FileUtil.getLogFile(requireContext(), item)
|
||||
if (logFile.exists()) {
|
||||
if (item.logID != null) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("logpath", logFile.absolutePath)
|
||||
bundle.putLong("logID", item.logID!!)
|
||||
findNavController().navigate(
|
||||
R.id.downloadLogFragment,
|
||||
bundle
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.ui.more.downloadLogs
|
|||
import android.content.ClipboardManager
|
||||
import android.content.Context.CLIPBOARD_SERVICE
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.FileObserver
|
||||
import android.view.LayoutInflater
|
||||
|
|
@ -12,14 +11,21 @@ import android.view.ViewGroup
|
|||
import android.widget.ScrollView
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.map
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
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.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.neo.highlight.core.Highlight
|
||||
import com.neo.highlight.util.listener.HighlightTextWatcher
|
||||
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
|
||||
|
||||
|
||||
|
|
@ -27,9 +33,9 @@ class DownloadLogFragment : Fragment() {
|
|||
private lateinit var content: TextView
|
||||
private lateinit var contentScrollView : ScrollView
|
||||
private lateinit var topAppBar: MaterialToolbar
|
||||
private lateinit var observer: FileObserver
|
||||
private lateinit var copyLog : ExtendedFloatingActionButton
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var logViewModel: LogViewModel
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
|
@ -61,41 +67,27 @@ class DownloadLogFragment : Fragment() {
|
|||
clipboard.setText(content.text)
|
||||
}
|
||||
|
||||
val path = arguments?.getString("logpath")
|
||||
if (path == null) {
|
||||
val id = arguments?.getLong("logID")
|
||||
if (id == null) {
|
||||
mainActivity.onBackPressedDispatcher.onBackPressed()
|
||||
}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){
|
||||
observer = object : FileObserver(file.absolutePath, MODIFY) {
|
||||
override fun onEvent(event: Int, p: String?) {
|
||||
mainActivity.runOnUiThread{
|
||||
val newText = File(path).readText()
|
||||
content.text = newText
|
||||
content.scrollTo(0, content.height)
|
||||
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
||||
}
|
||||
}
|
||||
logViewModel = ViewModelProvider(this)[LogViewModel::class.java]
|
||||
logViewModel.items.map { it.find { log -> log.id == id } }.observe(viewLifecycleOwner) { logItem ->
|
||||
mainActivity.runOnUiThread{
|
||||
content.text = logItem?.content
|
||||
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?) {
|
||||
mainActivity.runOnUiThread{
|
||||
val newText = File(path).readText()
|
||||
content.text = newText
|
||||
content.scrollTo(0, content.height)
|
||||
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
||||
}
|
||||
}
|
||||
}
|
||||
observer.startWatching();
|
||||
}
|
||||
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val logItem = logViewModel.getItemById(id!!)
|
||||
topAppBar.title = logItem.title
|
||||
}
|
||||
|
||||
//init syntax highlighter
|
||||
|
|
@ -119,11 +111,6 @@ class DownloadLogFragment : Fragment() {
|
|||
content.addTextChangedListener(highlightWatcher)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
observer.stopWatching()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DownloadLogActivity"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package com.deniscerri.ytdlnis.ui.more.downloadLogs
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.FileObserver
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
|
|
@ -11,12 +9,15 @@ import android.view.ViewGroup
|
|||
import android.widget.RelativeLayout
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
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.dialog.MaterialAlertDialogBuilder
|
||||
import java.io.File
|
||||
|
|
@ -28,8 +29,9 @@ class DownloadLogListFragment : Fragment(), DownloadLogsAdapter.OnItemClickListe
|
|||
private lateinit var noResults: RelativeLayout
|
||||
private lateinit var fileList: MutableList<File>
|
||||
private lateinit var topAppBar: MaterialToolbar
|
||||
private lateinit var logFolder : File
|
||||
private lateinit var mainActivity: MainActivity
|
||||
private lateinit var logViewModel: LogViewModel
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
|
@ -56,32 +58,17 @@ class DownloadLogListFragment : Fragment(), DownloadLogsAdapter.OnItemClickListe
|
|||
noResults = view.findViewById(R.id.no_results)
|
||||
noResults.visibility = View.GONE
|
||||
|
||||
logFolder = File(requireContext().filesDir.absolutePath + "/logs")
|
||||
updateList(logFolder)
|
||||
|
||||
if(Build.VERSION.SDK_INT < 29){
|
||||
val observer: FileObserver = object : FileObserver(logFolder.absolutePath) {
|
||||
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()
|
||||
logViewModel = ViewModelProvider(this)[LogViewModel::class.java]
|
||||
logViewModel.items.observe(viewLifecycleOwner) {
|
||||
if (it.isEmpty()) noResults.visibility = View.VISIBLE
|
||||
else noResults.visibility = View.GONE
|
||||
downloadLogAdapter.submitList(it)
|
||||
}
|
||||
initMenu(logFolder)
|
||||
|
||||
initMenu()
|
||||
}
|
||||
|
||||
private fun initMenu(logFolder: File) {
|
||||
private fun initMenu() {
|
||||
topAppBar.setOnMenuItemClickListener { m: MenuItem ->
|
||||
val itemId = m.itemId
|
||||
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.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
logFolder.listFiles()!!.forEach {
|
||||
it.delete()
|
||||
}.run {
|
||||
updateList(logFolder)
|
||||
}
|
||||
logViewModel.deleteAll()
|
||||
}
|
||||
deleteDialog.show()
|
||||
}catch (e: Exception){
|
||||
|
|
@ -106,43 +89,22 @@ class DownloadLogListFragment : Fragment(), DownloadLogsAdapter.OnItemClickListe
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateList(logFolder: File){
|
||||
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) {
|
||||
override fun onItemClick(item: LogItem) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("logpath", file.absolutePath)
|
||||
bundle.putLong("logID", item.id)
|
||||
findNavController().navigate(
|
||||
R.id.downloadLogFragment,
|
||||
bundle
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDeleteClick(file: File) {
|
||||
override fun onDeleteClick(item: LogItem) {
|
||||
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.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
file.delete().run {
|
||||
updateList(logFolder)
|
||||
}
|
||||
logViewModel.delete(item)
|
||||
|
||||
}
|
||||
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.HistoryViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
|
@ -65,6 +64,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
private lateinit var cookieViewModel: CookieViewModel
|
||||
private lateinit var commandTemplateViewModel: CommandTemplateViewModel
|
||||
|
||||
private var arch: Preference? = null
|
||||
private var version: Preference? = null
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
|
|
@ -200,7 +200,7 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
|
||||
version = findPreference("version")
|
||||
version!!.summary = BuildConfig.VERSION_NAME
|
||||
version!!.summary = "${BuildConfig.VERSION_NAME} [${Build.SUPPORTED_ABIS[0]}] ${BuildConfig.BUILD_TYPE}"
|
||||
|
||||
version!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
|
|
@ -223,11 +223,13 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
|||
val prefs = preferences.all
|
||||
val arr = JsonArray()
|
||||
prefs.forEach {
|
||||
val obj = JsonObject()
|
||||
obj.addProperty("key", it.key)
|
||||
obj.addProperty("value", it.value.toString())
|
||||
obj.addProperty("type", it.value!!::class.simpleName)
|
||||
arr.add(obj)
|
||||
if (it.key != "app_language"){
|
||||
val obj = JsonObject()
|
||||
obj.addProperty("key", it.key)
|
||||
obj.addProperty("value", it.value.toString())
|
||||
obj.addProperty("type", it.value!!::class.simpleName)
|
||||
arr.add(obj)
|
||||
}
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,25 +152,6 @@ object FileUtil {
|
|||
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{
|
||||
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 url = "https://www.youtube.com/watch?v=$id"
|
||||
val formats : ArrayList<Format> = ArrayList()
|
||||
if (obj.has("audioStreams")){
|
||||
val formatsInJSON = obj.getJSONArray("audioStreams")
|
||||
for (f in 0 until formatsInJSON.length()){
|
||||
val format = formatsInJSON.getJSONObject(f)
|
||||
if (format.getInt("bitrate") == 0) continue
|
||||
val formatObj = Gson().fromJson(format.toString(), Format::class.java)
|
||||
try{
|
||||
formatObj.acodec = format.getString("codec")
|
||||
formatObj.asr = format.getString("quality")
|
||||
if (! format.getString("audioTrackName").equals("null", ignoreCase = true)){
|
||||
formatObj.format_note = format.getString("audioTrackName") + " Audio, " + formatObj.format_note
|
||||
}else{
|
||||
formatObj.format_note = formatObj.format_note + " Audio"
|
||||
|
||||
if(sharedPreferences.getString("formats_source", "yt-dlp") == "piped"){
|
||||
if (obj.has("audioStreams")){
|
||||
val formatsInJSON = obj.getJSONArray("audioStreams")
|
||||
for (f in 0 until formatsInJSON.length()){
|
||||
val format = formatsInJSON.getJSONObject(f)
|
||||
if (format.getInt("bitrate") == 0) continue
|
||||
val formatObj = Gson().fromJson(format.toString(), Format::class.java)
|
||||
try{
|
||||
formatObj.acodec = format.getString("codec")
|
||||
formatObj.asr = format.getString("quality")
|
||||
if (! format.getString("audioTrackName").equals("null", ignoreCase = true)){
|
||||
formatObj.format_note = format.getString("audioTrackName") + " Audio, " + formatObj.format_note
|
||||
}else{
|
||||
formatObj.format_note = formatObj.format_note + " Audio"
|
||||
}
|
||||
|
||||
}catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
formats.add(formatObj)
|
||||
}
|
||||
formats.add(formatObj)
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.has("videoStreams")){
|
||||
val formatsInJSON = obj.getJSONArray("videoStreams")
|
||||
for (f in 0 until formatsInJSON.length()){
|
||||
val format = formatsInJSON.getJSONObject(f)
|
||||
if (format.getInt("bitrate") == 0) continue
|
||||
val formatObj = Gson().fromJson(format.toString(), Format::class.java)
|
||||
try{
|
||||
formatObj.vcodec = format.getString("codec")
|
||||
}catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
if (obj.has("videoStreams")){
|
||||
val formatsInJSON = obj.getJSONArray("videoStreams")
|
||||
for (f in 0 until formatsInJSON.length()){
|
||||
val format = formatsInJSON.getJSONObject(f)
|
||||
if (format.getInt("bitrate") == 0) continue
|
||||
val formatObj = Gson().fromJson(format.toString(), Format::class.java)
|
||||
try{
|
||||
formatObj.vcodec = format.getString("codec")
|
||||
}catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
formats.add(formatObj)
|
||||
}
|
||||
formats.add(formatObj)
|
||||
}
|
||||
}
|
||||
formats.sortBy { it.filesize }
|
||||
formats.groupBy { it.format_id }.forEach {
|
||||
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}" }
|
||||
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}"
|
||||
formats.sortBy { it.filesize }
|
||||
formats.groupBy { it.format_id }.forEach {
|
||||
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}" }
|
||||
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}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import com.deniscerri.ytdlnis.receiver.PauseDownloadNotificationReceiver
|
|||
import com.deniscerri.ytdlnis.receiver.ResumeActivity
|
||||
import com.deniscerri.ytdlnis.receiver.ShareFileActivity
|
||||
import java.io.File
|
||||
import kotlin.math.log
|
||||
|
||||
|
||||
class NotificationUtil(var context: Context) {
|
||||
|
|
@ -231,13 +232,15 @@ class NotificationUtil(var context: Context) {
|
|||
|
||||
fun createDownloadErrored(title: String?,
|
||||
error: String?,
|
||||
logFile: File?,
|
||||
logID: Long?,
|
||||
channel: String
|
||||
) {
|
||||
val notificationBuilder = getBuilder(channel)
|
||||
|
||||
val bundle = Bundle()
|
||||
bundle.putString("logpath", logFile?.absolutePath)
|
||||
if (logID != null){
|
||||
bundle.putLong("logID", logID)
|
||||
}
|
||||
|
||||
val errorPendingIntent = NavDeepLinkBuilder(context)
|
||||
.setGraph(R.navigation.nav_graph)
|
||||
|
|
@ -268,7 +271,7 @@ class NotificationUtil(var context: Context) {
|
|||
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.clearActions()
|
||||
if (logFile != null){
|
||||
if (logID != null){
|
||||
notificationBuilder.setContentIntent(errorPendingIntent)
|
||||
notificationBuilder.addAction(0, context.getString(R.string.logs), errorPendingIntent)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.work
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
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.models.DownloadItem
|
||||
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.LogRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
|
|
@ -48,6 +49,7 @@ class DownloadWorker(
|
|||
val repository = DownloadRepository(dao)
|
||||
val historyDao = dbManager.historyDao
|
||||
val resultDao = dbManager.resultDao
|
||||
val logRepo = LogRepository(dbManager.logDao)
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
|
||||
|
|
@ -92,16 +94,6 @@ class DownloadWorker(
|
|||
tempFileDir.delete()
|
||||
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)
|
||||
if (aria2) {
|
||||
request.addOption("--downloader", "libaria2c.so")
|
||||
|
|
@ -159,6 +151,10 @@ class DownloadWorker(
|
|||
request.addOption("--download-sections", "*$it")
|
||||
else
|
||||
request.addOption("--download-sections", it)
|
||||
|
||||
if (sharedPreferences.getBoolean("force_keyframes", false)){
|
||||
request.addOption("--force-keyframes-at-cuts")
|
||||
}
|
||||
}
|
||||
downloadItem.customFileNameTemplate += " %(section_title)s %(autonumber)s"
|
||||
request.addOption("--output-na-placeholder", " ")
|
||||
|
|
@ -233,9 +229,9 @@ class DownloadWorker(
|
|||
|
||||
if (downloadItem.audioPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
||||
request.addOption("--split-chapters")
|
||||
request.addOption("-P", pathUsed)
|
||||
request.addOption("-P", tempFileDir.absolutePath)
|
||||
}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 (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("+")
|
||||
"$videoFormatID+$audioIds/best/$videoFormatID"
|
||||
}else{
|
||||
|
|
@ -292,16 +288,15 @@ class DownloadWorker(
|
|||
}
|
||||
}
|
||||
|
||||
if (downloadItem.videoPreferences.removeAudio &&
|
||||
(downloadItem.format.acodec.isNotEmpty() && downloadItem.format.acodec != "none")){
|
||||
if (downloadItem.videoPreferences.removeAudio){
|
||||
request.addOption("--ppa", "ffmpeg:-an")
|
||||
}
|
||||
|
||||
if (downloadItem.videoPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
||||
request.addOption("--split-chapters")
|
||||
request.addOption("-P", pathUsed)
|
||||
request.addOption("-P", tempFileDir.absolutePath)
|
||||
}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)
|
||||
}.absolutePath
|
||||
)
|
||||
request.addOption("-P", pathUsed)
|
||||
request.addOption("-P", tempFileDir.absolutePath)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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){
|
||||
logFolder.mkdirs()
|
||||
logFile.createNewFile()
|
||||
logFile.writeText("Downloading:\n" +
|
||||
val logItem = LogItem(
|
||||
0,
|
||||
downloadItem.title,
|
||||
"Downloading:\n" +
|
||||
"Title: ${downloadItem.title}\n" +
|
||||
"URL: ${downloadItem.url}\n" +
|
||||
"Type: ${downloadItem.type}\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 {
|
||||
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
|
||||
|
|
@ -340,48 +343,41 @@ class DownloadWorker(
|
|||
line, progress.toInt(), 0, title,
|
||||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
||||
)
|
||||
if (logDownloads && logFile.exists()){
|
||||
logFile.appendText("${line}\n")
|
||||
if (logDownloads){
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
logRepo.update(line, logItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onSuccess {
|
||||
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
|
||||
val incognito = sharedPreferences.getBoolean("incognito", false)
|
||||
if (!incognito) {
|
||||
val unixtime = System.currentTimeMillis() / 1000
|
||||
val file = File(finalPaths.first()!!)
|
||||
val file = File(finalPaths?.first()!!)
|
||||
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)
|
||||
runBlocking {
|
||||
|
|
@ -421,8 +417,12 @@ class DownloadWorker(
|
|||
Data.Builder().putString("output", "Download has been cancelled!").build()
|
||||
)
|
||||
}else{
|
||||
if (logDownloads && logFile.exists()){
|
||||
logFile.appendText("${it.message}\n")
|
||||
if (logDownloads){
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
if(it.message != null){
|
||||
logRepo.update(it.message!!, logItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tempFileDir.delete()
|
||||
|
|
@ -440,7 +440,7 @@ class DownloadWorker(
|
|||
|
||||
notificationUtil.createDownloadErrored(
|
||||
downloadItem.title, it.message,
|
||||
if (logDownloads) logFile else null,
|
||||
if (logDownloads) logItem.id else null,
|
||||
NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,12 +14,22 @@ import androidx.work.WorkerParameters
|
|||
import androidx.work.workDataOf
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
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.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
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.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.util.Calendar
|
||||
|
||||
|
||||
class TerminalDownloadWorker(
|
||||
|
|
@ -32,6 +42,9 @@ class TerminalDownloadWorker(
|
|||
if (itemId == 0) return Result.failure()
|
||||
if (command!!.isEmpty()) return Result.failure()
|
||||
|
||||
val dbManager = DBManager.getInstance(context)
|
||||
val logRepo = LogRepository(dbManager.logDao)
|
||||
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
|
|
@ -67,16 +80,20 @@ class TerminalDownloadWorker(
|
|||
request.addOption("-P", tempFileDir.absolutePath)
|
||||
|
||||
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 {
|
||||
if (logDownloads){
|
||||
logFolder.mkdirs()
|
||||
logFile.createNewFile()
|
||||
logFile.writeText("Downloading:\n" +
|
||||
"Terminal Download\n" +
|
||||
"Command: ${command}\n\n")
|
||||
runBlocking {
|
||||
logItem.id = logRepo.insert(logItem)
|
||||
}
|
||||
}
|
||||
|
||||
YoutubeDL.getInstance().execute(request, itemId.toString()){ progress, _, line ->
|
||||
|
|
@ -87,8 +104,10 @@ class TerminalDownloadWorker(
|
|||
line, progress.toInt(), 0, title,
|
||||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
||||
)
|
||||
if (logDownloads && logFile.exists()){
|
||||
logFile.appendText("${line}\n")
|
||||
if (logDownloads){
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
logRepo.update(line, logItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onSuccess {
|
||||
|
|
@ -106,8 +125,10 @@ class TerminalDownloadWorker(
|
|||
|
||||
if (it.out.length > 200){
|
||||
outputFile.appendText("${it.out}\n")
|
||||
if (logDownloads && logFile.exists()){
|
||||
logFile.appendText("${it.out}\n")
|
||||
if (logDownloads){
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
logRepo.update(it.out, logItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
notificationUtil.cancelDownloadNotification(itemId)
|
||||
|
|
@ -117,8 +138,12 @@ class TerminalDownloadWorker(
|
|||
return Result.failure()
|
||||
}
|
||||
outputFile.appendText("${it.message}\n")
|
||||
if (logDownloads && logFile.exists()){
|
||||
logFile.appendText("${it.message}\n")
|
||||
if (logDownloads){
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
if (it.message != null){
|
||||
logRepo.update(it.message!!, logItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
tempFileDir.delete()
|
||||
|
||||
|
|
|
|||
|
|
@ -282,4 +282,6 @@
|
|||
<string name="retries">Retries</string>
|
||||
<string name="fragment_retries">Fragment Retries</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>
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory android:title="@string/locale">
|
||||
<PreferenceCategory android:title="@string/appearance">
|
||||
<ListPreference
|
||||
android:entries="@array/language_values"
|
||||
android:entryValues="@array/language_values"
|
||||
|
|
@ -11,18 +11,7 @@
|
|||
app:summary="en"
|
||||
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
|
||||
android:entries="@array/themes"
|
||||
android:entryValues="@array/themes_values"
|
||||
|
|
@ -60,6 +49,17 @@
|
|||
app:summary="@string/video_recommendations_summary"
|
||||
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
|
||||
android:defaultValue="Home"
|
||||
android:entries="@array/start_destination"
|
||||
|
|
|
|||
|
|
@ -60,6 +60,14 @@
|
|||
app:summary="@string/crop_thumb_summary"
|
||||
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
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
app:title="@string/update_formats" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="yt-dlp"
|
||||
android:defaultValue="piped"
|
||||
android:entries="@array/formats_source"
|
||||
android:entryValues="@array/formats_source_values"
|
||||
android:icon="@drawable/baseline_manage_search_24"
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
<EditTextPreference
|
||||
app:key="piped_instance"
|
||||
app:defaultValue="https://pipedapi.kavin.rocks"
|
||||
app:defaultValue="https://pipedapi.syncpundit.io"
|
||||
android:summary="@string/piped_instance_summary"
|
||||
app:title="@string/piped_instance" />
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue