This commit is contained in:
zaednasr 2024-03-31 22:26:04 +02:00
parent 89e6700db0
commit d7819aca98
No known key found for this signature in database
GPG key ID: 92B1DE23AD3D0E9E
180 changed files with 3001 additions and 1801 deletions

View file

@ -12,14 +12,14 @@ def versionMajor = 1
def versionMinor = 7
def versionPatch = 4
def versionBuild = 0 // bump for dogfood builds, public betas, etc.
def versionExt = ".${versionBuild}"
def versionExt = ""
if (versionBuild > 0){
versionExt = ".${versionBuild}-beta"
}
android {
namespace 'com.deniscerri.ytdlnis'
namespace 'com.deniscerri.ytdl'
compileSdk 34
try {

View file

@ -22,10 +22,10 @@
-if @kotlinx.serialization.Serializable class **
-keep class androidx.lifecycle.LiveData { *; }
-keep class com.google.gson.** { *; }
-keep class com.deniscerri.ytdlnis.database.models.AudioPreferences
-keep class com.deniscerri.ytdlnis.database.models.VideoPreferences
-keep class com.deniscerri.ytdlnis.database.models.GithubRelease
-keep class com.deniscerri.ytdlnis.database.models.GithubReleaseAsset
-keep class com.deniscerri.ytdl.database.models.AudioPreferences
-keep class com.deniscerri.ytdl.database.models.VideoPreferences
-keep class com.deniscerri.ytdl.database.models.GithubRelease
-keep class com.deniscerri.ytdl.database.models.GithubReleaseAsset
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}

View file

@ -0,0 +1,718 @@
{
"formatVersion": 1,
"database": {
"version": 16,
"identityHash": "6d3700c5756542e79e6368575533f6ed",
"entities": [
{
"tableName": "results",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `website` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `formats` TEXT NOT NULL, `urls` TEXT NOT NULL DEFAULT '', `chapters` TEXT, `playlistURL` TEXT DEFAULT '', `playlistIndex` INTEGER, `creationTime` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "author",
"columnName": "author",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "thumb",
"columnName": "thumb",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "website",
"columnName": "website",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "playlistTitle",
"columnName": "playlistTitle",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "formats",
"columnName": "formats",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "urls",
"columnName": "urls",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"fieldPath": "chapters",
"columnName": "chapters",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "playlistURL",
"columnName": "playlistURL",
"affinity": "TEXT",
"notNull": false,
"defaultValue": "''"
},
{
"fieldPath": "playlistIndex",
"columnName": "playlistIndex",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "creationTime",
"columnName": "creationTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "history",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadId` INTEGER NOT NULL DEFAULT 0, `command` TEXT NOT NULL DEFAULT '')",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "author",
"columnName": "author",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "thumb",
"columnName": "thumb",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "downloadPath",
"columnName": "downloadPath",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "website",
"columnName": "website",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "format",
"columnName": "format",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadId",
"columnName": "downloadId",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "command",
"columnName": "command",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "downloads",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `format` TEXT NOT NULL, `container` TEXT NOT NULL DEFAULT 'Default', `downloadSections` TEXT NOT NULL DEFAULT '', `allFormats` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `audioPreferences` TEXT NOT NULL, `videoPreferences` TEXT NOT NULL, `extraCommands` TEXT NOT NULL DEFAULT '', `customFileNameTemplate` TEXT NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `downloadStartTime` INTEGER NOT NULL DEFAULT 0, `logID` INTEGER, `playlistURL` TEXT DEFAULT '', `playlistIndex` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "author",
"columnName": "author",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "thumb",
"columnName": "thumb",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "format",
"columnName": "format",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "container",
"columnName": "container",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'Default'"
},
{
"fieldPath": "downloadSections",
"columnName": "downloadSections",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"fieldPath": "allFormats",
"columnName": "allFormats",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadPath",
"columnName": "downloadPath",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "website",
"columnName": "website",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadSize",
"columnName": "downloadSize",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "playlistTitle",
"columnName": "playlistTitle",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "audioPreferences",
"columnName": "audioPreferences",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "videoPreferences",
"columnName": "videoPreferences",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "extraCommands",
"columnName": "extraCommands",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"fieldPath": "customFileNameTemplate",
"columnName": "customFileNameTemplate",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "SaveThumb",
"columnName": "SaveThumb",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "status",
"columnName": "status",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'Queued'"
},
{
"fieldPath": "downloadStartTime",
"columnName": "downloadStartTime",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "logID",
"columnName": "logID",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "playlistURL",
"columnName": "playlistURL",
"affinity": "TEXT",
"notNull": false,
"defaultValue": "''"
},
{
"fieldPath": "playlistIndex",
"columnName": "playlistIndex",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "commandTemplates",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `useAsExtraCommand` INTEGER NOT NULL DEFAULT 0, `useAsExtraCommandAudio` INTEGER NOT NULL DEFAULT 1, `useAsExtraCommandVideo` INTEGER NOT NULL DEFAULT 1)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "useAsExtraCommand",
"columnName": "useAsExtraCommand",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "useAsExtraCommandAudio",
"columnName": "useAsExtraCommandAudio",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "1"
},
{
"fieldPath": "useAsExtraCommandVideo",
"columnName": "useAsExtraCommandVideo",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "1"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "searchHistory",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `query` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "query",
"columnName": "query",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "templateShortcuts",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `content` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "cookies",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `content` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "logs",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadType` TEXT NOT NULL, `downloadTime` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "format",
"columnName": "format",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadType",
"columnName": "downloadType",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadTime",
"columnName": "downloadTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "terminalDownloads",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `command` TEXT NOT NULL, `log` TEXT DEFAULT '')",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "command",
"columnName": "command",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "log",
"columnName": "log",
"affinity": "TEXT",
"notNull": false,
"defaultValue": "''"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "sources",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, `downloadItemTemplate` TEXT NOT NULL, `everyNr` INTEGER NOT NULL, `everyCategory` TEXT NOT NULL, `everyTime` INTEGER NOT NULL, `weeklyConfig` TEXT, `monthlyConfig` TEXT, `status` TEXT NOT NULL, `startsTime` INTEGER NOT NULL, `endsDate` INTEGER NOT NULL DEFAULT 0, `endsAfterCount` INTEGER NOT NULL DEFAULT 0, `runCount` INTEGER NOT NULL DEFAULT 0, `getOnlyNewUploads` INTEGER NOT NULL DEFAULT 0, `retryMissingDownloads` INTEGER NOT NULL, `alreadyProcessedLinks` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadItemTemplate",
"columnName": "downloadItemTemplate",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "everyNr",
"columnName": "everyNr",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "everyCategory",
"columnName": "everyCategory",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "everyTime",
"columnName": "everyTime",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "weeklyConfig",
"columnName": "weeklyConfig",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "monthlyConfig",
"columnName": "monthlyConfig",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "status",
"columnName": "status",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "startsTime",
"columnName": "startsTime",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "endsDate",
"columnName": "endsDate",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "endsAfterCount",
"columnName": "endsAfterCount",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "runCount",
"columnName": "runCount",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "getOnlyNewUploads",
"columnName": "getOnlyNewUploads",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "retryMissingDownloads",
"columnName": "retryMissingDownloads",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "alreadyProcessedLinks",
"columnName": "alreadyProcessedLinks",
"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, '6d3700c5756542e79e6368575533f6ed')"
]
}
}

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis
package com.deniscerri.ytdl
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry

View file

@ -9,6 +9,7 @@
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
@ -18,10 +19,7 @@
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
android:name="android.permission.SCHEDULE_EXACT_ALARM"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application
@ -50,6 +48,7 @@
android:exported="true"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustPan">
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" />
</activity>
<activity
@ -222,17 +221,20 @@
<data android:host="rutube.com" />
</intent-filter>
</activity>
<activity
android:name=".receiver.ShareFileActivity"
android:name=".receiver.TransparentActivity"
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
android:excludeFromRecents="true"
android:exported="true"
android:launchMode="singleInstance"
android:theme="@style/Theme.BottomSheet">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".ui.more.settings.SettingsActivity"
android:configChanges="smallestScreenSize|layoutDirection|orientation|screenSize"
@ -280,6 +282,7 @@
android:targetActivity=".MainActivity"
android:windowSoftInputMode="adjustPan"
android:exported="true">
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@ -302,6 +305,7 @@
android:launchMode="singleTask"
android:targetActivity=".MainActivity"
android:windowSoftInputMode="adjustPan">
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@ -323,6 +327,7 @@
android:launchMode="singleTask"
android:targetActivity=".MainActivity"
android:windowSoftInputMode="adjustPan">
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@ -351,9 +356,6 @@
<receiver android:name=".receiver.CancelDownloadNotificationReceiver" />
<receiver android:name=".receiver.CancelWorkReceiver" />
<receiver android:name=".receiver.PauseDownloadNotificationReceiver" />
<receiver android:name=".receiver.downloadAlarmReceivers.AlarmStartReceiver" />
<receiver android:name=".receiver.downloadAlarmReceivers.AlarmStopReceiver" />
<receiver android:name=".receiver.ObserveAlarmReceiver" />
<activity
android:name=".receiver.ResumeActivity"

View file

@ -1,12 +1,11 @@
package com.deniscerri.ytdlnis
package com.deniscerri.ytdl
import android.app.Application
import android.os.Looper
import android.widget.Toast
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import com.deniscerri.ytdlnis.util.CrashListener
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.deniscerri.ytdl.util.NotificationUtil
import com.yausername.aria2c.Aria2c
import com.yausername.ffmpeg.FFmpeg
import com.yausername.youtubedl_android.YoutubeDL

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis
package com.deniscerri.ytdl
import android.Manifest
import android.app.ActionBar.LayoutParams
@ -35,18 +35,18 @@ import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.setupWithNavController
import androidx.preference.PreferenceManager
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.ui.BaseActivity
import com.deniscerri.ytdlnis.ui.HomeFragment
import com.deniscerri.ytdlnis.ui.more.settings.SettingsActivity
import com.deniscerri.ytdlnis.util.CrashListener
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.ThemeUtil
import com.deniscerri.ytdlnis.util.UpdateUtil
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.database.viewmodel.CookieViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.ui.BaseActivity
import com.deniscerri.ytdl.ui.HomeFragment
import com.deniscerri.ytdl.ui.more.settings.SettingsActivity
import com.deniscerri.ytdl.util.CrashListener
import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.ThemeUtil
import com.deniscerri.ytdl.util.UpdateUtil
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.elevation.SurfaceColors
@ -59,7 +59,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@ -101,6 +100,8 @@ class MainActivity : BaseActivity() {
}
}
askPermissions()
checkUpdate()
@ -412,6 +413,24 @@ class MainActivity : BaseActivity() {
} catch (e: Exception) {
e.printStackTrace()
}
}else if (action == Intent.ACTION_VIEW){
when(intent.getStringExtra("destination")){
"Downloads" -> {
navController.navigate(R.id.historyFragment)
}
"Queue" -> {
navController.navigate(R.id.downloadQueueMainFragment)
}
"Search" -> {
val bundle = Bundle()
bundle.putBoolean("search", true)
navController.popBackStack(R.id.homeFragment, true)
navController.navigate(
R.id.homeFragment,
bundle
)
}
}
}
}
@ -425,88 +444,6 @@ class MainActivity : BaseActivity() {
}
}
private fun askPermissions() {
val permissions = arrayListOf<String>()
if (!checkFilePermission()) {
if (Build.VERSION.SDK_INT >= 33){
permissions.add(Manifest.permission.READ_MEDIA_AUDIO)
permissions.add(Manifest.permission.READ_MEDIA_VIDEO)
}else{
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE)
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (!checkNotificationPermission()){
permissions.add(Manifest.permission.POST_NOTIFICATIONS)
}
}
if (permissions.isNotEmpty()){
ActivityCompat.requestPermissions(
this,
permissions.toTypedArray(),
1
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
for (i in permissions.indices) {
if (permissions.contains(Manifest.permission.POST_NOTIFICATIONS)) continue
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
createPermissionRequestDialog()
}
}
}
private fun exit() {
finishAffinity()
exitProcess(0)
}
private fun checkFilePermission(): Boolean {
return if(Build.VERSION.SDK_INT >= 33){
(ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO)
== PackageManager.PERMISSION_GRANTED) &&
(ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_VIDEO)
== PackageManager.PERMISSION_GRANTED)
}else{
(ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) &&
(ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED)
}
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun checkNotificationPermission(): Boolean {
return (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED)
}
private fun createPermissionRequestDialog() {
val dialog = MaterialAlertDialogBuilder(this)
dialog.setTitle(getString(R.string.warning))
dialog.setMessage(getString(R.string.request_permission_desc))
dialog.setOnCancelListener { exit() }
dialog.setNegativeButton(getString(R.string.exit_app)) { _: DialogInterface?, _: Int -> exit() }
dialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null)
)
startActivity(intent)
exitProcess(0)
}
dialog.show()
}
companion object {
private const val TAG = "MainActivity"
}

View file

@ -1,12 +1,14 @@
package com.deniscerri.ytdlnis.database
package com.deniscerri.ytdl.database
import androidx.room.TypeConverter
import com.deniscerri.ytdlnis.database.models.AudioPreferences
import com.deniscerri.ytdlnis.database.models.ChapterItem
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.VideoPreferences
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.models.AudioPreferences
import com.deniscerri.ytdl.database.models.ChapterItem
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.Format
import com.deniscerri.ytdl.database.models.VideoPreferences
import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesMonthlyConfig
import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesWeeklyConfig
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.google.gson.Gson
@ -73,4 +75,17 @@ class Converters {
@TypeConverter
fun stringtoMutableListofStrings(s: String) = Gson().fromJson(s, Array<String>::class.java).toMutableList()
@TypeConverter
fun observeSourcesWeeklyConfigToString(c: ObserveSourcesWeeklyConfig) = Gson().toJson(c)
@TypeConverter
fun stringToObserveSourcesWeeklyConfig(s: String) = Gson().fromJson(s, ObserveSourcesWeeklyConfig::class.java)
@TypeConverter
fun observeSourcesMonthlyConfigToString(c: ObserveSourcesMonthlyConfig) = Gson().toJson(c)
@TypeConverter
fun stringToObserveSourcesMonthlyConfig(s: String) = Gson().fromJson(s, ObserveSourcesMonthlyConfig::class.java)
}

View file

@ -1,30 +1,31 @@
package com.deniscerri.ytdlnis.database
package com.deniscerri.ytdl.database
import android.content.Context
import androidx.room.AutoMigration
import androidx.room.Database
import androidx.room.DeleteTable
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
import com.deniscerri.ytdlnis.database.dao.CookieDao
import com.deniscerri.ytdlnis.database.dao.DownloadDao
import com.deniscerri.ytdlnis.database.dao.HistoryDao
import com.deniscerri.ytdlnis.database.dao.LogDao
import com.deniscerri.ytdlnis.database.dao.ObserveSourcesDao
import com.deniscerri.ytdlnis.database.dao.ResultDao
import com.deniscerri.ytdlnis.database.dao.SearchHistoryDao
import com.deniscerri.ytdlnis.database.dao.TerminalDao
import com.deniscerri.ytdlnis.database.models.CommandTemplate
import com.deniscerri.ytdlnis.database.models.CookieItem
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.models.ObserveSourcesItem
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.models.SearchHistoryItem
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
import com.deniscerri.ytdlnis.database.models.TerminalItem
import com.deniscerri.ytdl.database.dao.CommandTemplateDao
import com.deniscerri.ytdl.database.dao.CookieDao
import com.deniscerri.ytdl.database.dao.DownloadDao
import com.deniscerri.ytdl.database.dao.HistoryDao
import com.deniscerri.ytdl.database.dao.LogDao
import com.deniscerri.ytdl.database.dao.ObserveSourcesDao
import com.deniscerri.ytdl.database.dao.ResultDao
import com.deniscerri.ytdl.database.dao.SearchHistoryDao
import com.deniscerri.ytdl.database.dao.TerminalDao
import com.deniscerri.ytdl.database.models.CommandTemplate
import com.deniscerri.ytdl.database.models.CookieItem
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.HistoryItem
import com.deniscerri.ytdl.database.models.LogItem
import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesItem
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.database.models.SearchHistoryItem
import com.deniscerri.ytdl.database.models.TemplateShortcut
import com.deniscerri.ytdl.database.models.TerminalItem
@TypeConverters(Converters::class)
@Database(
@ -40,7 +41,7 @@ import com.deniscerri.ytdlnis.database.models.TerminalItem
TerminalItem::class,
ObserveSourcesItem::class
],
version = 15,
version = 16,
autoMigrations = [
AutoMigration (from = 1, to = 2),
AutoMigration (from = 2, to = 3),
@ -56,6 +57,7 @@ import com.deniscerri.ytdlnis.database.models.TerminalItem
AutoMigration (from = 12, to = 13),
// AutoMigration (from = 13, to = 14) MANUALLY HANDLED
AutoMigration (from = 14, to = 15),
AutoMigration (from = 15, to = 16, spec = Migrations.resetObserveSources::class)
]
)
abstract class DBManager : RoomDatabase(){

View file

@ -1,7 +1,10 @@
package com.deniscerri.ytdlnis.database
package com.deniscerri.ytdl.database
import android.annotation.SuppressLint
import androidx.room.DeleteTable
import androidx.room.migration.AutoMigrationSpec
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
object Migrations {
@ -23,6 +26,18 @@ object Migrations {
}
)
@DeleteTable.Entries(
DeleteTable(
tableName = "observeSources"
)
)
class resetObserveSources : AutoMigrationSpec {
@Override
override fun onPostMigrate(db: SupportSQLiteDatabase) {
// Invoked once auto migration is done
}
}
}

View file

@ -1,12 +1,12 @@
package com.deniscerri.ytdlnis.database.dao
package com.deniscerri.ytdl.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.deniscerri.ytdlnis.database.models.CommandTemplate
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
import com.deniscerri.ytdl.database.models.CommandTemplate
import com.deniscerri.ytdl.database.models.TemplateShortcut
import kotlinx.coroutines.flow.Flow
@Dao

View file

@ -1,11 +1,11 @@
package com.deniscerri.ytdlnis.database.dao
package com.deniscerri.ytdl.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.deniscerri.ytdlnis.database.models.CookieItem
import com.deniscerri.ytdl.database.models.CookieItem
import kotlinx.coroutines.flow.Flow
@Dao

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.dao
package com.deniscerri.ytdl.database.dao
import androidx.paging.PagingSource
import androidx.room.Dao
@ -9,9 +9,9 @@ import androidx.room.RewriteQueriesToDropUnusedColumns
import androidx.room.Transaction
import androidx.room.Update
import androidx.room.Upsert
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.DownloadItemSimple
import com.deniscerri.ytdl.database.models.Format
import kotlinx.coroutines.flow.Flow
@Dao

View file

@ -1,11 +1,11 @@
package com.deniscerri.ytdlnis.database.dao
package com.deniscerri.ytdl.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdl.database.models.HistoryItem
import kotlinx.coroutines.flow.Flow
@Dao

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.dao
package com.deniscerri.ytdl.database.dao
import androidx.room.Dao
import androidx.room.Insert
@ -6,7 +6,7 @@ import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import com.deniscerri.ytdlnis.database.models.LogItem
import com.deniscerri.ytdl.database.models.LogItem
import kotlinx.coroutines.flow.Flow
@Dao

View file

@ -1,37 +1,37 @@
package com.deniscerri.ytdlnis.database.dao
package com.deniscerri.ytdl.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.deniscerri.ytdlnis.database.models.ObserveSourcesItem
import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesItem
import kotlinx.coroutines.flow.Flow
@Dao
interface ObserveSourcesDao {
@Query("SELECT * FROM observeSources ORDER BY id DESC")
@Query("SELECT * FROM sources ORDER BY id DESC")
fun getAllSources() : List<ObserveSourcesItem>
@Query("SELECT * FROM observeSources WHERE url = :url LIMIT 1")
@Query("SELECT * FROM sources WHERE url = :url LIMIT 1")
fun getByURL(url: String) : ObserveSourcesItem
@Query("SELECT * FROM observeSources WHERE id = :id LIMIT 1")
@Query("SELECT * FROM sources WHERE id = :id LIMIT 1")
fun getByID(id: Long) : ObserveSourcesItem
@Query("SELECT * FROM observeSources ORDER BY id DESC")
@Query("SELECT * FROM sources ORDER BY id DESC")
fun getAllSourcesFlow() : Flow<List<ObserveSourcesItem>>
@Query("SELECT EXISTS(SELECT * FROM observeSources WHERE url=:url LIMIT 1)")
@Query("SELECT EXISTS(SELECT * FROM sources WHERE url=:url LIMIT 1)")
fun checkIfExistsWithSameURL(url: String) : Boolean
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(item: ObserveSourcesItem) : Long
@Query("DELETE FROM observeSources")
@Query("DELETE FROM sources")
suspend fun deleteAll()
@Query("DELETE FROM observeSources WHERE id=:itemId")
@Query("DELETE FROM sources WHERE id=:itemId")
suspend fun delete(itemId: Long)
@Update(onConflict = OnConflictStrategy.REPLACE)

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.dao
package com.deniscerri.ytdl.database.dao
import androidx.room.Dao
import androidx.room.Insert
@ -6,7 +6,7 @@ import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdl.database.models.ResultItem
import kotlinx.coroutines.flow.Flow
@Dao

View file

@ -1,10 +1,10 @@
package com.deniscerri.ytdlnis.database.dao
package com.deniscerri.ytdl.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.deniscerri.ytdlnis.database.models.SearchHistoryItem
import com.deniscerri.ytdl.database.models.SearchHistoryItem
@Dao
interface SearchHistoryDao {

View file

@ -1,11 +1,11 @@
package com.deniscerri.ytdlnis.database.dao
package com.deniscerri.ytdl.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Transaction
import com.deniscerri.ytdlnis.database.models.TerminalItem
import com.deniscerri.ytdlnis.util.Extensions.appendLineToLog
import com.deniscerri.ytdl.database.models.TerminalItem
import com.deniscerri.ytdl.util.Extensions.appendLineToLog
import kotlinx.coroutines.flow.Flow
@Dao

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import android.os.Parcelable
import kotlinx.parcelize.Parcelize

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import android.os.Parcelable
import com.google.gson.annotations.SerializedName

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import androidx.room.ColumnInfo
import androidx.room.Entity

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import kotlinx.serialization.Serializable

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import androidx.room.Entity
import androidx.room.PrimaryKey

View file

@ -1,10 +1,10 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import kotlinx.parcelize.Parcelize
@Entity(tableName = "downloads")

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import androidx.room.ColumnInfo
import androidx.room.Entity

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import android.os.Parcelable
import com.google.gson.annotations.SerializedName

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import com.google.gson.annotations.SerializedName
import java.util.Date

View file

@ -1,9 +1,9 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
@Entity(tableName = "history")
data class HistoryItem(

View file

@ -1,8 +1,8 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
@Entity(tableName = "logs")
data class LogItem(

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import android.os.Parcelable
import androidx.room.ColumnInfo

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import androidx.room.Entity
import androidx.room.PrimaryKey

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
data class SearchSuggestionItem(
var text: String,

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import androidx.room.Entity
import androidx.room.PrimaryKey

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import androidx.room.ColumnInfo
import androidx.room.Entity

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models
import android.os.Parcelable
import kotlinx.parcelize.Parcelize

View file

@ -1,14 +1,15 @@
package com.deniscerri.ytdlnis.database.models
package com.deniscerri.ytdl.database.models.observeSources
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.deniscerri.ytdlnis.database.repository.ObserveSourcesRepository
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.repository.ObserveSourcesRepository
import kotlinx.parcelize.Parcelize
import java.time.Month
@Entity(tableName = "observeSources")
@Entity(tableName = "sources")
@Parcelize
data class ObserveSourcesItem(
@PrimaryKey(autoGenerate = true)
@ -16,14 +17,15 @@ data class ObserveSourcesItem(
var name: String,
var url: String,
var downloadItemTemplate: DownloadItem,
var status: ObserveSourcesRepository.SourceStatus,
var everyNr: Int,
var everyCategory: ObserveSourcesRepository.EveryCategory,
val everyWeekDay: List<String>,
val everyMonthDay: Int,
val everyTime: Long,
var weeklyConfig: ObserveSourcesWeeklyConfig?,
var monthlyConfig: ObserveSourcesMonthlyConfig?,
var status: ObserveSourcesRepository.SourceStatus,
var startsTime: Long,
val startsMonth: Month,
@ColumnInfo(defaultValue = "0")
var endsDate: Long,
@ColumnInfo(defaultValue = "0")

View file

@ -0,0 +1,11 @@
package com.deniscerri.ytdl.database.models.observeSources
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import java.time.Month
@Parcelize
data class ObserveSourcesMonthlyConfig(
var everyMonthDay: Int,
var startsMonth: Int
) : Parcelable

View file

@ -0,0 +1,9 @@
package com.deniscerri.ytdl.database.models.observeSources
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class ObserveSourcesWeeklyConfig(
var weekDays: List<Int>
) : Parcelable

View file

@ -1,9 +1,9 @@
package com.deniscerri.ytdlnis.database.repository
package com.deniscerri.ytdl.database.repository
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
import com.deniscerri.ytdlnis.database.models.CommandTemplate
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.dao.CommandTemplateDao
import com.deniscerri.ytdl.database.models.CommandTemplate
import com.deniscerri.ytdl.database.models.TemplateShortcut
import kotlinx.coroutines.flow.Flow
class CommandTemplateRepository(private val commandDao: CommandTemplateDao) {

View file

@ -1,7 +1,7 @@
package com.deniscerri.ytdlnis.database.repository
package com.deniscerri.ytdl.database.repository
import com.deniscerri.ytdlnis.database.dao.CookieDao
import com.deniscerri.ytdlnis.database.models.CookieItem
import com.deniscerri.ytdl.database.dao.CookieDao
import com.deniscerri.ytdl.database.models.CookieItem
import kotlinx.coroutines.flow.Flow
class CookieRepository(private val cookieDao: CookieDao) {

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.repository
package com.deniscerri.ytdl.database.repository
import android.annotation.SuppressLint
import android.content.Context
@ -16,14 +16,14 @@ import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkInfo
import androidx.work.WorkManager
import androidx.work.await
import com.deniscerri.ytdlnis.App
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.dao.DownloadDao
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
import com.deniscerri.ytdlnis.util.Extensions.toListString
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.work.DownloadWorker
import com.deniscerri.ytdl.App
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.dao.DownloadDao
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.DownloadItemSimple
import com.deniscerri.ytdl.util.Extensions.toListString
import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.work.DownloadWorker
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import java.io.File

View file

@ -1,9 +1,9 @@
package com.deniscerri.ytdlnis.database.repository
package com.deniscerri.ytdl.database.repository
import com.deniscerri.ytdlnis.database.DBManager.SORTING
import com.deniscerri.ytdlnis.database.dao.HistoryDao
import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdl.database.DBManager.SORTING
import com.deniscerri.ytdl.database.dao.HistoryDao
import com.deniscerri.ytdl.database.models.HistoryItem
import com.deniscerri.ytdl.util.FileUtil
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest

View file

@ -1,8 +1,8 @@
package com.deniscerri.ytdlnis.database.repository
package com.deniscerri.ytdl.database.repository
import com.deniscerri.ytdlnis.database.dao.LogDao
import com.deniscerri.ytdlnis.database.models.LogItem
import com.deniscerri.ytdlnis.util.Extensions.appendLineToLog
import com.deniscerri.ytdl.database.dao.LogDao
import com.deniscerri.ytdl.database.models.LogItem
import com.deniscerri.ytdl.util.Extensions.appendLineToLog
import kotlinx.coroutines.flow.Flow
class LogRepository(private val logDao: LogDao) {

View file

@ -0,0 +1,61 @@
package com.deniscerri.ytdl.database.repository
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.dao.ObserveSourcesDao
import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesItem
import kotlinx.coroutines.flow.Flow
class ObserveSourcesRepository(private val observeSourcesDao: ObserveSourcesDao) {
val items : Flow<List<ObserveSourcesItem>> = observeSourcesDao.getAllSourcesFlow()
enum class SourceStatus {
ACTIVE, STOPPED
}
enum class EveryCategory {
HOUR, DAY, WEEK, MONTH
}
companion object {
val everyCategoryName = mapOf(
EveryCategory.HOUR to R.string.hour,
EveryCategory.DAY to R.string.day,
EveryCategory.WEEK to R.string.week,
EveryCategory.MONTH to R.string.month
)
}
fun getAll() : List<ObserveSourcesItem> {
return observeSourcesDao.getAllSources()
}
fun getByURL(url: String) : ObserveSourcesItem {
return observeSourcesDao.getByURL(url)
}
fun getByID(id: Long) : ObserveSourcesItem {
return observeSourcesDao.getByID(id)
}
suspend fun insert(item: ObserveSourcesItem) : Long{
if (!observeSourcesDao.checkIfExistsWithSameURL(item.url)){
return observeSourcesDao.insert(item)
}
return -1
}
suspend fun delete(item: ObserveSourcesItem){
observeSourcesDao.delete(item.id)
}
suspend fun deleteAll(){
observeSourcesDao.deleteAll()
}
suspend fun update(item: ObserveSourcesItem){
observeSourcesDao.update(item)
}
}

View file

@ -1,11 +1,11 @@
package com.deniscerri.ytdlnis.database.repository
package com.deniscerri.ytdl.database.repository
import android.content.Context
import android.util.Patterns
import com.deniscerri.ytdlnis.database.dao.ResultDao
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdl.database.dao.ResultDao
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.util.InfoUtil
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import java.util.regex.Pattern

View file

@ -1,7 +1,7 @@
package com.deniscerri.ytdlnis.database.repository
package com.deniscerri.ytdl.database.repository
import com.deniscerri.ytdlnis.database.dao.SearchHistoryDao
import com.deniscerri.ytdlnis.database.models.SearchHistoryItem
import com.deniscerri.ytdl.database.dao.SearchHistoryDao
import com.deniscerri.ytdl.database.models.SearchHistoryItem
class SearchHistoryRepository(private val searchHistoryDao: SearchHistoryDao) {
fun getAll() : List<SearchHistoryItem> {

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.viewmodel
package com.deniscerri.ytdl.database.viewmodel
import android.app.Application
import android.content.ClipboardManager
@ -9,11 +9,11 @@ import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.models.CommandTemplate
import com.deniscerri.ytdlnis.database.models.CommandTemplateExport
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
import com.deniscerri.ytdlnis.database.repository.CommandTemplateRepository
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.models.CommandTemplate
import com.deniscerri.ytdl.database.models.CommandTemplateExport
import com.deniscerri.ytdl.database.models.TemplateShortcut
import com.deniscerri.ytdl.database.repository.CommandTemplateRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

View file

@ -1,15 +1,11 @@
package com.deniscerri.ytdlnis.database.viewmodel
package com.deniscerri.ytdl.database.viewmodel
import android.R.attr.description
import android.R.attr.duration
import android.annotation.SuppressLint
import android.app.Application
import android.content.ClipboardManager
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteDatabase.OPEN_READONLY
import android.database.sqlite.SQLiteDatabase.OPEN_READWRITE
import android.os.Environment
import android.util.Log
import android.webkit.CookieManager
@ -17,13 +13,12 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import com.deniscerri.ytdlnis.BuildConfig
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.models.CookieItem
import com.deniscerri.ytdlnis.database.repository.CookieRepository
import com.deniscerri.ytdlnis.ui.more.WebViewActivity
import com.deniscerri.ytdlnis.util.Extensions.convertNetscapeToSetCookie
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdl.BuildConfig
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.models.CookieItem
import com.deniscerri.ytdl.database.repository.CookieRepository
import com.deniscerri.ytdl.ui.more.WebViewActivity
import com.deniscerri.ytdl.util.FileUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.viewmodel
package com.deniscerri.ytdl.database.viewmodel
import android.annotation.SuppressLint
import android.app.Application
@ -6,6 +6,7 @@ import android.content.SharedPreferences
import android.content.res.Configuration
import android.content.res.Resources
import android.util.DisplayMetrics
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
@ -17,27 +18,27 @@ import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
import com.deniscerri.ytdlnis.App
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
import com.deniscerri.ytdlnis.database.dao.DownloadDao
import com.deniscerri.ytdlnis.database.models.AudioPreferences
import com.deniscerri.ytdlnis.database.models.CommandTemplate
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.models.VideoPreferences
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.repository.HistoryRepository
import com.deniscerri.ytdlnis.database.repository.ResultRepository
import com.deniscerri.ytdlnis.ui.downloadcard.FormatTuple
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.work.AlarmScheduler
import com.deniscerri.ytdlnis.work.UpdatePlaylistFormatsWorker
import com.deniscerri.ytdl.App
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.dao.CommandTemplateDao
import com.deniscerri.ytdl.database.dao.DownloadDao
import com.deniscerri.ytdl.database.models.AudioPreferences
import com.deniscerri.ytdl.database.models.CommandTemplate
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.DownloadItemSimple
import com.deniscerri.ytdl.database.models.Format
import com.deniscerri.ytdl.database.models.HistoryItem
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.database.models.VideoPreferences
import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.database.repository.HistoryRepository
import com.deniscerri.ytdl.database.repository.ResultRepository
import com.deniscerri.ytdl.ui.downloadcard.FormatTuple
import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.InfoUtil
import com.deniscerri.ytdl.work.AlarmScheduler
import com.deniscerri.ytdl.work.UpdatePlaylistFormatsWorker
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -458,28 +459,61 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
}
fun getPreferredAudioRequirements(): MutableList<(Format) -> Boolean> {
val requirements: MutableList<(Format) -> Boolean> = mutableListOf()
requirements.add {it: Format -> audioFormatIDPreference.contains(it.format_id)}
fun getPreferredAudioRequirements(): MutableList<(Format) -> Int> {
val requirements: MutableList<(Format) -> Int> = mutableListOf()
requirements.add {it: Format -> if (audioFormatIDPreference.contains(it.format_id)) 10 else 0}
sharedPreferences.getString("audio_language", "")?.apply {
if (this.isNotBlank()){
requirements.add { it: Format -> it.lang?.contains(this) == true }
requirements.add { it: Format -> if (it.lang?.contains(this) == true) 3 else 0 }
}
}
requirements.add {it: Format -> it.container == audioContainer }
requirements.add {it: Format -> "^(${audioCodec}).+$".toRegex(RegexOption.IGNORE_CASE).matches(it.acodec)}
requirements.add {it: Format -> if ("^(${audioCodec}).+$".toRegex(RegexOption.IGNORE_CASE).matches(it.acodec)) 2 else 0}
requirements.add {it: Format -> if (it.container == audioContainer) 1 else 0 }
return requirements
}
fun getPreferredVideoRequirements(): MutableList<(Format) -> Boolean> {
val requirements: MutableList<(Format) -> Boolean> = mutableListOf()
requirements.add { it: Format -> formatIDPreference.contains(it.format_id) }
requirements.add { it: Format -> if (videoContainer == "mp4") it.container.equals("mpeg_4", true) else it.container.equals(videoContainer, true)}
requirements.add { it: Format -> it.format_note.contains(videoQualityPreference.split("_")[0].dropLast(1)) }
requirements.add { it: Format -> "^(${videoCodec}).+$".toRegex(RegexOption.IGNORE_CASE).matches(it.vcodec)}
requirements.add { it: Format -> it.acodec == "none" || it.acodec == "" }
//requirement and importance
@SuppressLint("RestrictedApi")
fun getPreferredVideoRequirements(): MutableList<(Format) -> Int> {
val requirements: MutableList<(Format) -> Int> = mutableListOf()
//format id
requirements.add { it: Format -> if (formatIDPreference.contains(it.format_id)) 20 else 0 }
//resolutions
application.getStringArray(R.array.video_formats_values)
.filter { it.contains("_") }
.map{ it.split("_")[0].dropLast(1)
}.toMutableList().apply {
when(videoQualityPreference) {
"worst" -> {
requirements.add { it: Format -> if (it.format_note.contains("worst", ignoreCase = true)) (15) else 0 }
}
"best" -> {
requirements.add { it: Format -> if (it.format_note.contains("best", ignoreCase = true)) (15) else 0 }
}
else -> {
val preferenceIndex = this.indexOfFirst { videoQualityPreference.contains(it) }
val preference = this[preferenceIndex]
for(i in 0..preferenceIndex){
removeAt(0)
}
add(0, preference)
forEachIndexed { index, res ->
requirements.add { it: Format -> if (it.format_note.contains(res, ignoreCase = true)) (15 - index - 1) else 0 }
}
}
}
}
requirements.add { it: Format -> if ("^(${videoCodec})(.+)?$".toRegex(RegexOption.IGNORE_CASE).matches(it.vcodec)) 5 else 0 }
requirements.add { it: Format -> if (it.acodec == "none" || it.acodec == "") 1 else 0 }
requirements.add { it: Format ->
if (videoContainer == "mp4")
if (it.container.equals("mpeg_4", true)) 1 else 0
else
if (it.container.equals(videoContainer, true)) 1 else 0
}
return requirements
}
@ -490,7 +524,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
try {
val theFormats = formats.filter { it.vcodec.isBlank() || it.vcodec == "none" }
val requirements = getPreferredAudioRequirements()
theFormats.maxByOrNull { f -> requirements.count{req -> req(f)} } ?: throw Exception()
theFormats.maxByOrNull { f -> requirements.sumOf{ req -> req(f)} } ?: throw Exception()
}catch (e: Exception){
bestAudioFormat
}
@ -500,14 +534,25 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
Type.video -> {
return cloneFormat(
try {
val theFormats = formats.filter { it.vcodec.isNotBlank() && it.vcodec != "null" }.ifEmpty { defaultVideoFormats.sortedByDescending { it.filesize } }
val theFormats = formats.filter { it.vcodec.isNotBlank() && it.vcodec != "none" }.ifEmpty {
defaultVideoFormats.sortedByDescending { it.filesize }
}
when (videoQualityPreference) {
"worst" -> {
theFormats.last()
}
else /*best*/ -> {
val requirements = getPreferredVideoRequirements()
theFormats.maxByOrNull { f -> requirements.count{ req -> req(f)} } ?: throw Exception()
theFormats.run {
if (sharedPreferences.getBoolean("prefer_smaller_formats", false)){
sortedBy { it.filesize }.maxByOrNull { f -> requirements.sumOf { req -> req(f) } } ?: throw Exception()
}else{
sortedByDescending { it.filesize }.maxByOrNull { f ->
val summ = requirements.sumOf { req -> req(f) }
summ
} ?: throw Exception()
}
}
}
}
}catch (e: Exception){
@ -828,7 +873,9 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
suspend fun updateProcessingFormat(selectedFormats: List<FormatTuple>): List<Long> {
val items = repository.getProcessingDownloads()
items.forEachIndexed { index, i ->
i.format = selectedFormats[index].format
selectedFormats[index].format?.apply {
i.format = this
}
if (i.type == Type.video) selectedFormats[index].audioFormats?.map { it.format_id }?.let { i.videoPreferences.audioFormatIDs.addAll(it) }
repository.update(i)
}

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.viewmodel
package com.deniscerri.ytdl.database.viewmodel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
@ -7,11 +7,11 @@ import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.DBManager.SORTING
import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.repository.HistoryRepository
import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySortType
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.DBManager.SORTING
import com.deniscerri.ytdl.database.models.HistoryItem
import com.deniscerri.ytdl.database.repository.HistoryRepository
import com.deniscerri.ytdl.database.repository.HistoryRepository.HistorySortType
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

View file

@ -1,14 +1,14 @@
package com.deniscerri.ytdlnis.database.viewmodel
package com.deniscerri.ytdl.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.DownloadRepository
import com.deniscerri.ytdlnis.database.repository.LogRepository
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.models.LogItem
import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.database.repository.LogRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

View file

@ -0,0 +1,147 @@
package com.deniscerri.ytdl.database.viewmodel
import android.app.Application
import android.content.SharedPreferences
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import androidx.preference.PreferenceManager
import androidx.work.Constraints
import androidx.work.Data
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesItem
import com.deniscerri.ytdl.database.repository.ObserveSourcesRepository
import com.deniscerri.ytdl.work.ObserveSourceWorker
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.Calendar
import java.util.concurrent.TimeUnit
class ObserveSourcesViewModel(private val application: Application) : AndroidViewModel(application) {
private val repository: ObserveSourcesRepository
val items: LiveData<List<ObserveSourcesItem>>
private val workManager : WorkManager
private val preferences : SharedPreferences
init {
val dao = DBManager.getInstance(application).observeSourcesDao
repository = ObserveSourcesRepository(dao)
items = repository.items.asLiveData()
workManager = WorkManager.getInstance(application)
preferences = PreferenceManager.getDefaultSharedPreferences(application)
}
fun getAll(): List<ObserveSourcesItem> {
return repository.getAll()
}
fun getByURL(url: String) : ObserveSourcesItem {
return repository.getByURL(url)
}
fun getByID(id: Long) : ObserveSourcesItem {
return repository.getByID(id)
}
suspend fun insert(item: ObserveSourcesItem) : Long {
if (item.id > 0) {
repository.update(item)
observeTask(item)
return item.id
}
val id = repository.insert(item)
item.id = id
if (id > 0) observeTask(item)
return id
}
fun delete(item: ObserveSourcesItem) = viewModelScope.launch(Dispatchers.IO) {
runCatching { cancelObservationTaskByID(item.id) }
repository.delete(item)
}
fun deleteAll() = viewModelScope.launch(Dispatchers.IO) {
getAll().forEach {
runCatching { cancelObservationTaskByID(it.id) }
}
repository.deleteAll()
}
suspend fun update(item: ObserveSourcesItem) {
repository.update(item)
}
private fun cancelObservationTaskByID(id: Long){
workManager.cancelAllWorkByTag(id.toString())
}
private fun observeTask(it: ObserveSourcesItem){
cancelObservationTaskByID(it.id)
Calendar.getInstance().apply {
timeInMillis = it.startsTime
val date = Calendar.getInstance()
set(Calendar.DAY_OF_MONTH, date.get(Calendar.DAY_OF_MONTH))
set(Calendar.MONTH, date.get(Calendar.MONTH))
set(Calendar.YEAR, date.get(Calendar.YEAR))
if (it.everyCategory != ObserveSourcesRepository.EveryCategory.HOUR){
val hourMin = Calendar.getInstance()
hourMin.timeInMillis = it.everyTime
set(Calendar.HOUR_OF_DAY, hourMin.get(Calendar.HOUR_OF_DAY))
set(Calendar.MINUTE, hourMin.get(Calendar.MINUTE))
}
when(it.everyCategory){
ObserveSourcesRepository.EveryCategory.HOUR -> {}
ObserveSourcesRepository.EveryCategory.DAY -> {}
ObserveSourcesRepository.EveryCategory.WEEK -> {
var weekDayNr = get(Calendar.DAY_OF_WEEK) - 1
if (weekDayNr == 0) weekDayNr = 7
val followingWeekDay = it.weeklyConfig?.weekDays?.firstOrNull { it >= weekDayNr }
if (followingWeekDay == null){
add(Calendar.DAY_OF_MONTH,
it.weeklyConfig?.weekDays?.minBy { it }?.plus((7 - weekDayNr)) ?: 0)
}else{
add(Calendar.DAY_OF_MONTH, followingWeekDay - weekDayNr)
}
}
ObserveSourcesRepository.EveryCategory.MONTH -> {
val currentMonthIndex = get(Calendar.MONTH)
if (it.monthlyConfig?.startsMonth != currentMonthIndex){
set(Calendar.MONTH, it.monthlyConfig?.startsMonth ?: 0)
if (timeInMillis < Calendar.getInstance().timeInMillis){
add(Calendar.YEAR, 1)
}
}
}
}
//schedule for next time
val workConstraints = Constraints.Builder()
val workRequest = OneTimeWorkRequestBuilder<ObserveSourceWorker>()
.addTag("observeSources")
.addTag(it.id.toString())
.setConstraints(workConstraints.build())
.setInitialDelay(System.currentTimeMillis() - timeInMillis, TimeUnit.MILLISECONDS)
.setInputData(Data.Builder().putLong("id", it.id).build())
workManager.enqueueUniqueWork(
"OBSERVE${it.id}",
ExistingWorkPolicy.REPLACE,
workRequest.build()
)
}
}
}

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.viewmodel
package com.deniscerri.ytdl.database.viewmodel
import android.app.ActivityManager
import android.app.ActivityManager.RunningAppProcessInfo
@ -10,24 +10,22 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import androidx.preference.PreferenceManager
import com.deniscerri.ytdlnis.App
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.dao.DownloadDao
import com.deniscerri.ytdlnis.database.dao.ResultDao
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.models.SearchHistoryItem
import com.deniscerri.ytdlnis.database.repository.ResultRepository
import com.deniscerri.ytdlnis.database.repository.SearchHistoryRepository
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.deniscerri.ytdl.App
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.dao.ResultDao
import com.deniscerri.ytdl.database.models.Format
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.database.models.SearchHistoryItem
import com.deniscerri.ytdl.database.repository.ResultRepository
import com.deniscerri.ytdl.database.repository.SearchHistoryRepository
import com.deniscerri.ytdl.util.InfoUtil
import com.deniscerri.ytdl.util.NotificationUtil
import com.yausername.youtubedl_android.YoutubeDLException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.util.concurrent.CancellationException
@ -106,36 +104,42 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
uiState.update {it.copy(processing = false)}
}
private suspend fun parseQueriesImpl(inputQueries: List<String>, onResult: (list: List<ResultItem?>) -> Unit) {
if (inputQueries.size > 1){
repository.itemCount.value = inputQueries.size
}
val resetResults = inputQueries.size == 1
uiState.update {it.copy(processing = true, errorMessage = null, actions = null)}
val res = mutableListOf<ResultItem?>()
inputQueries.forEach { inputQuery ->
try {
res.addAll(repository.getResultsFromSource(inputQuery, resetResults))
} catch (e: Exception) {
if (updateResultDataJob?.isCancelled == false || e is YoutubeDLException){
uiState.update {it.copy(
processing = false,
errorMessage = Pair(R.string.no_results, e.message.toString()),
actions = mutableListOf(Pair(R.string.copy_log, ResultAction.COPY_LOG))
)}
Log.e(tag, e.toString())
}
}
}
if (!isForegrounded() && inputQueries.size > 1){
notificationUtil.showQueriesFinished()
}
uiState.update {it.copy(processing = false)}
onResult(res)
}
suspend fun parseQueries(inputQueries: List<String>, onResult: (list: List<ResultItem?>) -> Unit) {
if (parsingQueries == null || parsingQueries?.isCancelled == true || parsingQueries?.isCompleted == true) {
parsingQueries = viewModelScope.launch(Dispatchers.IO) {
if (inputQueries.size > 1){
repository.itemCount.value = inputQueries.size
parseQueriesImpl(inputQueries) {
onResult(it)
}
val resetResults = inputQueries.size == 1
uiState.update {it.copy(processing = true, errorMessage = null, actions = null)}
val res = mutableListOf<ResultItem?>()
inputQueries.forEach { inputQuery ->
try {
res.addAll(repository.getResultsFromSource(inputQuery, resetResults))
} catch (e: Exception) {
if (updateResultDataJob?.isCancelled == false || e is YoutubeDLException){
uiState.update {it.copy(
processing = false,
errorMessage = Pair(R.string.no_results, e.message.toString()),
actions = mutableListOf(Pair(R.string.copy_log, ResultAction.COPY_LOG))
)}
Log.e(tag, e.toString())
}
}
}
if (!isForegrounded() && inputQueries.size > 1){
notificationUtil.showQueriesFinished()
}
uiState.update {it.copy(processing = false)}
onResult(res)
}
}else{
onResult(listOf())
@ -207,7 +211,7 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
updateResultDataJob = viewModelScope.launch(Dispatchers.IO) {
updatingData.emit(true)
updatingData.value = true
parseQueries(listOf(res.url)){ result ->
parseQueriesImpl(listOf(res.url)){ result ->
viewModelScope.launch(Dispatchers.IO){
updatingData.emit(false)
updatingData.value = false
@ -216,7 +220,7 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
}
}
updateResultDataJob?.start()
//updateResultDataJob?.start()
updateResultDataJob?.invokeOnCompletion {
if (it != null){
viewModelScope.launch(Dispatchers.IO) {
@ -230,7 +234,7 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
}
}
suspend fun cancelUpdateItemData(){
suspend fun cancelUpdateItemData() = viewModelScope.launch(Dispatchers.IO) {
updateResultDataJob?.cancel(CancellationException())
updatingData.emit(false)
updatingData.value = false
@ -238,7 +242,7 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
updateResultData.value = null
}
suspend fun cancelUpdateFormatsItemData(){
suspend fun cancelUpdateFormatsItemData() = viewModelScope.launch(Dispatchers.IO) {
updatingFormats.emit(false)
updatingFormats.value = false
updateFormatsResultData.emit(null)

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.database.viewmodel
package com.deniscerri.ytdl.database.viewmodel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
@ -6,11 +6,11 @@ import androidx.work.Data
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.dao.TerminalDao
import com.deniscerri.ytdlnis.database.models.TerminalItem
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.deniscerri.ytdlnis.work.TerminalDownloadWorker
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.dao.TerminalDao
import com.deniscerri.ytdl.database.models.TerminalItem
import com.deniscerri.ytdl.util.NotificationUtil
import com.deniscerri.ytdl.work.TerminalDownloadWorker
import com.yausername.youtubedl_android.YoutubeDL
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

View file

@ -1,11 +1,11 @@
package com.deniscerri.ytdlnis.receiver
package com.deniscerri.ytdl.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.util.NotificationUtil
import com.yausername.youtubedl_android.YoutubeDL
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.receiver
package com.deniscerri.ytdl.receiver
import android.content.BroadcastReceiver
import android.content.Context

View file

@ -1,11 +1,11 @@
package com.deniscerri.ytdlnis.receiver
package com.deniscerri.ytdl.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.util.NotificationUtil
import com.yausername.youtubedl_android.YoutubeDL
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.receiver
package com.deniscerri.ytdl.receiver
import android.content.Context
import android.content.Intent
@ -12,11 +12,11 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.ui.BaseActivity
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.deniscerri.ytdlnis.util.ThemeUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.ui.BaseActivity
import com.deniscerri.ytdl.util.NotificationUtil
import com.deniscerri.ytdl.util.ThemeUtil
import com.google.android.material.bottomsheet.BottomSheetDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.receiver
package com.deniscerri.ytdl.receiver
import android.Manifest
import android.annotation.SuppressLint
@ -8,6 +8,8 @@ import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
@ -15,6 +17,8 @@ import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.util.Patterns
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import androidx.core.app.ActivityCompat
import androidx.core.view.ViewCompat
@ -26,13 +30,13 @@ import androidx.navigation.NavDestination
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.ui.BaseActivity
import com.deniscerri.ytdlnis.util.ThemeUtil
import com.deniscerri.ytdl.MainActivity
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.viewmodel.CookieViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.ui.BaseActivity
import com.deniscerri.ytdl.util.ThemeUtil
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -43,6 +47,7 @@ import kotlinx.coroutines.withContext
import kotlin.properties.Delegates
import kotlin.system.exitProcess
class ShareActivity : BaseActivity() {
lateinit var context: Context
@ -63,20 +68,51 @@ class ShareActivity : BaseActivity() {
v.setPadding(0, 0, 0, 0)
insets
}
window.run {
setBackgroundDrawable(ColorDrawable(0))
setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
if (Settings.canDrawOverlays(this)){
val params = WindowManager.LayoutParams(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
},
PixelFormat.TRANSLUCENT
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY)
} else {
setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
val wm = getSystemService(WINDOW_SERVICE) as WindowManager
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
val myView: View = inflater.inflate(R.layout.activity_share, null)
window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
wm.addView(myView, params)
// window.addFlags(
// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
// or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
// or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
// )
//
// val params = window.attributes
// params.alpha = 0f
// window.attributes = params
// setContentView(R.layout.activity_share)
}else{
window.run {
setBackgroundDrawable(ColorDrawable(0))
setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY)
} else {
setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
}
}
setContentView(R.layout.activity_share)
}
setContentView(R.layout.activity_share)
context = baseContext
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
@ -175,75 +211,6 @@ class ShareActivity : BaseActivity() {
}
}
}
private fun askPermissions() {
val permissions = arrayListOf<String>()
if (!checkFilePermission()) {
if (Build.VERSION.SDK_INT >= 33){
permissions.add(Manifest.permission.READ_MEDIA_AUDIO)
permissions.add(Manifest.permission.READ_MEDIA_VIDEO)
}else{
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}
if (!checkNotificationPermission()){
permissions.add(Manifest.permission.POST_NOTIFICATIONS)
}
if (permissions.isNotEmpty()){
ActivityCompat.requestPermissions(
this,
permissions.toTypedArray(),
1
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
for (i in permissions.indices) {
if (permissions.contains(Manifest.permission.POST_NOTIFICATIONS)) break
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
createPermissionRequestDialog()
}
}
}
private fun exit() {
finishAffinity()
exitProcess(0)
}
private fun checkFilePermission(): Boolean {
return (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED)
}
private fun checkNotificationPermission(): Boolean {
return (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED)
}
private fun createPermissionRequestDialog() {
val dialog = MaterialAlertDialogBuilder(this)
dialog.setTitle(getString(R.string.warning))
dialog.setMessage(getString(R.string.request_permission_desc))
dialog.setOnCancelListener { exit() }
dialog.setNegativeButton(getString(R.string.exit_app)) { _: DialogInterface?, _: Int -> exit() }
dialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null)
)
startActivity(intent)
exitProcess(0)
}
dialog.show()
}
override fun onConfigurationChanged(newConfig: Configuration) {
startActivity(Intent(this, MainActivity::class.java))
super.onConfigurationChanged(newConfig)

View file

@ -0,0 +1,85 @@
package com.deniscerri.ytdl.receiver
import android.content.Context
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import android.widget.Toast
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.ui.BaseActivity
import com.deniscerri.ytdl.util.NotificationUtil
import com.deniscerri.ytdl.util.ThemeUtil
import com.deniscerri.ytdl.util.UiUtil
class TransparentActivity : BaseActivity() {
lateinit var context: Context
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeUtil.updateTheme(this)
WindowCompat.setDecorFitsSystemWindows(window, false)
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { v, insets ->
v.setPadding(0, 0, 0, 0)
insets
}
if (Settings.canDrawOverlays(this)){
window.addFlags(
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
)
val params = window.attributes
params.alpha = 0f
window.attributes = params
setContentView(R.layout.activity_share)
}else{
window.run {
setBackgroundDrawable(ColorDrawable(0))
setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY)
} else {
setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
}
}
setContentView(R.layout.activity_share)
}
when(intent.getStringExtra("action")){
"NEW_TEMPLATE" -> newTemplate()
}
}
private fun newTemplate(){
val viewmodel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
UiUtil.showCommandTemplateCreationOrUpdatingSheet(
null, this, this, viewmodel,
newTemplate = {
Toast.makeText(this, R.string.ok,Toast.LENGTH_SHORT).show()
this.finishAffinity()
},
dismissed = {
this.finishAffinity()
}
)
}
}

View file

@ -0,0 +1,112 @@
package com.deniscerri.ytdl.ui
import android.Manifest
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.util.ThemeUtil
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.elevation.SurfaceColors
import kotlin.system.exitProcess
open class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
ThemeUtil.updateTheme(this)
window.navigationBarColor = SurfaceColors.SURFACE_2.getColor(this)
super.onCreate(savedInstanceState)
}
fun askPermissions() {
val permissions = arrayListOf<String>()
if (!checkFilePermission()) {
if (Build.VERSION.SDK_INT >= 33){
permissions.add(Manifest.permission.READ_MEDIA_AUDIO)
permissions.add(Manifest.permission.READ_MEDIA_VIDEO)
if (Build.VERSION.SDK_INT >= 34){
permissions.add(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
}
}else{
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE)
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (!checkNotificationPermission()){
permissions.add(Manifest.permission.POST_NOTIFICATIONS)
}
}
if (permissions.isNotEmpty()){
ActivityCompat.requestPermissions(
this,
permissions.toTypedArray(),
1
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
for (i in permissions.indices) {
if (permissions.contains(Manifest.permission.POST_NOTIFICATIONS)) continue
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
createPermissionRequestDialog()
}
}
}
private fun checkFilePermission(): Boolean {
return if(Build.VERSION.SDK_INT >= 33){
(ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO)
== PackageManager.PERMISSION_GRANTED) &&
(ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_VIDEO)
== PackageManager.PERMISSION_GRANTED)
}else{
(ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) &&
(ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED)
}
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun checkNotificationPermission(): Boolean {
return (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED)
}
private fun createPermissionRequestDialog() {
val dialog = MaterialAlertDialogBuilder(this)
dialog.setTitle(getString(R.string.warning))
dialog.setMessage(getString(R.string.request_permission_desc))
dialog.setOnCancelListener { exit() }
dialog.setNegativeButton(getString(R.string.exit_app)) { _: DialogInterface?, _: Int -> exit() }
dialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null)
)
startActivity(intent)
exitProcess(0)
}
dialog.show()
}
private fun exit() {
finishAffinity()
exitProcess(0)
}
}

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui
package com.deniscerri.ytdl.ui
import android.annotation.SuppressLint
import android.app.Activity
@ -32,22 +32,20 @@ import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.models.SearchSuggestionItem
import com.deniscerri.ytdlnis.database.models.SearchSuggestionType
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
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.ui.adapter.HomeAdapter
import com.deniscerri.ytdlnis.ui.adapter.SearchSuggestionsAdapter
import com.deniscerri.ytdlnis.util.Extensions.enableFastScroll
import com.deniscerri.ytdlnis.util.Extensions.toListString
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.ThemeUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.deniscerri.ytdl.MainActivity
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.database.models.SearchSuggestionItem
import com.deniscerri.ytdl.database.models.SearchSuggestionType
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.HistoryViewModel
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.ui.adapter.HomeAdapter
import com.deniscerri.ytdl.ui.adapter.SearchSuggestionsAdapter
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
import com.deniscerri.ytdl.util.InfoUtil
import com.deniscerri.ytdl.util.ThemeUtil
import com.deniscerri.ytdl.util.UiUtil
import com.facebook.shimmer.ShimmerFrameLayout
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.MaterialToolbar
@ -218,6 +216,12 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
inputQueries!!.addAll(argList)
}
if(arguments?.getBoolean("search") == true){
requireView().post {
searchBar?.performClick()
}
}
if (inputQueries != null) {
lifecycleScope.launch(Dispatchers.IO){
resultViewModel.deleteAll()

View file

@ -1,9 +1,8 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.animation.ValueAnimator
import android.app.Activity
import android.content.SharedPreferences
import android.graphics.Color
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
@ -17,18 +16,17 @@ import androidx.recyclerview.widget.AsyncDifferConfig
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.DownloadItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.util.Extensions.dp
import com.deniscerri.ytdlnis.util.Extensions.loadThumbnail
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.util.Extensions.dp
import com.deniscerri.ytdl.util.Extensions.loadThumbnail
import com.deniscerri.ytdl.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.squareup.picasso.Picasso
class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ActiveDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(

View file

@ -1,8 +1,7 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.app.Activity
import android.content.SharedPreferences
import android.graphics.Color
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
@ -16,16 +15,15 @@ import androidx.recyclerview.widget.AsyncDifferConfig
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.DownloadItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.util.Extensions.loadThumbnail
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.util.Extensions.loadThumbnail
import com.deniscerri.ytdl.util.Extensions.popup
import com.deniscerri.ytdl.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.squareup.picasso.Picasso
class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ActiveDownloadMinifiedAdapter.ViewHolder>(AsyncDifferConfig.Builder(
DIFF_CALLBACK

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.app.Activity
import android.content.SharedPreferences
@ -10,17 +10,16 @@ import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.AsyncDifferConfig
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.DownloadItem
import com.deniscerri.ytdlnis.util.Extensions.loadThumbnail
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.util.Extensions.loadThumbnail
import com.deniscerri.ytdl.util.Extensions.popup
import com.deniscerri.ytdl.util.FileUtil
import com.google.android.material.card.MaterialCardView
class AlreadyExistsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<Pair<DownloadItem, Long?>, AlreadyExistsAdapter.ViewHolder>(AsyncDifferConfig.Builder(

View file

@ -1,8 +1,7 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.app.Activity
import android.content.SharedPreferences
import android.graphics.Color
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
@ -16,14 +15,13 @@ import androidx.recyclerview.widget.AsyncDifferConfig
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.DownloadItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.util.Extensions.loadThumbnail
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.util.Extensions.loadThumbnail
import com.deniscerri.ytdl.util.Extensions.popup
import com.deniscerri.ytdl.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.squareup.picasso.Picasso
import java.util.Locale
class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ConfigureMultipleDownloadsAdapter.ViewHolder>(AsyncDifferConfig.Builder(

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.app.Activity
import android.view.LayoutInflater
@ -9,9 +9,9 @@ import androidx.recyclerview.widget.AsyncDifferConfig
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.CookieItem
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.CookieItem
import com.deniscerri.ytdl.util.Extensions.popup
import com.google.android.material.card.MaterialCardView
class CookieAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<CookieItem?, CookieAdapter.ViewHolder>(AsyncDifferConfig.Builder(

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.annotation.SuppressLint
import android.app.Activity
@ -11,11 +11,11 @@ import androidx.recyclerview.widget.AsyncDifferConfig
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 com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.LogItem
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.util.Extensions.popup
import com.deniscerri.ytdl.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import java.text.SimpleDateFormat

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.annotation.SuppressLint
import android.app.Activity
@ -14,15 +14,14 @@ import androidx.paging.PagingDataAdapter
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.util.Extensions.loadThumbnail
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.DownloadItemSimple
import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.util.Extensions.loadThumbnail
import com.deniscerri.ytdl.util.Extensions.popup
import com.deniscerri.ytdl.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.squareup.picasso.Picasso
class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : PagingDataAdapter<DownloadItemSimple, GenericDownloadAdapter.ViewHolder>(
DIFF_CALLBACK

View file

@ -1,9 +1,8 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.annotation.SuppressLint
import android.app.Activity
import android.content.SharedPreferences
import android.graphics.Color
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.os.Handler
@ -19,15 +18,14 @@ import androidx.recyclerview.widget.AsyncDifferConfig
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.HistoryItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.util.Extensions.loadThumbnail
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.HistoryItem
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.util.Extensions.loadThumbnail
import com.deniscerri.ytdl.util.Extensions.popup
import com.google.android.material.card.MaterialCardView
import com.google.android.material.color.MaterialColors
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.squareup.picasso.Picasso
import java.io.File
import java.text.SimpleDateFormat
import java.util.*

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.annotation.SuppressLint
import android.app.Activity
@ -15,11 +15,11 @@ import androidx.recyclerview.widget.AsyncDifferConfig
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.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.util.Extensions.loadThumbnail
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.util.Extensions.loadThumbnail
import com.deniscerri.ytdl.util.Extensions.popup
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.progressindicator.LinearProgressIndicator

View file

@ -1,24 +1,22 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.app.Activity
import android.os.Handler
import android.os.Looper
import android.text.format.DateFormat
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.recyclerview.widget.AsyncDifferConfig
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.ObserveSourcesItem
import com.deniscerri.ytdlnis.database.repository.ObserveSourcesRepository
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesItem
import com.deniscerri.ytdl.database.repository.ObserveSourcesRepository
import com.deniscerri.ytdl.util.Extensions.calculateNextTime
import com.deniscerri.ytdl.util.Extensions.popup
import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip
import com.google.android.material.floatingactionbutton.FloatingActionButton
@ -78,34 +76,10 @@ class ObserveSourcesAdapter(onItemClickListener: OnItemClickListener, activity:
//INFO
val info = card.findViewById<Chip>(R.id.info)
val nextTime = item.calculateNextTime()
val c = Calendar.getInstance()
val hourMin = Calendar.getInstance()
hourMin.timeInMillis = item.everyTime
c.set(Calendar.HOUR_OF_DAY, hourMin.get(Calendar.HOUR_OF_DAY))
c.set(Calendar.MINUTE, hourMin.get(Calendar.MINUTE))
c.timeInMillis = nextTime
when(item.everyCategory){
ObserveSourcesRepository.EveryCategory.DAY -> {
c.add(Calendar.DAY_OF_MONTH, item.everyNr)
}
ObserveSourcesRepository.EveryCategory.WEEK -> {
if(item.everyWeekDay.isEmpty()){
c.add(Calendar.DAY_OF_MONTH, 7 * item.everyNr)
}else{
val weekDayID = c.get(Calendar.DAY_OF_WEEK).toString()
val followingWeekDay = (item.everyWeekDay.firstOrNull { it.toInt() > weekDayID.toInt() } ?: item.everyWeekDay.minBy { it.toInt() }).toInt()
c.set(Calendar.DAY_OF_WEEK, followingWeekDay)
if (item.everyNr > 1){
c.add(Calendar.DAY_OF_MONTH, 7 * item.everyNr)
}
}
}
ObserveSourcesRepository.EveryCategory.MONTH -> {
c.add(Calendar.MONTH, item.everyNr)
c.set(Calendar.DAY_OF_MONTH, item.everyMonthDay)
}
}
val weekdays = DateFormatSymbols(Locale.getDefault()).shortWeekdays
val text = "${weekdays[c.get(Calendar.DAY_OF_WEEK)]}, ${SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(c.timeInMillis)}"
info.text = text
@ -169,12 +143,13 @@ class ObserveSourcesAdapter(onItemClickListener: OnItemClickListener, activity:
}
override fun areContentsTheSame(oldItem: ObserveSourcesItem, newItem: ObserveSourcesItem): Boolean {
return oldItem.id == newItem.id &&
oldItem.name == newItem.name &&
oldItem.downloadItemTemplate == newItem.downloadItemTemplate &&
oldItem.status == newItem.status &&
oldItem.retryMissingDownloads == newItem.retryMissingDownloads &&
oldItem.runCount == newItem.runCount
return oldItem.id == newItem.id
&& oldItem.name == newItem.name
&& oldItem.downloadItemTemplate == newItem.downloadItemTemplate
&& oldItem.status == newItem.status
&& oldItem.retryMissingDownloads == newItem.retryMissingDownloads
&& oldItem.runCount == newItem.runCount
&& oldItem.everyCategory == newItem.everyCategory
}
}
}

View file

@ -1,9 +1,8 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.annotation.SuppressLint
import android.app.Activity
import android.content.SharedPreferences
import android.graphics.Color
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
@ -12,18 +11,16 @@ import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.AsyncDifferConfig
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.ResultItem
import com.deniscerri.ytdlnis.util.Extensions.loadThumbnail
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.util.Extensions.loadThumbnail
import com.deniscerri.ytdl.util.Extensions.popup
import com.google.android.material.card.MaterialCardView
import com.squareup.picasso.Picasso
import java.util.*

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.app.Activity
import android.content.SharedPreferences
@ -13,9 +13,9 @@ import androidx.recyclerview.widget.AsyncDifferConfig
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.SearchSuggestionItem
import com.deniscerri.ytdlnis.database.models.SearchSuggestionType
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.SearchSuggestionItem
import com.deniscerri.ytdl.database.models.SearchSuggestionType
class SearchSuggestionsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<SearchSuggestionItem, SearchSuggestionsAdapter.ViewHolder>(AsyncDifferConfig.Builder(

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.annotation.SuppressLint
import android.app.Activity
@ -11,9 +11,9 @@ import androidx.recyclerview.widget.AsyncDifferConfig
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.CommandTemplate
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.CommandTemplate
import com.deniscerri.ytdl.util.Extensions.popup
import com.google.android.material.card.MaterialCardView
class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<CommandTemplate?, TemplatesAdapter.ViewHolder>(AsyncDifferConfig.Builder(

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.adapter
package com.deniscerri.ytdl.ui.adapter
import android.app.Activity
import android.content.SharedPreferences
@ -11,9 +11,9 @@ import androidx.recyclerview.widget.AsyncDifferConfig
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.TerminalItem
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.TerminalItem
import com.deniscerri.ytdl.util.Extensions.popup
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.progressindicator.LinearProgressIndicator

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.downloadcard
package com.deniscerri.ytdl.ui.downloadcard
import android.annotation.SuppressLint
import android.app.Dialog
@ -16,18 +16,17 @@ import android.widget.*
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdlnis.util.Extensions.enableTextHighlight
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdl.util.Extensions.enableTextHighlight
import com.deniscerri.ytdl.util.InfoUtil
import com.deniscerri.ytdl.util.UiUtil
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.*
class AddExtraCommandsDialog(private val item: DownloadItem?, private val callback: ExtraCommandsListener) : BottomSheetDialogFragment() {

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.downloadcard
package com.deniscerri.ytdl.ui.downloadcard
import android.view.View
import androidx.viewpager2.widget.ViewPager2

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.downloadcard
package com.deniscerri.ytdl.ui.downloadcard
import android.annotation.SuppressLint
import android.app.Dialog
@ -19,14 +19,14 @@ import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.util.UiUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.util.UiUtil
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.snackbar.Snackbar
@ -147,12 +147,16 @@ class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private
val snackTextView = snackbarView.findViewById<View>(com.google.android.material.R.id.snackbar_text) as TextView
snackTextView.maxLines = 9999999
s.setAction(R.string.new_template){
UiUtil.showCommandTemplateCreationOrUpdatingSheet(item = null, context = requireActivity(), lifeCycle = this@ConfigureDownloadBottomSheetDialog, commandTemplateViewModel = commandTemplateViewModel){
commandTemplateNr = 1
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.isClickable = true
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.alpha = 1f
tabLayout.selectTab(tabLayout.getTabAt(2))
}
UiUtil.showCommandTemplateCreationOrUpdatingSheet(
item = null, context = requireActivity(), lifeCycle = this@ConfigureDownloadBottomSheetDialog, commandTemplateViewModel = commandTemplateViewModel,
newTemplate = {
commandTemplateNr = 1
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.isClickable = true
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.alpha = 1f
tabLayout.selectTab(tabLayout.getTabAt(2))
},
dismissed = {}
)
}
s.show()
}else if (tab.position == 1 && isAudioOnly){

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.downloadcard
package com.deniscerri.ytdl.ui.downloadcard
import android.annotation.SuppressLint
import android.app.Dialog
@ -25,14 +25,14 @@ import androidx.media3.exoplayer.source.MediaSource
import androidx.media3.exoplayer.source.MergingMediaSource
import androidx.media3.ui.PlayerView
import androidx.preference.PreferenceManager
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.ChapterItem
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.util.Extensions.setTextAndRecalculateWidth
import com.deniscerri.ytdlnis.util.Extensions.toStringDuration
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.deniscerri.ytdlnis.util.VideoPlayerUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.ChapterItem
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.util.Extensions.setTextAndRecalculateWidth
import com.deniscerri.ytdl.util.Extensions.toStringDuration
import com.deniscerri.ytdl.util.InfoUtil
import com.deniscerri.ytdl.util.UiUtil
import com.deniscerri.ytdl.util.VideoPlayerUtil
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.downloadcard
package com.deniscerri.ytdl.ui.downloadcard
import android.annotation.SuppressLint
import android.app.Activity
@ -24,16 +24,16 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.Format
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.InfoUtil
import com.deniscerri.ytdl.util.UiUtil
import com.google.android.material.card.MaterialCardView
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputLayout
@ -210,8 +210,10 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
UiUtil.populateFormatCard(requireContext(), formatCard, chosenFormat, null)
val listener = object : OnFormatClickListener {
override fun onFormatClick(item: List<FormatTuple>) {
downloadItem.format = item.first().format
UiUtil.populateFormatCard(requireContext(), formatCard, item.first().format, null)
item.first().format?.apply {
downloadItem.format = this
UiUtil.populateFormatCard(requireContext(), formatCard, this, null)
}
}
override fun onFormatsUpdated(allFormats: List<List<Format>>) {

View file

@ -1,8 +1,7 @@
package com.deniscerri.ytdlnis.ui.downloadcard
package com.deniscerri.ytdl.ui.downloadcard
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.content.SharedPreferences
import android.content.res.Configuration
@ -20,11 +19,9 @@ import android.widget.TextView
import android.widget.Toast
import androidx.core.content.edit
import androidx.core.os.bundleOf
import androidx.core.view.get
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.commitNow
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
@ -32,18 +29,18 @@ import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.receiver.ShareActivity
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdl.database.viewmodel.HistoryViewModel
import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
import com.deniscerri.ytdl.receiver.ShareActivity
import com.deniscerri.ytdl.util.InfoUtil
import com.deniscerri.ytdl.util.UiUtil
import com.facebook.shimmer.ShimmerFrameLayout
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
@ -155,9 +152,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
shimmerLoading.setOnClickListener {
lifecycleScope.launch {
withContext(Dispatchers.IO){
resultViewModel.cancelUpdateItemData()
}
resultViewModel.cancelUpdateItemData()
(updateItem.parent as LinearLayout).visibility = View.VISIBLE
}
}
@ -252,12 +247,18 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
val snackTextView = snackbarView.findViewById<View>(com.google.android.material.R.id.snackbar_text) as TextView
snackTextView.maxLines = 9999999
s.setAction(R.string.new_template){
UiUtil.showCommandTemplateCreationOrUpdatingSheet(item = null, context = requireActivity(), lifeCycle = this@DownloadBottomSheetDialog, commandTemplateViewModel = commandTemplateViewModel){
commandTemplateNr = 1
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.isClickable = true
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.alpha = 1f
tabLayout.selectTab(tabLayout.getTabAt(2))
}
UiUtil.showCommandTemplateCreationOrUpdatingSheet(
item = null, context = requireActivity(), lifeCycle = this@DownloadBottomSheetDialog, commandTemplateViewModel = commandTemplateViewModel,
newTemplate = {
commandTemplateNr = 1
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.isClickable = true
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.alpha = 1f
tabLayout.selectTab(tabLayout.getTabAt(2))
},
dismissed = {
}
)
}
s.show()
}else if (tab.position == 1 && isAudioOnly){
@ -305,10 +306,8 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
scheduleBtn.setOnClickListener{
UiUtil.showDatePicker(fragmentManager) {
lifecycleScope.launch {
withContext(Dispatchers.IO){
resultViewModel.cancelUpdateItemData()
resultViewModel.cancelUpdateFormatsItemData()
}
resultViewModel.cancelUpdateItemData()
resultViewModel.cancelUpdateFormatsItemData()
}
scheduleBtn.isEnabled = false
@ -344,10 +343,8 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
}
download!!.setOnClickListener {
lifecycleScope.launch {
withContext(Dispatchers.IO){
resultViewModel.cancelUpdateItemData()
resultViewModel.cancelUpdateFormatsItemData()
}
resultViewModel.cancelUpdateItemData()
resultViewModel.cancelUpdateFormatsItemData()
scheduleBtn.isEnabled = false
download.isEnabled = false
val item: DownloadItem = getDownloadItem()
@ -481,7 +478,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
isVisible = true
isClickable = true
setOnClickListener {
lifecycleScope.launch(Dispatchers.IO) {
lifecycleScope.launch {
resultViewModel.cancelUpdateFormatsItemData()
}
}
@ -493,7 +490,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
isVisible = true
isClickable = true
setOnClickListener {
lifecycleScope.launch(Dispatchers.IO) {
lifecycleScope.launch {
resultViewModel.cancelUpdateFormatsItemData()
}
}
@ -687,7 +684,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
}
if (resultViewModel.updatingData.value) return
CoroutineScope(SupervisorJob()).launch(Dispatchers.IO) {
lifecycleScope.launch(Dispatchers.IO) {
resultViewModel.updateItemData(result)
}
}

View file

@ -1,4 +1,4 @@
package com.deniscerri.ytdlnis.ui.downloadcard
package com.deniscerri.ytdl.ui.downloadcard
import android.annotation.SuppressLint
import android.app.Activity
@ -23,17 +23,17 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.CommandTemplate
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.util.Extensions.enableTextHighlight
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.deniscerri.ytdlnis.util.UiUtil.populateCommandCard
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.models.CommandTemplate
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.Format
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.util.Extensions.enableTextHighlight
import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.UiUtil
import com.deniscerri.ytdl.util.UiUtil.populateCommandCard
import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip
import com.google.android.material.textfield.TextInputLayout
@ -218,24 +218,28 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
if (downloadItem.url.isEmpty()) 0 else 1,
shortcutCount,
newTemplateClicked = {
UiUtil.showCommandTemplateCreationOrUpdatingSheet(null, requireActivity(), viewLifecycleOwner, commandTemplateViewModel) {
templates.add(it)
chosenCommandView.editText!!.setText(it.content)
downloadItem.format = Format(
it.title,
"",
"",
"",
"",
0,
it.content
)
preferences.edit().putString("lastCommandTemplateUsed", it.content).apply()
commandTemplateCard.visibility = View.VISIBLE
view.findViewById<TextView>(R.id.command_txt).visibility = View.VISIBLE
view.findViewById<Chip>(R.id.editSelected).isEnabled = true
populateCommandCard(commandTemplateCard, it)
}
UiUtil.showCommandTemplateCreationOrUpdatingSheet(
null, requireActivity(), viewLifecycleOwner, commandTemplateViewModel,
newTemplate = {
templates.add(it)
chosenCommandView.editText!!.setText(it.content)
downloadItem.format = Format(
it.title,
"",
"",
"",
"",
0,
it.content
)
preferences.edit().putString("lastCommandTemplateUsed", it.content).apply()
commandTemplateCard.visibility = View.VISIBLE
view.findViewById<TextView>(R.id.command_txt).visibility = View.VISIBLE
view.findViewById<Chip>(R.id.editSelected).isEnabled = true
populateCommandCard(commandTemplateCard, it)
},
dismissed = {}
)
},
editSelectedClicked =
{
@ -247,21 +251,25 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
chosenCommandView.editText!!.text.toString(),
useAsExtraCommand = false, useAsExtraCommandAudio = false, useAsExtraCommandVideo = false
)
UiUtil.showCommandTemplateCreationOrUpdatingSheet(current, requireActivity(), viewLifecycleOwner, commandTemplateViewModel) {
templates.add(it)
chosenCommandView.editText!!.setText(it.content)
populateCommandCard(commandTemplateCard, it)
downloadItem.format = Format(
it.title,
"",
"",
"",
"",
0,
it.content
)
preferences.edit().putString("lastCommandTemplateUsed", it.content).apply()
}
UiUtil.showCommandTemplateCreationOrUpdatingSheet(
current, requireActivity(), viewLifecycleOwner, commandTemplateViewModel,
newTemplate = {
templates.add(it)
chosenCommandView.editText!!.setText(it.content)
populateCommandCard(commandTemplateCard, it)
downloadItem.format = Format(
it.title,
"",
"",
"",
"",
0,
it.content
)
preferences.edit().putString("lastCommandTemplateUsed", it.content).apply()
},
dismissed = {}
)
},
shortcutClicked = {
UiUtil.showShortcuts(requireActivity(), commandTemplateViewModel,

Some files were not shown because too many files have changed in this diff Show more