From 177ba4881c7bd49db8ee6a3fcb1f9274c1223528 Mon Sep 17 00:00:00 2001
From: zaednasr <75589932+zaednasr@users.noreply.github.com>
Date: Sun, 25 Feb 2024 19:23:38 +0100
Subject: [PATCH] 1.7.3
---
app/build.gradle | 2 +-
.../15.json | 724 ++++++++++++++++++
app/src/main/AndroidManifest.xml | 1 -
.../com/deniscerri/ytdlnis/MainActivity.kt | 3 -
.../deniscerri/ytdlnis/database/DBManager.kt | 35 +-
.../database/dao/CommandTemplateDao.kt | 6 +-
.../ytdlnis/database/dao/CookieDao.kt | 8 +-
.../ytdlnis/database/dao/DownloadDao.kt | 46 +-
.../ytdlnis/database/dao/HistoryDao.kt | 6 +-
.../deniscerri/ytdlnis/database/dao/LogDao.kt | 7 +-
.../ytdlnis/database/dao/ObserveSourcesDao.kt | 7 +-
.../ytdlnis/database/dao/ResultDao.kt | 12 +-
.../ytdlnis/database/dao/SearchHistoryDao.kt | 5 +-
.../ytdlnis/database/dao/TerminalDao.kt | 17 +-
.../database/models/ObserveSourcesItem.kt | 4 +-
.../database/models/SearchSuggestionItem.kt | 5 -
.../database/models/VideoPreferences.kt | 3 +-
.../database/repository/CookieRepository.kt | 2 +-
.../database/repository/DownloadRepository.kt | 76 +-
.../database/repository/HistoryRepository.kt | 2 +-
.../database/repository/LogRepository.kt | 14 +-
.../repository/ObserveSourcesRepository.kt | 17 +
.../database/repository/ResultRepository.kt | 116 ++-
.../database/viewmodel/CookieViewModel.kt | 64 +-
.../database/viewmodel/DownloadViewModel.kt | 98 +--
.../database/viewmodel/HistoryViewModel.kt | 2 +-
.../viewmodel/ObserveSourcesViewModel.kt | 10 +-
.../database/viewmodel/ResultViewModel.kt | 122 +--
.../CancelDownloadNotificationReceiver.kt | 1 -
.../ytdlnis/receiver/ObserveAlarmReceiver.kt | 1 -
.../PauseDownloadNotificationReceiver.kt | 10 +-
.../AlarmStartReceiver.kt | 1 -
.../com/deniscerri/ytdlnis/ui/HomeFragment.kt | 56 +-
.../ui/adapter/ActiveDownloadAdapter.kt | 9 +-
.../adapter/ActiveDownloadMinifiedAdapter.kt | 3 +-
.../ui/adapter/AlreadyExistsAdapter.kt | 7 -
.../ConfigureMultipleDownloadsAdapter.kt | 3 +
.../ytdlnis/ui/adapter/DownloadLogsAdapter.kt | 15 +-
.../ui/adapter/GenericDownloadAdapter.kt | 16 +-
.../ytdlnis/ui/adapter/HistoryAdapter.kt | 2 +-
.../ytdlnis/ui/adapter/HomeAdapter.kt | 4 -
.../ui/adapter/ObserveSourcesAdapter.kt | 4 -
.../ui/adapter/SearchSuggestionsAdapter.kt | 1 -
.../ytdlnis/ui/adapter/TemplatesAdapter.kt | 2 -
.../ui/downloadcard/AddExtraCommandsDialog.kt | 2 +-
.../ConfigureDownloadBottomSheetDialog.kt | 5 +-
.../downloadcard/CutVideoBottomSheetDialog.kt | 4 +-
.../ui/downloadcard/DownloadAudioFragment.kt | 38 +-
.../downloadcard/DownloadBottomSheetDialog.kt | 85 +-
.../downloadcard/DownloadCommandFragment.kt | 4 +-
.../DownloadMultipleBottomSheetDialog.kt | 19 +-
.../ui/downloadcard/DownloadVideoFragment.kt | 24 +-
.../FormatSelectionBottomSheetDialog.kt | 4 -
.../ObserveSourcesBottomSheetDialog.kt | 19 +-
.../downloadcard/ResultCardDetailsDialog.kt | 15 +-
.../downloadcard/SelectPlaylistItemsDialog.kt | 5 +-
.../ui/downloads/ActiveDownloadsFragment.kt | 4 +-
.../downloads/CancelledDownloadsFragment.kt | 5 +-
.../downloads/DownloadListFragmentAdapter.kt | 4 -
.../ui/downloads/DownloadQueueMainFragment.kt | 57 +-
.../ui/downloads/ErroredDownloadsFragment.kt | 5 +-
.../ytdlnis/ui/downloads/HistoryFragment.kt | 10 +-
.../ui/downloads/QueuedDownloadsFragment.kt | 33 +-
.../ui/downloads/SavedDownloadsFragment.kt | 5 +-
.../ui/more/CommandTemplatesFragment.kt | 8 +-
.../ytdlnis/ui/more/CookiesFragment.kt | 16 +-
.../ytdlnis/ui/more/ObserveSourcesFragment.kt | 77 +-
.../ytdlnis/ui/more/WebViewActivity.kt | 85 +-
.../more/downloadLogs/DownloadLogFragment.kt | 9 +-
.../downloadLogs/DownloadLogListFragment.kt | 2 +-
.../ui/more/settings/BaseSettingsFragment.kt | 1 -
.../more/settings/FolderSettingsFragment.kt | 1 -
.../ui/more/settings/MainSettingsFragment.kt | 351 +++++----
.../settings/ProcessingSettingsFragment.kt | 1 -
.../more/settings/UpdateSettingsFragment.kt | 87 ++-
.../terminal/TerminalDownloadsListFragment.kt | 2 +-
.../ui/more/terminal/TerminalFragment.kt | 7 +-
.../deniscerri/ytdlnis/util/DownloadUtil.kt | 92 ---
.../com/deniscerri/ytdlnis/util/Extensions.kt | 26 +-
.../com/deniscerri/ytdlnis/util/InfoUtil.kt | 205 ++---
.../ytdlnis/util/NotificationUtil.kt | 5 -
.../com/deniscerri/ytdlnis/util/ThemeUtil.kt | 2 -
.../com/deniscerri/ytdlnis/util/UiUtil.kt | 85 +-
.../com/deniscerri/ytdlnis/util/UpdateUtil.kt | 7 +-
.../deniscerri/ytdlnis/work/DownloadWorker.kt | 62 +-
.../ytdlnis/work/ObserveSourceWorker.kt | 175 ++---
.../ytdlnis/work/TerminalDownloadWorker.kt | 3 +-
.../ytdlnis/work/UpdateYTDLWorker.kt | 2 -
.../drawable/baseline_network_locked_24.xml | 13 +-
.../main/res/drawable/baseline_numbers_24.xml | 5 +
.../res/drawable/ic_baseline_file_open_24.xml | 14 +-
.../res/drawable/ic_concurrent_downloads.xml | 14 +-
app/src/main/res/drawable/ic_dns.xml | 10 +
app/src/main/res/drawable/ic_end.xml | 10 +
app/src/main/res/drawable/ic_experiment.xml | 10 +
app/src/main/res/drawable/ic_incognito.xml | 13 +-
app/src/main/res/drawable/ic_ipv4.xml | 10 +
app/src/main/res/drawable/ic_license.xml | 10 +
app/src/main/res/drawable/ic_limitrate.xml | 10 +
.../main/res/drawable/ic_music_formatcard.xml | 5 +
app/src/main/res/drawable/ic_open_file.xml | 5 +
app/src/main/res/drawable/ic_retries.xml | 11 +
app/src/main/res/drawable/ic_start.xml | 10 +
app/src/main/res/drawable/ic_update_app.xml | 13 +-
.../main/res/drawable/metered_networks.xml | 13 +-
.../main/res/layout/active_download_card.xml | 17 +-
.../layout/active_download_card_minified.xml | 5 +-
app/src/main/res/layout/activity_settings.xml | 1 +
app/src/main/res/layout/activity_terminal.xml | 1 +
app/src/main/res/layout/adjust_video.xml | 129 ++--
.../main/res/layout/already_exists_item.xml | 2 +
.../audio_download_preferences_dialog.xml | 22 +
app/src/main/res/layout/changelog_item.xml | 4 +-
.../main/res/layout/command_template_item.xml | 1 -
app/src/main/res/layout/cut_video_sheet.xml | 5 +-
.../main/res/layout/download_bottom_sheet.xml | 4 +-
.../layout/download_multiple_bottom_sheet.xml | 45 +-
.../layout/extra_commands_bottom_sheet.xml | 3 +
app/src/main/res/layout/format_item.xml | 2 +-
.../res/layout/format_select_bottom_sheet.xml | 24 +-
app/src/main/res/layout/fragment_active.xml | 3 +-
.../res/layout/fragment_command_templates.xml | 1 +
app/src/main/res/layout/fragment_cookies.xml | 1 +
.../main/res/layout/fragment_download_log.xml | 30 +-
.../res/layout/fragment_download_log_list.xml | 1 +
.../fragment_download_queue_main_screen.xml | 2 +-
.../res/layout/fragment_observe_sources.xml | 1 +
app/src/main/res/layout/fragment_terminal.xml | 1 +
app/src/main/res/layout/history_card.xml | 19 +-
.../main/res/layout/history_card_multiple.xml | 19 +-
.../history_item_details_bottom_sheet.xml | 5 +-
.../layout/observe_sources_bottom_sheet.xml | 113 +--
app/src/main/res/layout/playlist_item.xml | 6 -
app/src/main/res/layout/result_card.xml | 20 +-
.../main/res/layout/result_card_details.xml | 5 +
.../res/layout/search_suggestion_item.xml | 1 +
app/src/main/res/layout/webview_activity.xml | 1 +
app/src/main/res/menu/log_detail_menu.xml | 6 +-
app/src/main/res/menu/terminal_top_menu.xml | 6 +-
app/src/main/res/values/arrays.xml | 12 +
app/src/main/res/values/strings.xml | 12 +-
.../main/res/xml/downloading_preferences.xml | 10 +-
app/src/main/res/xml/general_preferences.xml | 14 +
.../main/res/xml/processing_preferences.xml | 9 +
app/src/main/res/xml/root_preferences.xml | 2 +-
app/src/main/res/xml/updating_preferences.xml | 15 +-
.../android/en-US/changelogs/10730.txt | 23 +
147 files changed, 2645 insertions(+), 1341 deletions(-)
create mode 100644 app/schemas/com.deniscerri.ytdlnis.database.DBManager/15.json
delete mode 100644 app/src/main/java/com/deniscerri/ytdlnis/util/DownloadUtil.kt
create mode 100644 app/src/main/res/drawable/baseline_numbers_24.xml
create mode 100644 app/src/main/res/drawable/ic_dns.xml
create mode 100644 app/src/main/res/drawable/ic_end.xml
create mode 100644 app/src/main/res/drawable/ic_experiment.xml
create mode 100644 app/src/main/res/drawable/ic_ipv4.xml
create mode 100644 app/src/main/res/drawable/ic_license.xml
create mode 100644 app/src/main/res/drawable/ic_limitrate.xml
create mode 100644 app/src/main/res/drawable/ic_music_formatcard.xml
create mode 100644 app/src/main/res/drawable/ic_open_file.xml
create mode 100644 app/src/main/res/drawable/ic_retries.xml
create mode 100644 app/src/main/res/drawable/ic_start.xml
create mode 100644 app/src/main/res/layout/audio_download_preferences_dialog.xml
create mode 100644 fastlane/metadata/android/en-US/changelogs/10730.txt
diff --git a/app/build.gradle b/app/build.gradle
index 5304dbf3..78502114 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -10,7 +10,7 @@ plugins {
def properties = new Properties()
def versionMajor = 1
def versionMinor = 7
-def versionPatch = 2
+def versionPatch = 3
def versionBuild = 0 // bump for dogfood builds, public betas, etc.
def versionExt = ""
diff --git a/app/schemas/com.deniscerri.ytdlnis.database.DBManager/15.json b/app/schemas/com.deniscerri.ytdlnis.database.DBManager/15.json
new file mode 100644
index 00000000..fde9fc50
--- /dev/null
+++ b/app/schemas/com.deniscerri.ytdlnis.database.DBManager/15.json
@@ -0,0 +1,724 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 15,
+ "identityHash": "3f4252e3a5d5fbf3d4706a4d999055f1",
+ "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": "observeSources",
+ "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, `status` TEXT NOT NULL, `everyNr` INTEGER NOT NULL, `everyCategory` TEXT NOT NULL, `everyWeekDay` TEXT NOT NULL, `everyMonthDay` INTEGER NOT NULL, `everyTime` INTEGER NOT NULL, `startsTime` INTEGER NOT NULL, `startsMonth` TEXT 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": "status",
+ "columnName": "status",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "everyNr",
+ "columnName": "everyNr",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "everyCategory",
+ "columnName": "everyCategory",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "everyWeekDay",
+ "columnName": "everyWeekDay",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "everyMonthDay",
+ "columnName": "everyMonthDay",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "everyTime",
+ "columnName": "everyTime",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "startsTime",
+ "columnName": "startsTime",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "startsMonth",
+ "columnName": "startsMonth",
+ "affinity": "TEXT",
+ "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, '3f4252e3a5d5fbf3d4706a4d999055f1')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index dd009739..1257f698 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,7 +11,6 @@
tools:ignore="ScopedStorage" />
-
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt
index c13ba5a4..89d3a283 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt
@@ -13,16 +13,13 @@ import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.util.Log
-import android.view.Gravity
import android.view.View
import android.view.WindowInsets
import android.widget.CheckBox
-import android.widget.FrameLayout
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.constraintlayout.widget.ConstraintLayout
-import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.app.ActivityCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.forEach
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/DBManager.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/DBManager.kt
index 8c51f85e..749b28d3 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/DBManager.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/DBManager.kt
@@ -1,14 +1,30 @@
package com.deniscerri.ytdlnis.database
import android.content.Context
-import androidx.room.*
-import androidx.room.migration.AutoMigrationSpec
-import androidx.room.migration.Migration
-import androidx.sqlite.db.SupportSQLiteDatabase
-import androidx.work.impl.Migration_11_12
-import androidx.work.impl.Migration_12_13
-import com.deniscerri.ytdlnis.database.dao.*
-import com.deniscerri.ytdlnis.database.models.*
+import androidx.room.AutoMigration
+import androidx.room.Database
+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
@TypeConverters(Converters::class)
@Database(
@@ -24,7 +40,7 @@ import com.deniscerri.ytdlnis.database.models.*
TerminalItem::class,
ObserveSourcesItem::class
],
- version = 14,
+ version = 15,
autoMigrations = [
AutoMigration (from = 1, to = 2),
AutoMigration (from = 2, to = 3),
@@ -39,6 +55,7 @@ import com.deniscerri.ytdlnis.database.models.*
AutoMigration (from = 11, to = 12),
AutoMigration (from = 12, to = 13),
// AutoMigration (from = 13, to = 14) MANUALLY HANDLED
+ AutoMigration (from = 14, to = 15),
]
)
abstract class DBManager : RoomDatabase(){
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CommandTemplateDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CommandTemplateDao.kt
index 94888975..ed82344d 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CommandTemplateDao.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CommandTemplateDao.kt
@@ -1,6 +1,10 @@
package com.deniscerri.ytdlnis.database.dao
-import androidx.room.*
+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 kotlinx.coroutines.flow.Flow
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CookieDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CookieDao.kt
index d5ad77f0..f4426698 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CookieDao.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CookieDao.kt
@@ -1,6 +1,10 @@
package com.deniscerri.ytdlnis.database.dao
-import androidx.room.*
+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 kotlinx.coroutines.flow.Flow
@@ -10,7 +14,7 @@ interface CookieDao {
fun getAllCookies() : List
@Query("SELECT * FROM cookies WHERE url = :url LIMIT 1")
- fun getByURL(url: String) : CookieItem
+ fun getByURL(url: String) : CookieItem?
@Query("SELECT * FROM cookies ORDER BY id DESC")
fun getAllCookiesFlow() : Flow>
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt
index 754e7663..dd6fe092 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt
@@ -1,7 +1,14 @@
package com.deniscerri.ytdlnis.database.dao
import androidx.paging.PagingSource
-import androidx.room.*
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+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
@@ -19,14 +26,14 @@ interface DownloadDao {
@Query("SELECT * FROM downloads WHERE status = 'Processing'")
fun getProcessingDownloads() : Flow>
- @Query("SELECT COUNT(*) FROM downloads WHERE status in ('Active', 'ActivePaused', 'PausedReQueued')")
- fun getActiveDownloadsCountFlow() : Flow
+ @Query("SELECT COUNT(*) FROM downloads WHERE status in (:statuses)")
+ fun getDownloadsCountFlow(statuses: List) : Flow
@Query("SELECT COUNT(*) FROM downloads WHERE status in (:status)")
fun getDownloadsCountByStatusFlow(status : List) : Flow
- @Query("SELECT COUNT(*) FROM downloads WHERE status in (:status)")
- fun getDownloadsCountByStatus(status : List) : Int
+ @Query("SELECT COUNT(*) FROM downloads WHERE status in (:statuses)")
+ fun getDownloadsCountByStatus(statuses : List) : Int
@Query("""
@@ -79,6 +86,9 @@ interface DownloadDao {
@Query("SELECT * FROM downloads WHERE status in('Queued','QueuedPaused') ORDER BY downloadStartTime, id")
fun getQueuedDownloadsList() : List
+ @Query("SELECT id FROM downloads WHERE status in('Queued','QueuedPaused') ORDER BY downloadStartTime, id")
+ fun getQueuedDownloadsListIDs() : List
+
@RewriteQueriesToDropUnusedColumns
@Query("SELECT * FROM downloads WHERE status='Cancelled' ORDER BY id DESC")
fun getCancelledDownloads() : PagingSource
@@ -207,28 +217,30 @@ interface DownloadDao {
fun getURLsByStatus(status: List) : List
@Query("UPDATE downloads SET downloadStartTime=0 where id in (:list)")
- fun resetScheduleTimeForItems(list: List)
+ suspend fun resetScheduleTimeForItems(list: List)
@Query("Update downloads SET status='Queued', downloadStartTime = 0 WHERE id in (:list)")
- fun reQueueDownloadItems(list: List)
+ suspend fun reQueueDownloadItems(list: List)
@Query("Update downloads SET status='Saved' WHERE status='Processing'")
fun updateProcessingtoSavedStatus()
@Transaction
- fun putAtTopOfTheQueue(id: Long){
- val downloads = getQueuedDownloadsList()
- val newID = downloads.first().id
+ suspend fun putAtTopOfTheQueue(existingIDs: List){
+ val downloads = getQueuedDownloadsListIDs()
+ val newIDs = downloads.sortedBy { it }.take(existingIDs.size)
- updateDownloadID(id, -id)
- resetScheduleTimeForItems(listOf(-id))
-
- downloads.reversed().dropWhile { it.id == id }.forEach {
- updateDownloadID(it.id, it.id + 1)
+ resetScheduleTimeForItems(existingIDs)
+ existingIDs.forEach { updateDownloadID(it, -it) }
+ downloads.filter { !existingIDs.contains(it) }.reversed().forEach {
+ updateDownloadID(it, it + existingIDs.size)
+ }
+
+ existingIDs.forEachIndexed { idx, it ->
+ updateDownloadID(-it, newIDs[idx])
}
- updateDownloadID(-id, newID)
}
@Query("Update downloads set id=:newId where id=:id")
- fun updateDownloadID(id: Long, newId: Long)
+ suspend fun updateDownloadID(id: Long, newId: Long)
}
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/HistoryDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/HistoryDao.kt
index beb39c4b..7acbc849 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/HistoryDao.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/HistoryDao.kt
@@ -1,6 +1,10 @@
package com.deniscerri.ytdlnis.database.dao
-import androidx.room.*
+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 kotlinx.coroutines.flow.Flow
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/LogDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/LogDao.kt
index be21f5e6..9c8544dc 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/LogDao.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/LogDao.kt
@@ -1,6 +1,11 @@
package com.deniscerri.ytdlnis.database.dao
-import androidx.room.*
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import androidx.room.Transaction
+import androidx.room.Update
import com.deniscerri.ytdlnis.database.models.LogItem
import kotlinx.coroutines.flow.Flow
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/ObserveSourcesDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/ObserveSourcesDao.kt
index 2ee57b32..767bf711 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/ObserveSourcesDao.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/ObserveSourcesDao.kt
@@ -1,7 +1,10 @@
package com.deniscerri.ytdlnis.database.dao
-import androidx.room.*
-import com.deniscerri.ytdlnis.database.models.CookieItem
+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 kotlinx.coroutines.flow.Flow
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/ResultDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/ResultDao.kt
index d28d30ff..7726d340 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/ResultDao.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/ResultDao.kt
@@ -1,6 +1,11 @@
package com.deniscerri.ytdlnis.database.dao
-import androidx.room.*
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import androidx.room.Transaction
+import androidx.room.Update
import com.deniscerri.ytdlnis.database.models.ResultItem
import kotlinx.coroutines.flow.Flow
@@ -27,6 +32,11 @@ interface ResultDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertMultiple(items: List) : List
+ @Transaction
+ suspend fun insertMultipleNoDuplicates(items: List) : List {
+ return insertMultiple(items.filter { getResultByURL(it.url) == null })
+ }
+
@Update(onConflict = OnConflictStrategy.REPLACE)
suspend fun update(item: ResultItem)
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/SearchHistoryDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/SearchHistoryDao.kt
index 94bd2056..fcaebc8c 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/SearchHistoryDao.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/SearchHistoryDao.kt
@@ -1,6 +1,9 @@
package com.deniscerri.ytdlnis.database.dao
-import androidx.room.*
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
import com.deniscerri.ytdlnis.database.models.SearchHistoryItem
@Dao
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/TerminalDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/TerminalDao.kt
index 707e87fa..f1592553 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/TerminalDao.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/TerminalDao.kt
@@ -1,7 +1,11 @@
package com.deniscerri.ytdlnis.database.dao
-import androidx.room.*
+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 kotlinx.coroutines.flow.Flow
@Dao
@@ -28,16 +32,7 @@ interface TerminalDao {
fun updateLog(line: String, id: Long){
val t = getTerminalById(id) ?: return
val log = t.log ?: ""
- val lines = log.split("\n")
- //clean dublicate progress + add newline
- var newLine = line
- if (newLine.contains("[download")){
- newLine = "[download]" + line.split("[download]").last()
- }
-
- val l = lines.dropLastWhile { it.contains("[download") }.joinToString("\n") + "\n${newLine}"
-
- updateTerminalLog(l, id)
+ updateTerminalLog(log.appendLineToLog(line), id)
}
@Insert
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/models/ObserveSourcesItem.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/models/ObserveSourcesItem.kt
index 4241b58c..8533262f 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/models/ObserveSourcesItem.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/models/ObserveSourcesItem.kt
@@ -7,8 +7,6 @@ import androidx.room.PrimaryKey
import com.deniscerri.ytdlnis.database.repository.ObserveSourcesRepository
import kotlinx.parcelize.Parcelize
import java.time.Month
-import java.util.Calendar
-import java.util.Date
@Entity(tableName = "observeSources")
@Parcelize
@@ -32,6 +30,8 @@ data class ObserveSourcesItem(
var endsAfterCount: Int,
@ColumnInfo(defaultValue = "0")
var runCount: Int,
+ @ColumnInfo(defaultValue = "0")
+ var getOnlyNewUploads: Boolean,
var retryMissingDownloads: Boolean,
var alreadyProcessedLinks : MutableList
) : Parcelable
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/models/SearchSuggestionItem.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/models/SearchSuggestionItem.kt
index 0f1bf51c..acc171ca 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/models/SearchSuggestionItem.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/models/SearchSuggestionItem.kt
@@ -1,10 +1,5 @@
package com.deniscerri.ytdlnis.database.models
-import androidx.room.ColumnInfo
-import androidx.room.Entity
-import androidx.room.PrimaryKey
-import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
-
data class SearchSuggestionItem(
var text: String,
val type: SearchSuggestionType,
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/models/VideoPreferences.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/models/VideoPreferences.kt
index 9fad348a..673c472f 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/models/VideoPreferences.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/models/VideoPreferences.kt
@@ -13,5 +13,6 @@ data class VideoPreferences (
var writeAutoSubs: Boolean = false,
var subsLanguages: String = "en.*,.*-orig",
var audioFormatIDs : ArrayList = arrayListOf(),
- var removeAudio: Boolean = false
+ var removeAudio: Boolean = false,
+ var alsoDownloadAsAudio: Boolean = false
) : Parcelable
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/CookieRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/CookieRepository.kt
index b42699a9..e6cb4335 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/CookieRepository.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/CookieRepository.kt
@@ -11,7 +11,7 @@ class CookieRepository(private val cookieDao: CookieDao) {
return cookieDao.getAllCookies()
}
- fun getByURL(url: String) : CookieItem {
+ fun getByURL(url: String) : CookieItem? {
return cookieDao.getByURL(url)
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt
index 2336f2c0..e5f8d480 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt
@@ -1,15 +1,32 @@
package com.deniscerri.ytdlnis.database.repository
+import android.annotation.SuppressLint
+import android.content.Context
+import android.net.ConnectivityManager
+import android.os.Looper
+import android.widget.Toast
import androidx.paging.Pager
import androidx.paging.PagingConfig
+import androidx.preference.PreferenceManager
+import androidx.work.Constraints
+import androidx.work.Data
+import androidx.work.ExistingWorkPolicy
+import androidx.work.NetworkType
+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.FileUtil
+import com.deniscerri.ytdlnis.work.DownloadWorker
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import java.io.File
+import java.util.concurrent.TimeUnit
class DownloadRepository(private val downloadDao: DownloadDao) {
@@ -36,12 +53,20 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
pagingSourceFactory = {downloadDao.getSavedDownloads()}
)
- val activeDownloadsCount : Flow = downloadDao.getActiveDownloadsCountFlow()
+ val activeDownloadsCount : Flow = downloadDao.getDownloadsCountByStatusFlow(listOf(Status.Active, Status.ActivePaused, Status.PausedReQueued).toListString())
+ val queuedDownloadsCount : Flow = downloadDao.getDownloadsCountByStatusFlow(listOf(Status.Queued, Status.QueuedPaused).toListString())
+ val cancelledDownloadsCount : Flow = downloadDao.getDownloadsCountByStatusFlow(listOf(Status.Cancelled).toListString())
+ val erroredDownloadsCount : Flow = downloadDao.getDownloadsCountByStatusFlow(listOf(Status.Error).toListString())
+ val savedDownloadsCount : Flow = downloadDao.getDownloadsCountByStatusFlow(listOf(Status.Saved).toListString())
enum class Status {
Active, ActivePaused, PausedReQueued, Queued, QueuedPaused, Error, Cancelled, Saved, Processing
}
+ private fun List.toListString() : List{
+ return this.map { it.toString() }
+ }
+
suspend fun insert(item: DownloadItem) : Long {
return downloadDao.insert(item)
}
@@ -162,4 +187,53 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
downloadDao.removeAllLogID()
}
+
+ @SuppressLint("RestrictedApi")
+ suspend fun startDownloadWorker(queuedItems: List, context: Context, inputData: Data.Builder = Data.Builder()) {
+ val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
+ val allowMeteredNetworks = sharedPreferences.getBoolean("metered_networks", true)
+ val workManager = WorkManager.getInstance(context)
+
+ val currentWork = workManager.getWorkInfosByTag("download").await()
+ if (currentWork.size == 0 || currentWork.none{ it.state == WorkInfo.State.RUNNING } || (queuedItems.isNotEmpty() && queuedItems[0].downloadStartTime != 0L)){
+
+ val currentTime = System.currentTimeMillis()
+ var delay = 0L
+ if (queuedItems.isNotEmpty()){
+ delay = if (queuedItems[0].downloadStartTime != 0L){
+ queuedItems[0].downloadStartTime.minus(currentTime)
+ } else 0
+ if (delay <= 60000L) delay = 0L
+ }
+
+
+ val workConstraints = Constraints.Builder()
+ if (!allowMeteredNetworks) workConstraints.setRequiredNetworkType(NetworkType.UNMETERED)
+
+ val workRequest = OneTimeWorkRequestBuilder()
+ .addTag("download")
+ .setConstraints(workConstraints.build())
+ .setInitialDelay(delay, TimeUnit.MILLISECONDS)
+ .setInputData(inputData.build())
+
+ queuedItems.forEach {
+ workRequest.addTag(it.id.toString())
+ }
+
+ workManager.enqueueUniqueWork(
+ System.currentTimeMillis().toString(),
+ ExistingWorkPolicy.REPLACE,
+ workRequest.build()
+ )
+
+ }
+
+ val isCurrentNetworkMetered = (context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).isActiveNetworkMetered
+ if (!allowMeteredNetworks && isCurrentNetworkMetered){
+ Looper.prepare().run {
+ Toast.makeText(context, context.getString(R.string.metered_network_download_start_info), Toast.LENGTH_LONG).show()
+ }
+ }
+ }
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/HistoryRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/HistoryRepository.kt
index a90d876b..9f13a414 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/HistoryRepository.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/HistoryRepository.kt
@@ -1,11 +1,11 @@
package com.deniscerri.ytdlnis.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 kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
-import com.deniscerri.ytdlnis.database.DBManager.SORTING
class HistoryRepository(private val historyDao: HistoryDao) {
val items : Flow> = historyDao.getAllHistory()
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/LogRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/LogRepository.kt
index 90366ebe..f5712b7c 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/LogRepository.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/LogRepository.kt
@@ -2,9 +2,8 @@ package com.deniscerri.ytdlnis.database.repository
import com.deniscerri.ytdlnis.database.dao.LogDao
import com.deniscerri.ytdlnis.database.models.LogItem
+import com.deniscerri.ytdlnis.util.Extensions.appendLineToLog
import kotlinx.coroutines.flow.Flow
-import java.util.regex.MatchResult
-import java.util.regex.Pattern
class LogRepository(private val logDao: LogDao) {
val items : Flow> = logDao.getAllLogsFlow()
@@ -43,16 +42,7 @@ class LogRepository(private val logDao: LogDao) {
runCatching {
val item = getItem(id) ?: return
val log = item.content ?: ""
- val lines = log.split("\n")
- //clean dublicate progress + add newline
- var newLine = line
- if (newLine.contains("[download")){
- newLine = "[download]" + line.split("[download]").last()
- }
-
- val l = lines.dropLastWhile { it.contains("[download") }.joinToString("\n") + "\n${newLine}"
- item.content = l
-
+ item.content = log.appendLineToLog(line)
//item.content += "\n$line"
logDao.update(item)
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ObserveSourcesRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ObserveSourcesRepository.kt
index 9ee8bf3d..2ffa2dff 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ObserveSourcesRepository.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ObserveSourcesRepository.kt
@@ -1,8 +1,13 @@
package com.deniscerri.ytdlnis.database.repository
+import android.app.AlarmManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.dao.ObserveSourcesDao
import com.deniscerri.ytdlnis.database.models.ObserveSourcesItem
+import com.deniscerri.ytdlnis.receiver.ObserveAlarmReceiver
import kotlinx.coroutines.flow.Flow
class ObserveSourcesRepository(private val observeSourcesDao: ObserveSourcesDao) {
@@ -57,4 +62,16 @@ class ObserveSourcesRepository(private val observeSourcesDao: ObserveSourcesDao)
observeSourcesDao.update(item)
}
+ fun cancelObservationTaskByID(context: Context, id: Long){
+ val alarmManager = context.getSystemService(AlarmManager::class.java)
+ alarmManager.cancel(
+ PendingIntent.getBroadcast(
+ context,
+ id.toInt(),
+ Intent(context, ObserveAlarmReceiver::class.java),
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ )
+ }
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt
index afe8b8ee..0368e712 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt
@@ -1,17 +1,24 @@
package com.deniscerri.ytdlnis.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 kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import java.util.regex.Pattern
class ResultRepository(private val resultDao: ResultDao, private val context: Context) {
private val tag: String = "ResultRepository"
val allResults : Flow> = resultDao.getResults()
var itemCount = MutableStateFlow(-1)
+ enum class SourceType {
+ YOUTUBE_VIDEO, YOUTUBE_PLAYLIST, SEARCH_QUERY, YT_DLP
+ }
+
suspend fun insert(it: ResultItem){
resultDao.insert(it)
}
@@ -28,46 +35,52 @@ class ResultRepository(private val resultDao: ResultDao, private val context: Co
resultDao.insertMultiple(items)
}
- suspend fun search(inputQuery: String, resetResults: Boolean) : ArrayList{
+ suspend fun search(inputQuery: String, resetResults: Boolean, addToResults: Boolean) : ArrayList{
val infoUtil = InfoUtil(context)
if (resetResults) deleteAll()
val res = infoUtil.search(inputQuery)
itemCount.value = res.size
- val ids = resultDao.insertMultiple(res)
- ids.forEachIndexed { index, id ->
- res[index]?.id = id
+ if (addToResults){
+ val ids = resultDao.insertMultiple(res)
+ ids.forEachIndexed { index, id ->
+ res[index].id = id
+ }
}
return res
}
- suspend fun getYoutubeVideo(inputQuery: String, resetResults: Boolean) : ArrayList{
+ suspend fun getYoutubeVideo(inputQuery: String, resetResults: Boolean, addToResults: Boolean) : ArrayList{
val infoUtil = InfoUtil(context)
- val v = infoUtil.getYoutubeVideo(inputQuery)
+ val v = infoUtil.getYoutubeVideo(inputQuery) ?: return arrayListOf()
if (resetResults) {
deleteAll()
itemCount.value = v.size
}else{
- v.filter { it?.playlistTitle.isNullOrBlank() }.forEach { it?.playlistTitle = "ytdlnis-Search" }
+ v.filter { it.playlistTitle.isBlank() }.forEach { it.playlistTitle = "ytdlnis-Search" }
}
- val ids = resultDao.insertMultiple(v)
- ids.forEachIndexed { index, id ->
- v[index]?.id = id
+ if (addToResults){
+ val ids = resultDao.insertMultiple(v)
+ ids.forEachIndexed { index, id ->
+ v[index].id = id
+ }
}
return ArrayList(v)
}
- suspend fun getPlaylist(inputQuery: String, resetResults: Boolean) : ArrayList{
+ suspend fun getPlaylist(inputQuery: String, resetResults: Boolean, addToResults: Boolean) : ArrayList{
val query = inputQuery.split("list=".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()[1].split("&").first()
var nextPageToken = ""
if (resetResults) deleteAll()
val infoUtil = InfoUtil(context)
- val items : ArrayList = arrayListOf()
+ val items = arrayListOf()
do {
- val tmp = infoUtil.getPlaylist(query, nextPageToken, if (items.isNotEmpty()) items[0]?.playlistTitle ?: "" else "")
- val ids = resultDao.insertMultiple(tmp.videos.toList())
- ids.forEachIndexed { index, id ->
- tmp.videos[index]?.id = id
+ val tmp = infoUtil.getPlaylist(query, nextPageToken, if (items.isNotEmpty()) items[0].playlistTitle else "")
+ if (addToResults){
+ val ids = resultDao.insertMultiple(tmp.videos.toList())
+ ids.forEachIndexed { index, id ->
+ tmp.videos[index].id = id
+ }
}
items.addAll(tmp.videos)
val tmpToken = tmp.nextPageToken
@@ -79,19 +92,23 @@ class ResultRepository(private val resultDao: ResultDao, private val context: Co
return items
}
- suspend fun getDefault(inputQuery: String, resetResults: Boolean) : ArrayList {
+ suspend fun getDefault(inputQuery: String, resetResults: Boolean, addToResults: Boolean, singleItem: Boolean = false) : ArrayList {
val infoUtil = InfoUtil(context)
- val items = infoUtil.getFromYTDL(inputQuery)
+ val items = infoUtil.getFromYTDL(inputQuery, singleItem)
if (resetResults) {
deleteAll()
itemCount.value = items.size
}else{
- items.filter { it?.playlistTitle.isNullOrBlank() }.forEach { it!!.playlistTitle = "ytdlnis-Search" }
+ items.filter { it.playlistTitle.isNullOrBlank() }.forEach { it.playlistTitle = "ytdlnis-Search" }
}
- val ids = resultDao.insertMultiple(items.toList())
- ids.forEachIndexed { index, id ->
- items[index]?.id = id
+
+ if (addToResults){
+ val ids = resultDao.insertMultiple(items.toList())
+ ids.forEachIndexed { index, id ->
+ items[index].id = id
+ }
}
+
return items
}
@@ -111,4 +128,59 @@ class ResultRepository(private val resultDao: ResultDao, private val context: Co
fun getItemByURL(url: String): ResultItem? {
return resultDao.getResultByURL(url)
}
+
+ suspend fun getResultsFromSource(inputQuery: String, resetResults: Boolean, addToResults: Boolean = true, singleItem: Boolean = false) : ArrayList {
+ return when(getQueryType(inputQuery)){
+ SourceType.YOUTUBE_VIDEO -> {
+ getYoutubeVideo(inputQuery, resetResults, addToResults)
+ }
+ SourceType.YOUTUBE_PLAYLIST -> {
+ if (singleItem){
+ getDefault(inputQuery, resetResults, addToResults, true)
+ }else{
+ getPlaylist(inputQuery, resetResults, addToResults)
+ }
+ }
+ SourceType.SEARCH_QUERY -> {
+ search(inputQuery, resetResults, addToResults)
+ }
+ SourceType.YT_DLP -> {
+ getDefault(inputQuery, resetResults, addToResults)
+ }
+ }
+
+ }
+
+ fun getQueryType(inputQuery: String) : SourceType {
+ var type = SourceType.SEARCH_QUERY
+ val p = Pattern.compile("(^(https?)://(www.)?youtu(.be)?)|(^(https?)://(www.)?piped.video)")
+ val m = p.matcher(inputQuery)
+ if (m.find()) {
+ type = SourceType.YOUTUBE_VIDEO
+ if (inputQuery.contains("playlist?list=")) {
+ type = SourceType.YOUTUBE_PLAYLIST
+ }
+ } else if (Patterns.WEB_URL.matcher(inputQuery).matches()) {
+ type = SourceType.YT_DLP
+ }
+ return type
+ }
+
+ suspend fun updateDownloadItem(
+ downloadItem: DownloadItem
+ ) : DownloadItem? {
+ if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){
+ runCatching {
+ val info = getResultsFromSource(downloadItem.url, resetResults = false, addToResults = false, singleItem = true).first()
+ if (downloadItem.title.isEmpty()) downloadItem.title = info.title
+ if (downloadItem.author.isEmpty()) downloadItem.author = info.author
+ downloadItem.duration = info.duration
+ downloadItem.website = info.website
+ if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info.thumb
+ return downloadItem
+ }
+ }
+ return null
+ }
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/CookieViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/CookieViewModel.kt
index dde43c31..b1784046 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/CookieViewModel.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/CookieViewModel.kt
@@ -17,12 +17,11 @@ 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.CookiesFragment
import com.deniscerri.ytdlnis.ui.more.WebViewActivity
-import com.deniscerri.ytdlnis.util.FileUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
+import java.net.URL
import java.util.Date
class CookieViewModel(private val application: Application) : AndroidViewModel(application) {
@@ -44,7 +43,7 @@ class CookieViewModel(private val application: Application) : AndroidViewModel(a
return repository.getAll()
}
- fun getByURL(url: String) : CookieItem {
+ fun getByURL(url: String) : CookieItem? {
return repository.getByURL(url)
}
@@ -75,7 +74,7 @@ class CookieViewModel(private val application: Application) : AndroidViewModel(a
}
@SuppressLint("SdCardPath")
- fun getCookiesFromDB() : Result = kotlin.runCatching {
+ fun getCookiesFromDB(url: String) : Result = kotlin.runCatching {
CookieManager.getInstance().run {
if (!hasCookies()) throw Exception("There is no cookies in the database!")
flush()
@@ -83,30 +82,35 @@ class CookieViewModel(private val application: Application) : AndroidViewModel(a
val dbPath = File("/data/data/${BuildConfig.APPLICATION_ID}/").walkTopDown().find { it.name == "Cookies" }
?: throw Exception("Cookies File not found!")
- SQLiteDatabase.openDatabase(
+ val db = SQLiteDatabase.openDatabase(
dbPath.absolutePath, null, OPEN_READONLY
- ).run {
- val projection = arrayOf(
- CookieObject.HOST,
- CookieObject.EXPIRY,
- CookieObject.PATH,
- CookieObject.NAME,
- CookieObject.VALUE,
- CookieObject.SECURE
- )
- val cookieList = mutableListOf()
- query(
- "cookies", projection, null, null, null, null, null
- ).run {
- while (moveToNext()) {
- val expiry = getLong(getColumnIndexOrThrow(CookieObject.EXPIRY))
- val name = getString(getColumnIndexOrThrow(CookieObject.NAME))
- val value = getString(getColumnIndexOrThrow(CookieObject.VALUE))
- val path = getString(getColumnIndexOrThrow(CookieObject.PATH))
- val secure = getLong(getColumnIndexOrThrow(CookieObject.SECURE)) == 1L
- val hostKey = getString(getColumnIndexOrThrow(CookieObject.HOST))
+ )
- val host = if (hostKey[0] != '.') ".$hostKey" else hostKey
+ val projection = arrayOf(
+ CookieObject.HOST,
+ CookieObject.EXPIRY,
+ CookieObject.PATH,
+ CookieObject.NAME,
+ CookieObject.VALUE,
+ CookieObject.SECURE
+ )
+ val cookieList = mutableListOf()
+ db.query(
+ "cookies", projection, null, null, null, null, null
+ ).run {
+ while (moveToNext()) {
+ val expiry = getLong(getColumnIndexOrThrow(CookieObject.EXPIRY))
+ val name = getString(getColumnIndexOrThrow(CookieObject.NAME))
+ val value = getString(getColumnIndexOrThrow(CookieObject.VALUE))
+ val path = getString(getColumnIndexOrThrow(CookieObject.PATH))
+ val secure = getLong(getColumnIndexOrThrow(CookieObject.SECURE)) == 1L
+ val hostKey = getString(getColumnIndexOrThrow(CookieObject.HOST))
+
+
+ val host = if (hostKey[0] != '.') ".$hostKey" else hostKey
+
+ val requiredHost = URL(url).host
+ if(host.contains(requiredHost)){
cookieList.add(
WebViewActivity.CookieItem(
domain = host,
@@ -118,13 +122,13 @@ class CookieViewModel(private val application: Application) : AndroidViewModel(a
)
)
}
- close()
}
close()
- cookieList.fold(StringBuilder("")) { acc, cookie ->
- acc.append(cookie.toNetscapeFormat()).append("\n")
- }.toString()
}
+ db.close()
+ cookieList.fold(StringBuilder("")) { acc, cookie ->
+ acc.append(cookie.toNetscapeFormat()).append("\n")
+ }.toString()
}
fun updateCookiesFile() = viewModelScope.launch(Dispatchers.IO) {
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt
index 94bf4364..c7d3d2f1 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt
@@ -1,36 +1,25 @@
package com.deniscerri.ytdlnis.database.viewmodel
-import android.annotation.SuppressLint
import android.app.Application
-import android.content.Context
import android.content.SharedPreferences
import android.content.res.Configuration
import android.content.res.Resources
-import android.net.ConnectivityManager
-import android.os.Looper
import android.util.DisplayMetrics
-import android.widget.Toast
-import androidx.compose.animation.core.updateTransition
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.preference.PreferenceManager
-import androidx.work.Constraints
import androidx.work.Data
import androidx.work.ExistingWorkPolicy
-import androidx.work.NetworkType
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.DBManager
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
import com.deniscerri.ytdlnis.database.dao.DownloadDao
-import com.deniscerri.ytdlnis.database.dao.ResultDao
import com.deniscerri.ytdlnis.database.models.AudioPreferences
import com.deniscerri.ytdlnis.database.models.CommandTemplate
import com.deniscerri.ytdlnis.database.models.DownloadItem
@@ -41,12 +30,11 @@ 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.DownloadUtil
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.work.AlarmScheduler
-import com.deniscerri.ytdlnis.work.DownloadWorker
import com.deniscerri.ytdlnis.work.UpdatePlaylistFormatsWorker
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
@@ -59,7 +47,6 @@ import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.io.File
import java.util.Locale
-import java.util.concurrent.TimeUnit
class DownloadViewModel(private val application: Application) : AndroidViewModel(application) {
@@ -72,11 +59,16 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
val queuedDownloads : Flow>
val activeDownloads : Flow>
val processingDownloads : Flow>
- val activeDownloadsCount : Flow
val cancelledDownloads : Flow>
val erroredDownloads : Flow>
val savedDownloads : Flow>
+ val activeDownloadsCount : Flow
+ val queuedDownloadsCount : Flow
+ val cancelledDownloadsCount : Flow
+ val erroredDownloadsCount : Flow
+ val savedDownloadsCount : Flow
+
private var bestVideoFormat : Format
private var bestAudioFormat : Format
private var defaultVideoFormats : MutableList
@@ -94,6 +86,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
private var audioCodec: String?
private val dao: DownloadDao
private val historyRepository: HistoryRepository
+ private val resultRepository: ResultRepository
data class AlreadyExistsUIState(
var historyItems: MutableList,
@@ -120,15 +113,21 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
dao = dbManager.downloadDao
repository = DownloadRepository(dao)
historyRepository = HistoryRepository(dbManager.historyDao)
+ resultRepository = ResultRepository(dbManager.resultDao, application)
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(application)
commandTemplateDao = DBManager.getInstance(application).commandTemplateDao
infoUtil = InfoUtil(application)
+ activeDownloadsCount = repository.activeDownloadsCount
+ queuedDownloadsCount = repository.queuedDownloadsCount
+ cancelledDownloadsCount = repository.cancelledDownloadsCount
+ erroredDownloadsCount = repository.erroredDownloadsCount
+ savedDownloadsCount = repository.savedDownloadsCount
+
allDownloads = repository.allDownloads.flow
queuedDownloads = repository.queuedDownloads.flow
activeDownloads = repository.activeDownloads
processingDownloads = repository.processingDownloads
- activeDownloadsCount = repository.activeDownloadsCount
savedDownloads = repository.savedDownloads.flow
cancelledDownloads = repository.cancelledDownloads.flow
erroredDownloads = repository.erroredDownloads.flow
@@ -663,17 +662,17 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
suspend fun resetScheduleTimeForItemsAndStartDownload(items: List) = CoroutineScope(Dispatchers.IO).launch {
dbManager.downloadDao.resetScheduleTimeForItems(items)
- DownloadUtil.startDownloadWorker(emptyList(), application)
+ repository.startDownloadWorker(emptyList(), application)
}
- suspend fun putAtTopOfQueue(id: Long) = CoroutineScope(Dispatchers.IO).launch{
- dbManager.downloadDao.putAtTopOfTheQueue(id)
- DownloadUtil.startDownloadWorker(emptyList(), application)
+ suspend fun putAtTopOfQueue(ids: List) = CoroutineScope(Dispatchers.IO).launch{
+ dbManager.downloadDao.putAtTopOfTheQueue(ids)
+ repository.startDownloadWorker(emptyList(), application)
}
suspend fun reQueueDownloadItems(items: List) = CoroutineScope(Dispatchers.IO).launch {
dbManager.downloadDao.reQueueDownloadItems(items)
- DownloadUtil.startDownloadWorker(emptyList(), application)
+ repository.startDownloadWorker(emptyList(), application)
}
suspend fun queueDownloads(items: List, ign : Boolean = false) : Pair, List> {
@@ -761,19 +760,27 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
if (queuedItems.isNotEmpty()){
if (!useScheduler || alarmScheduler.isDuringTheScheduledTime()){
- DownloadUtil.startDownloadWorker(queuedItems, context)
+ repository.startDownloadWorker(queuedItems, context)
if(!useScheduler){
queuedItems.filter { it.downloadStartTime != 0L && (it.title.isEmpty() || it.author.isEmpty() || it.thumb.isEmpty()) }.forEach {
- try{
- updateDownloadItem(it, infoUtil, dbManager.downloadDao, dbManager.resultDao)
- }catch (ignored: Exception){}
+ CoroutineScope(Dispatchers.IO).launch {
+ runCatching {
+ resultRepository.updateDownloadItem(it)?.apply {
+ repository.updateWithoutUpsert(this)
+ }
+ }
+ }
}
}else{
queuedItems.filter { it.title.isEmpty() || it.author.isEmpty() || it.thumb.isEmpty() }.forEach {
- try{
- updateDownloadItem(it, infoUtil, dbManager.downloadDao, dbManager.resultDao)
- }catch (ignored: Exception){}
+ CoroutineScope(Dispatchers.IO).launch {
+ runCatching {
+ resultRepository.updateDownloadItem(it)?.apply {
+ repository.updateWithoutUpsert(this)
+ }
+ }
+ }
}
}
}
@@ -819,7 +826,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
items.forEachIndexed { index, i ->
i.format = selectedFormats[index].format
if (i.type == Type.video) selectedFormats[index].audioFormats?.map { it.format_id }?.let { i.videoPreferences.audioFormatIDs.addAll(it) }
- updateDownload(i)
+ repository.update(i)
}
return items.map { it.format.filesize }
@@ -829,7 +836,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
val items = repository.getProcessingDownloads()
items.forEach { i ->
i.format = format
- updateDownload(i)
+ repository.update(i)
}
}
@@ -837,7 +844,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
val items = repository.getProcessingDownloads()
items.forEach { i ->
i.downloadPath = path
- updateDownload(i)
+ repository.update(i)
}
}
@@ -866,7 +873,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
dbManager.resultDao.update(this)
}
}
- updateDownload(i)
+ repository.update(i)
}
}
@@ -874,7 +881,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
dao.getProcessingDownloadsList().apply {
this.forEach {
it.status = DownloadRepository.Status.Saved.toString()
- updateDownload(it)
+ repository.update(it)
}
val ids = this.map { it.id }
@@ -900,7 +907,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
repository.getProcessingDownloads().apply {
val new = switchDownloadType(this, newType)
new.forEach {
- updateDownload(it)
+ repository.update(it)
}
}
}
@@ -933,28 +940,5 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
return dao.getURLsByStatus(list.map { it.toString() })
}
- private fun updateDownloadItem(
- downloadItem: DownloadItem,
- infoUtil: InfoUtil,
- dao: DownloadDao,
- resultDao: ResultDao
- ) : Boolean {
- var wasQuickDownloaded = false
- if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){
- runCatching {
- val info = infoUtil.getMissingInfo(downloadItem.url)
- if (downloadItem.title.isEmpty()) downloadItem.title = info?.title.toString()
- if (downloadItem.author.isEmpty()) downloadItem.author = info?.author.toString()
- downloadItem.duration = info?.duration.toString()
- downloadItem.website = info?.website.toString()
- if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info?.thumb.toString()
- runBlocking {
- wasQuickDownloaded = resultDao.getCountInt() == 0
- repository.updateWithoutUpsert(downloadItem)
- }
- }
- }
- return wasQuickDownloaded
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/HistoryViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/HistoryViewModel.kt
index cb8646c2..93adf859 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/HistoryViewModel.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/HistoryViewModel.kt
@@ -8,9 +8,9 @@ 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.DBManager.SORTING
import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySortType
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ObserveSourcesViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ObserveSourcesViewModel.kt
index 00eb6c46..f7ff0d82 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ObserveSourcesViewModel.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ObserveSourcesViewModel.kt
@@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.database.viewmodel
import android.app.AlarmManager
import android.app.Application
import android.app.PendingIntent
-import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import androidx.lifecycle.AndroidViewModel
@@ -12,12 +11,9 @@ import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import androidx.preference.PreferenceManager
import com.deniscerri.ytdlnis.database.DBManager
-import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ObserveSourcesItem
import com.deniscerri.ytdlnis.database.repository.ObserveSourcesRepository
import com.deniscerri.ytdlnis.receiver.ObserveAlarmReceiver
-import com.deniscerri.ytdlnis.util.DownloadUtil
-import com.deniscerri.ytdlnis.util.Extensions.closestValue
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.time.Month
@@ -63,13 +59,13 @@ class ObserveSourcesViewModel(private val application: Application) : AndroidVie
}
fun delete(item: ObserveSourcesItem) = viewModelScope.launch(Dispatchers.IO) {
- runCatching { DownloadUtil.cancelObservationTaskByID(application, item.id) }
+ runCatching { repository.cancelObservationTaskByID(application, item.id) }
repository.delete(item)
}
fun deleteAll() = viewModelScope.launch(Dispatchers.IO) {
getAll().forEach {
- runCatching { DownloadUtil.cancelObservationTaskByID(application, it.id) }
+ runCatching { repository.cancelObservationTaskByID(application, it.id) }
}
repository.deleteAll()
@@ -94,7 +90,7 @@ class ObserveSourcesViewModel(private val application: Application) : AndroidVie
c.set(Calendar.MINUTE, hourMin.get(Calendar.MINUTE))
- DownloadUtil.cancelObservationTaskByID(application, id)
+ repository.cancelObservationTaskByID(application, id)
val intent = Intent(application, ObserveAlarmReceiver::class.java)
intent.putExtra("id", id)
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt
index c24f2dcf..61c8eac6 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt
@@ -5,7 +5,6 @@ import android.app.ActivityManager.RunningAppProcessInfo
import android.app.Application
import android.content.SharedPreferences
import android.util.Log
-import android.util.Patterns
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
@@ -21,14 +20,14 @@ 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.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 kotlinx.coroutines.withContext
-import java.util.regex.Pattern
+import java.util.concurrent.CancellationException
class ResultViewModel(private val application: Application) : AndroidViewModel(application) {
@@ -53,6 +52,18 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
errorMessage = null,
actions = null
))
+
+
+ val updatingData: MutableStateFlow = MutableStateFlow(false)
+ var updateResultData: MutableStateFlow?> = MutableStateFlow(null)
+ private var updateResultDataJob : Job? = null
+
+ val updatingFormats: MutableStateFlow = MutableStateFlow(false)
+ var updateFormatsResultData: MutableStateFlow?> = MutableStateFlow(null)
+ private var updateFormatsResultDataJob: Job? = null
+
+ var parsingQueries: Job? = null
+
private val sharedPreferences: SharedPreferences
init {
@@ -86,41 +97,45 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
deleteAll()
}
}
- suspend fun parseQueries(inputQueries: List) : List {
- if (inputQueries.size > 1){
- repository.itemCount.value = inputQueries.size
- }
- val resetResults = inputQueries.size == 1
- uiState.update {it.copy(processing = true, errorMessage = null, actions = null)}
- return withContext(Dispatchers.IO){
- val res = mutableListOf()
- inputQueries.forEach { inputQuery ->
- val type = getQueryType(inputQuery)
- try {
- when (type) {
- "Search" -> res.addAll(repository.search(inputQuery, resetResults))
- "YT_Video" -> res.addAll(repository.getYoutubeVideo(inputQuery, resetResults))
- "YT_Playlist" -> res.addAll(repository.getPlaylist(inputQuery, resetResults))
- else -> res.addAll(repository.getDefault(inputQuery, resetResults))
- }
- } catch (e: Exception) {
- if (updateResultDataJob?.isCancelled == false){
- 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())
- }
+ fun cancelParsingQueries(){
+ parsingQueries?.cancel(CancellationException())
+ uiState.update {it.copy(processing = false)}
+ }
+ suspend fun parseQueries(inputQueries: List, onResult: (list: List) -> Unit) {
+ if (parsingQueries == null || parsingQueries?.isCancelled == true || parsingQueries?.isCompleted == true) {
+ parsingQueries = viewModelScope.launch(Dispatchers.IO) {
+ 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()
+ 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)
}
- if (!isForegrounded() && inputQueries.size > 1){
- notificationUtil.showQueriesFinished()
- }
- uiState.update {it.copy(processing = false)}
- res
+ }else{
+ onResult(listOf())
}
}
@@ -133,20 +148,7 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
}.getOrElse { true }
}
- private fun getQueryType(inputQuery: String) : String {
- var type = "Search"
- val p = Pattern.compile("(^(https?)://(www.)?youtu(.be)?)|(^(https?)://(www.)?piped.video)")
- val m = p.matcher(inputQuery)
- if (m.find()) {
- type = "YT_Video"
- if (inputQuery.contains("playlist?list=")) {
- type = "YT_Playlist"
- }
- } else if (Patterns.WEB_URL.matcher(inputQuery).matches()) {
- type = "Default"
- }
- return type
- }
+
fun insert(items: ArrayList) = viewModelScope.launch(Dispatchers.IO){
items.forEach {
@@ -196,21 +198,19 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
}
}
- val updatingData: MutableStateFlow = MutableStateFlow(false)
- var updateResultData: MutableStateFlow?> = MutableStateFlow(null)
- private var updateResultDataJob : Job? = null
-
- val updatingFormats: MutableStateFlow = MutableStateFlow(false)
- var updateFormatsResultData: MutableStateFlow?> = MutableStateFlow(null)
- private var updateFormatsResultDataJob: Job? = null
suspend fun updateItemData(res: ResultItem){
if (updateResultDataJob == null || updateResultDataJob?.isCancelled == true || updateResultDataJob?.isCompleted == true){
updateResultDataJob = viewModelScope.launch(Dispatchers.IO) {
updatingData.emit(true)
- val result = parseQueries(listOf(res.url))
- updatingData.emit(false)
- updateResultData.emit(result)
+ updatingData.value = true
+ parseQueries(listOf(res.url)){ result ->
+ viewModelScope.launch(Dispatchers.IO){
+ updatingData.emit(false)
+ updatingData.value = false
+ updateResultData.emit(result)
+ }
+ }
}
updateResultDataJob?.start()
@@ -218,6 +218,7 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
if (it != null){
viewModelScope.launch(Dispatchers.IO) {
updatingData.emit(false)
+ updatingData.value = false
updateResultData.emit(mutableListOf())
}
}
@@ -226,13 +227,14 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
}
suspend fun cancelUpdateItemData(){
- updateResultDataJob?.cancel()
+ updateResultDataJob?.cancel(CancellationException())
updatingData.emit(false)
+ updatingData.value = false
updateResultData.emit(null)
}
suspend fun cancelUpdateFormatsItemData(){
- updateFormatsResultDataJob?.cancel()
+ updateFormatsResultDataJob?.cancel(CancellationException())
updatingFormats.emit(false)
updateFormatsResultData.emit(null)
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/receiver/CancelDownloadNotificationReceiver.kt b/app/src/main/java/com/deniscerri/ytdlnis/receiver/CancelDownloadNotificationReceiver.kt
index d0e2a33f..1731ff3e 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/receiver/CancelDownloadNotificationReceiver.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/receiver/CancelDownloadNotificationReceiver.kt
@@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
-import android.util.Log
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.util.NotificationUtil
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/receiver/ObserveAlarmReceiver.kt b/app/src/main/java/com/deniscerri/ytdlnis/receiver/ObserveAlarmReceiver.kt
index 84ef1d1c..e81eeb9a 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/receiver/ObserveAlarmReceiver.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/receiver/ObserveAlarmReceiver.kt
@@ -8,7 +8,6 @@ import androidx.work.Data
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
-import com.deniscerri.ytdlnis.work.DownloadWorker
import com.deniscerri.ytdlnis.work.ObserveSourceWorker
import java.util.concurrent.TimeUnit
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/receiver/PauseDownloadNotificationReceiver.kt b/app/src/main/java/com/deniscerri/ytdlnis/receiver/PauseDownloadNotificationReceiver.kt
index 4d2a778a..5906fa12 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/receiver/PauseDownloadNotificationReceiver.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/receiver/PauseDownloadNotificationReceiver.kt
@@ -10,9 +10,11 @@ import com.yausername.youtubedl_android.YoutubeDL
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
class PauseDownloadNotificationReceiver : BroadcastReceiver() {
override fun onReceive(c: Context, intent: Intent) {
+ val result = goAsync()
val id = intent.getIntExtra("itemID", 0)
if (id != 0) {
runCatching {
@@ -20,13 +22,17 @@ class PauseDownloadNotificationReceiver : BroadcastReceiver() {
val notificationUtil = NotificationUtil(c)
notificationUtil.cancelDownloadNotification(id)
YoutubeDL.getInstance().destroyProcessById(id.toString())
- notificationUtil.createResumeDownload(id, title)
val dbManager = DBManager.getInstance(c)
CoroutineScope(Dispatchers.IO).launch{
- runCatching {
+ try {
val item = dbManager.downloadDao.getDownloadById(id.toLong())
item.status = DownloadRepository.Status.ActivePaused.toString()
dbManager.downloadDao.update(item)
+ }finally {
+ withContext(Dispatchers.Main){
+ notificationUtil.createResumeDownload(id, title)
+ result.finish()
+ }
}
}
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/receiver/downloadAlarmReceivers/AlarmStartReceiver.kt b/app/src/main/java/com/deniscerri/ytdlnis/receiver/downloadAlarmReceivers/AlarmStartReceiver.kt
index 612e7480..308f9b08 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/receiver/downloadAlarmReceivers/AlarmStartReceiver.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/receiver/downloadAlarmReceivers/AlarmStartReceiver.kt
@@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.receiver.downloadAlarmReceivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
-import android.util.Log
import androidx.work.Constraints
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt
index 52b07b00..2d26548a 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt
@@ -1,6 +1,5 @@
package com.deniscerri.ytdlnis.ui
-import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Activity
import android.content.*
@@ -15,14 +14,12 @@ import android.util.Log
import android.util.Patterns
import android.view.*
import android.view.View.*
-import android.view.animation.Interpolator
import android.widget.*
import androidx.activity.addCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.coordinatorlayout.widget.CoordinatorLayout
-import androidx.core.os.bundleOf
import androidx.core.view.children
import androidx.core.view.forEach
import androidx.core.view.isVisible
@@ -45,7 +42,6 @@ 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
import com.deniscerri.ytdlnis.util.Extensions.enableFastScroll
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.ThemeUtil
@@ -220,7 +216,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
if (inputQueries != null) {
resultViewModel.deleteAll()
lifecycleScope.launch(Dispatchers.IO){
- resultViewModel.parseQueries(inputQueries!!)
+ resultViewModel.parseQueries(inputQueries!!){}
inputQueries = null
}
}
@@ -321,11 +317,25 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
requireView().post {
checkClipboard().apply {
- clipboardFab?.isVisible = this != null
- clipboardFab?.setOnClickListener {
- searchView!!.setText(this)
- clipboardFab?.isVisible = false
- initSearch(searchView!!)
+ this?.apply {
+ clipboardFab?.isVisible = this.isNotEmpty()
+ clipboardFab?.setOnClickListener {
+ if (this.size == 1){
+ searchView?.setText(this.first())
+ clipboardFab?.isVisible = false
+ initSearch(searchView!!)
+ }else{
+ searchBar?.performClick()
+ lifecycleScope.launch {
+ withContext(Dispatchers.IO){
+ delay(500)
+ }
+ this@apply.forEach {
+ onSearchSuggestionAdd(it)
+ }
+ }
+ }
+ }
}
lifecycleScope.launch {
@@ -435,6 +445,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
searchBar!!.setOnMenuItemClickListener { m: MenuItem ->
when (m.itemId) {
R.id.delete_results -> {
+ resultViewModel.cancelParsingQueries()
resultViewModel.getTrending()
selectedObjects = ArrayList()
searchBar!!.setText("")
@@ -489,7 +500,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
val url = checkClipboard()
url?.apply {
- combinedList.add(0, SearchSuggestionItem(this, SearchSuggestionType.CLIPBOARD))
+ combinedList.add(0, SearchSuggestionItem(this.joinToString("\n"), SearchSuggestionType.CLIPBOARD))
}
@@ -614,10 +625,10 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
}
}else{
- resultViewModel.parseQueries(queryList)
+ resultViewModel.parseQueries(queryList){}
}
}else{
- resultViewModel.parseQueries(queryList)
+ resultViewModel.parseQueries(queryList){}
}
}
}
@@ -830,12 +841,11 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
}
- private fun checkClipboard(): String?{
+ private fun checkClipboard(): List?{
return kotlin.runCatching {
val clipboard = requireContext().getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clip = clipboard.primaryClip!!.getItemAt(0).text
- val matchesURL = Patterns.WEB_URL.matcher(clip.toString()).matches()
- return if (matchesURL) clip.toString() else null
+ return clip.split("\r\n").filter { Patterns.WEB_URL.matcher(it).matches() }
}.getOrNull()
}
@@ -850,9 +860,17 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
}
override fun onSearchSuggestionClick(text: String) {
- clipboardFab?.isVisible = false
- searchView!!.setText(text)
- initSearch(searchView!!)
+ val res = text.split("\n")
+ if (res.size == 1){
+ clipboardFab?.isVisible = false
+ searchView!!.setText(text)
+ initSearch(searchView!!)
+ }else{
+ res.forEach {
+ onSearchSuggestionAdd(it)
+ }
+ }
+
}
override fun onSearchSuggestionAdd(text: String) {
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ActiveDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ActiveDownloadAdapter.kt
index 8b7ed9c4..84ed7bfc 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ActiveDownloadAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ActiveDownloadAdapter.kt
@@ -10,7 +10,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
-import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager
@@ -22,9 +21,7 @@ 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
import com.deniscerri.ytdlnis.util.Extensions.dp
-import com.deniscerri.ytdlnis.util.Extensions.popup
import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
@@ -63,7 +60,6 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
val card = holder.cardView
- card.popup()
card.tag = "${item!!.id}##card"
val uiHandler = Handler(Looper.getMainLooper())
val thumbnail = card.findViewById(R.id.image_view)
@@ -98,7 +94,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
// Author ----------------------------------
val author = card.findViewById(R.id.author)
var info = item.author
- if (item.duration.isNotEmpty()) {
+ if (item.duration.isNotEmpty() && item.duration != "-1") {
if (item.author.isNotEmpty()) info += " • "
info += item.duration
}
@@ -153,6 +149,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
val value = animation.animatedValue as Int
pauseButton.cornerRadius = value
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_pause_white)
+ pauseButton.contentDescription = activity.getString(R.string.pause)
pauseButton.isEnabled = true
pauseButton.tag = ActiveDownloadAction.Pause
}
@@ -171,6 +168,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
val value = animation.animatedValue as Int
pauseButton.cornerRadius = value
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_play_arrow_white)
+ pauseButton.contentDescription = activity.getString(R.string.start)
pauseButton.tag = ActiveDownloadAction.Resume
pauseButton.isEnabled = true
}
@@ -180,6 +178,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
DownloadRepository.Status.PausedReQueued -> {
progressBar.isIndeterminate = true
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.ic_refresh)
+ pauseButton.contentDescription = activity.getString(R.string.please_wait)
pauseButton.tag = null
pauseButton.isEnabled = false
cancelButton.visibility = View.GONE
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ActiveDownloadMinifiedAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ActiveDownloadMinifiedAdapter.kt
index 98a43063..3f9668dd 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ActiveDownloadMinifiedAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ActiveDownloadMinifiedAdapter.kt
@@ -25,7 +25,6 @@ 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
-import java.lang.StringBuilder
class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter(AsyncDifferConfig.Builder(
DIFF_CALLBACK
@@ -122,11 +121,13 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac
if (item.status == DownloadRepository.Status.ActivePaused.toString()){
progressBar.isIndeterminate = false
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_play_arrow_white)
+ pauseButton.contentDescription = activity.getString(R.string.start)
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Resume
cancelButton.visibility = View.VISIBLE
}else{
progressBar.isIndeterminate = true
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_pause_white)
+ pauseButton.contentDescription = activity.getString(R.string.pause)
cancelButton.visibility = View.GONE
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Pause
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/AlreadyExistsAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/AlreadyExistsAdapter.kt
index 684929c6..adee2e73 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/AlreadyExistsAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/AlreadyExistsAdapter.kt
@@ -5,7 +5,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
-import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
@@ -13,16 +12,10 @@ 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.models.HistoryItem
-import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
-import com.deniscerri.ytdlnis.ui.downloadcard.ConfigureDownloadBottomSheetDialog
import com.deniscerri.ytdlnis.util.Extensions.popup
-import com.deniscerri.ytdlnis.util.UiUtil
-import com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
class AlreadyExistsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter, AlreadyExistsAdapter.ViewHolder>(AsyncDifferConfig.Builder(
DIFF_CALLBACK
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ConfigureMultipleDownloadsAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ConfigureMultipleDownloadsAdapter.kt
index 1e1cc60a..01799569 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ConfigureMultipleDownloadsAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ConfigureMultipleDownloadsAdapter.kt
@@ -130,12 +130,15 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
when(item.type) {
DownloadViewModel.Type.audio -> {
btn.setIconResource(R.drawable.ic_music)
+ btn.contentDescription = activity.getString(R.string.audio)
}
DownloadViewModel.Type.video -> {
btn.setIconResource(R.drawable.ic_video)
+ btn.contentDescription = activity.getString(R.string.video)
}
else -> {
btn.setIconResource(R.drawable.ic_terminal)
+ btn.contentDescription = activity.getString(R.string.command)
}
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/DownloadLogsAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/DownloadLogsAdapter.kt
index e50894a6..89be5480 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/DownloadLogsAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/DownloadLogsAdapter.kt
@@ -63,9 +63,18 @@ class DownloadLogsAdapter(onItemClickListener: OnItemClickListener, activity: Ac
val downloadTypeIcon = card.findViewById(R.id.download_type)
when(item.downloadType){
- DownloadViewModel.Type.audio -> downloadTypeIcon.setIconResource(R.drawable.ic_music)
- DownloadViewModel.Type.video -> downloadTypeIcon.setIconResource(R.drawable.ic_video)
- DownloadViewModel.Type.command -> downloadTypeIcon.setIconResource(R.drawable.ic_terminal)
+ DownloadViewModel.Type.audio -> {
+ downloadTypeIcon.setIconResource(R.drawable.ic_music)
+ downloadTypeIcon.contentDescription = activity.getString(R.string.audio)
+ }
+ DownloadViewModel.Type.video -> {
+ downloadTypeIcon.setIconResource(R.drawable.ic_video)
+ downloadTypeIcon.contentDescription = activity.getString(R.string.video)
+ }
+ DownloadViewModel.Type.command -> {
+ downloadTypeIcon.setIconResource(R.drawable.ic_terminal)
+ downloadTypeIcon.contentDescription = activity.getString(R.string.command)
+ }
else -> {}
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/GenericDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/GenericDownloadAdapter.kt
index d291ef40..f8206899 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/GenericDownloadAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/GenericDownloadAdapter.kt
@@ -118,11 +118,21 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
if (actionButton.hasOnClickListeners()) actionButton.setOnClickListener(null)
when(item.status){
- DownloadRepository.Status.Cancelled.toString() -> actionButton.setIconResource(R.drawable.ic_refresh)
- DownloadRepository.Status.Saved.toString() -> actionButton.setIconResource(R.drawable.ic_downloads)
- DownloadRepository.Status.Queued.toString() -> actionButton.setIconResource(R.drawable.ic_baseline_delete_outline_24)
+ DownloadRepository.Status.Cancelled.toString() -> {
+ actionButton.setIconResource(R.drawable.ic_refresh)
+ actionButton.contentDescription = activity.getString(R.string.download)
+ }
+ DownloadRepository.Status.Saved.toString() -> {
+ actionButton.setIconResource(R.drawable.ic_downloads)
+ actionButton.contentDescription = activity.getString(R.string.download)
+ }
+ DownloadRepository.Status.Queued.toString() -> {
+ actionButton.setIconResource(R.drawable.ic_baseline_delete_outline_24)
+ actionButton.contentDescription = activity.getString(R.string.Remove)
+ }
else -> {
actionButton.setIconResource(R.drawable.ic_baseline_file_open_24)
+ actionButton.contentDescription = activity.getString(R.string.logs)
if (item.logID == null){
actionButton.visibility = View.GONE
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/HistoryAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/HistoryAdapter.kt
index 6d7b0cab..e39e4fc8 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/HistoryAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/HistoryAdapter.kt
@@ -114,7 +114,7 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
author.text = item.author
val length = card.findViewById(R.id.length)
- length.text = if(item.downloadPath.size == 1) item.duration else "[${item.downloadPath.size}]"
+ length.text = if(item.downloadPath.size == 1) item.duration else ""
// TIME DOWNLOADED ----------------------------------
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/HomeAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/HomeAdapter.kt
index 4ab2e4a7..0dfd561b 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/HomeAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/HomeAdapter.kt
@@ -1,9 +1,7 @@
package com.deniscerri.ytdlnis.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
@@ -19,7 +17,6 @@ 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
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
@@ -72,7 +69,6 @@ class HomeAdapter(onItemClickListener: OnItemClickListener, activity: Activity)
} else {
uiHandler.post { Picasso.get().load(R.color.black).into(thumbnail) }
}
- thumbnail.setColorFilter(Color.argb(20, 0, 0, 0))
}else{
uiHandler.post { Picasso.get().load(R.color.black).into(thumbnail) }
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ObserveSourcesAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ObserveSourcesAdapter.kt
index f6d221d4..5ee5390c 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ObserveSourcesAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/ObserveSourcesAdapter.kt
@@ -1,11 +1,9 @@
package com.deniscerri.ytdlnis.ui.adapter
import android.app.Activity
-import android.graphics.Color
import android.os.Handler
import android.os.Looper
import android.text.format.DateFormat
-import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -25,7 +23,6 @@ import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.progressindicator.LinearProgressIndicator
-import com.squareup.picasso.Picasso
import java.text.DateFormatSymbols
import java.text.SimpleDateFormat
import java.util.Calendar
@@ -139,7 +136,6 @@ class ObserveSourcesAdapter(onItemClickListener: OnItemClickListener, activity:
}
}else{
info.isVisible = true
- checkMissing.isVisible = true
btn.setImageResource(R.drawable.ic_search)
btn.setOnClickListener {
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/SearchSuggestionsAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/SearchSuggestionsAdapter.kt
index 72e89754..ee21f79f 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/SearchSuggestionsAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/SearchSuggestionsAdapter.kt
@@ -2,7 +2,6 @@ package com.deniscerri.ytdlnis.ui.adapter
import android.app.Activity
import android.content.SharedPreferences
-import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/TemplatesAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/TemplatesAdapter.kt
index ca221183..2e21938b 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/TemplatesAdapter.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/adapter/TemplatesAdapter.kt
@@ -6,7 +6,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
-import androidx.compose.ui.util.fastJoinToString
import androidx.core.view.isVisible
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
@@ -14,7 +13,6 @@ 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.database.models.LogItem
import com.deniscerri.ytdlnis.util.Extensions.popup
import com.google.android.material.card.MaterialCardView
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/AddExtraCommandsDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/AddExtraCommandsDialog.kt
index 43552868..f11e478f 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/AddExtraCommandsDialog.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/AddExtraCommandsDialog.kt
@@ -19,9 +19,9 @@ 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.ytdlnis.util.Extensions.enableTextHighlight
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kotlinx.coroutines.Dispatchers
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt
index 78edc2e5..65457dfc 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt
@@ -19,8 +19,6 @@ import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.deniscerri.ytdlnis.R
-import com.deniscerri.ytdlnis.database.DBManager
-import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
@@ -36,7 +34,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-//TODO MAKE CONFIGURE LIKE NORMAL SHEET
class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private val currentDownloadItem: DownloadItem, private val listener: OnDownloadItemUpdateListener) : BottomSheetDialogFragment() {
private lateinit var tabLayout: TabLayout
private lateinit var viewPager2: ViewPager2
@@ -77,6 +74,7 @@ class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private
tabLayout = view.findViewById(R.id.download_tablayout)
viewPager2 = view.findViewById(R.id.download_viewpager)
+ viewPager2.isUserInputEnabled = sharedPreferences.getBoolean("swipe_gestures_download_card", true)
(viewPager2.getChildAt(0) as? RecyclerView)?.apply {
isNestedScrollingEnabled = false
@@ -231,6 +229,7 @@ class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private
kotlin.runCatching {
val f = fragmentManager?.findFragmentByTag("f0") as DownloadAudioFragment
f.updateTitleAuthor(prevDownloadItem.title, prevDownloadItem.author)
+ f.updateSelectedAudioFormat(getDownloadItem(1).videoPreferences.audioFormatIDs.first())
}
}
1 -> {
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt
index f2e98e89..42dacacf 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt
@@ -28,10 +28,10 @@ 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.InfoUtil
-import com.deniscerri.ytdlnis.util.UiUtil
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.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadAudioFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadAudioFragment.kt
index db2f768f..35fb8236 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadAudioFragment.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadAudioFragment.kt
@@ -15,7 +15,6 @@ import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.widget.LinearLayout
import android.widget.TextView
-import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.isVisible
@@ -23,7 +22,6 @@ import androidx.core.view.setPadding
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
-import androidx.media3.common.util.Log
import androidx.preference.PreferenceManager
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
import com.deniscerri.ytdlnis.R
@@ -37,14 +35,13 @@ import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.google.android.material.card.MaterialCardView
-import com.google.android.material.progressindicator.LinearProgressIndicator
+import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputLayout
import com.google.android.material.textfield.TextInputLayout.END_ICON_NONE
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
@@ -83,7 +80,6 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
lifecycleScope.launch {
downloadItem = withContext(Dispatchers.IO) {
if (currentDownloadItem != null){
@@ -304,12 +300,22 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
bottomSheet.show(parentFragmentManager, "cutVideoSheet")
}
},
- updateDataClicked = {
- CoroutineScope(Dispatchers.IO).launch {
- resultItem?.apply {
- val rsVM = ViewModelProvider(requireActivity())[ResultViewModel::class.java]
- rsVM.updateItemData(this)
+ cutDisabledClicked = {
+ val isUpdatingData = ViewModelProvider(requireActivity())[ResultViewModel::class.java].updatingData.value
+ if(isUpdatingData){
+ val snack = Snackbar.make(view, context.getString(R.string.please_wait), Snackbar.LENGTH_SHORT)
+ snack.show()
+ }else{
+ val snack = Snackbar.make(view, context.getString(R.string.cut_unavailable), Snackbar.LENGTH_SHORT)
+ snack.setAction(R.string.update){
+ CoroutineScope(SupervisorJob()).launch(Dispatchers.IO) {
+ resultItem?.apply {
+ val rsVM = ViewModelProvider(requireActivity())[ResultViewModel::class.java]
+ rsVM.updateItemData(this)
+ }
+ }
}
+ snack.show()
}
},
extraCommandsClicked = {
@@ -328,6 +334,16 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
}catch (e : Exception){
e.printStackTrace()
}
+ super.onViewCreated(view, savedInstanceState)
+ }
+ }
+
+ @SuppressLint("RestrictedApi")
+ fun updateSelectedAudioFormat(formatID: String){
+ resultItem?.formats?.find { it.format_id == formatID }?.apply {
+ downloadItem.format = this
+ val formatCard = requireView().findViewById(R.id.format_card_constraintLayout)
+ UiUtil.populateFormatCard(requireContext(), formatCard, downloadItem.format, listOf())
}
}
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt
index dff14516..64037cd1 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt
@@ -2,6 +2,7 @@ package com.deniscerri.ytdlnis.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
@@ -19,7 +20,11 @@ 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
@@ -139,6 +144,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
tabLayout = view.findViewById(R.id.download_tablayout)
viewPager2 = view.findViewById(R.id.download_viewpager)
updateItem = view.findViewById(R.id.update_item)
+ viewPager2.isUserInputEnabled = sharedPreferences.getBoolean("swipe_gestures_download_card", true)
//loading shimmers
@@ -307,12 +313,31 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
download.isEnabled = false
val item: DownloadItem = getDownloadItem()
item.downloadStartTime = it.timeInMillis
- runBlocking {
- downloadViewModel.queueDownloads(listOf(item))
- val date = SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(item.downloadStartTime)
- Toast.makeText(context, getString(R.string.download_rescheduled_to) + " " + date, Toast.LENGTH_LONG).show()
+ if (item.videoPreferences.alsoDownloadAsAudio){
+ val itemsToQueue = mutableListOf()
+ itemsToQueue.add(item)
+
+ getAlsoAudioDownloadItem{ audioDownloadItem ->
+ audioDownloadItem.downloadStartTime = it.timeInMillis
+ itemsToQueue.add(audioDownloadItem)
+
+ runBlocking {
+ downloadViewModel.queueDownloads(itemsToQueue)
+ val date = SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(item.downloadStartTime)
+ Toast.makeText(context, getString(R.string.download_rescheduled_to) + " " + date, Toast.LENGTH_LONG).show()
+ }
+ dismiss()
+ }
+ }else{
+ runBlocking {
+ downloadViewModel.queueDownloads(listOf(item))
+ val date = SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(item.downloadStartTime)
+ Toast.makeText(context, getString(R.string.download_rescheduled_to) + " " + date, Toast.LENGTH_LONG).show()
+ }
+ dismiss()
+
}
- dismiss()
+
}
}
download!!.setOnClickListener {
@@ -324,10 +349,24 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
scheduleBtn.isEnabled = false
download.isEnabled = false
val item: DownloadItem = getDownloadItem()
- runBlocking {
- downloadViewModel.queueDownloads(listOf(item))
+ if (item.videoPreferences.alsoDownloadAsAudio){
+ val itemsToQueue = mutableListOf()
+ itemsToQueue.add(item)
+
+ getAlsoAudioDownloadItem {
+ itemsToQueue.add(it)
+
+ runBlocking {
+ downloadViewModel.queueDownloads(itemsToQueue)
+ }
+ dismiss()
+ }
+ }else{
+ runBlocking {
+ downloadViewModel.queueDownloads(listOf(item))
+ }
+ dismiss()
}
- dismiss()
}
}
@@ -563,7 +602,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
}
}
- private fun getDownloadItem(selectedTabPosition: Int = tabLayout.selectedTabPosition) : DownloadItem{
+ private fun getDownloadItem(selectedTabPosition: Int = tabLayout.selectedTabPosition) : DownloadItem {
return when(selectedTabPosition){
0 -> {
val f = fragmentManager?.findFragmentByTag("f0") as DownloadAudioFragment
@@ -580,6 +619,33 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
}
}
+ private fun getAlsoAudioDownloadItem(finished: (it: DownloadItem) -> Unit) {
+ try {
+ val ff = (fragmentManager?.findFragmentByTag("f0") as DownloadAudioFragment)
+ ff.updateSelectedAudioFormat(getDownloadItem(1).videoPreferences.audioFormatIDs.first())
+ finished(ff.downloadItem)
+ }catch (e: Exception){
+ val fragmentLifecycleCallback = object:
+ FragmentManager.FragmentLifecycleCallbacks() {
+
+ override fun onFragmentStarted(fm: FragmentManager, f: Fragment) {
+ fragmentManager?.unregisterFragmentLifecycleCallbacks(this)
+ val ff = (f as DownloadAudioFragment)
+ ff.requireView().post {
+ ff.updateSelectedAudioFormat(getDownloadItem(1).videoPreferences.audioFormatIDs.first())
+ finished(ff.downloadItem)
+ }
+ super.onFragmentStarted(fm, f)
+ }
+
+
+ }
+
+ fragmentManager?.registerFragmentLifecycleCallbacks(fragmentLifecycleCallback, true)
+ viewPager2.setCurrentItem(0, true)
+ }
+ }
+
private fun updateWhenSwitching(){
val prevDownloadItem = getDownloadItem(
if (viewPager2.currentItem == 1) 0 else 1
@@ -591,6 +657,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
kotlin.runCatching {
val f = fragmentManager?.findFragmentByTag("f0") as DownloadAudioFragment
f.updateTitleAuthor(prevDownloadItem.title, prevDownloadItem.author)
+ f.updateSelectedAudioFormat(getDownloadItem(1).videoPreferences.audioFormatIDs.first())
}
}
1 -> {
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt
index a75e5b6b..6ab94497 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt
@@ -30,17 +30,15 @@ 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.Extensions.enableTextHighlight
import com.deniscerri.ytdlnis.util.UiUtil.populateCommandCard
import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip
import com.google.android.material.textfield.TextInputLayout
import com.google.gson.Gson
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt
index 28bd0e76..c2b33c05 100644
--- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt
+++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt
@@ -10,8 +10,6 @@ import android.content.res.Configuration
import android.graphics.Canvas
import android.graphics.Color
import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
import android.text.format.DateFormat
import android.util.DisplayMetrics
import android.view.LayoutInflater
@@ -30,15 +28,10 @@ import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import androidx.work.Data
-import androidx.work.ExistingWorkPolicy
-import androidx.work.OneTimeWorkRequestBuilder
-import androidx.work.WorkManager
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.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
@@ -48,8 +41,6 @@ import com.deniscerri.ytdlnis.util.Extensions.enableFastScroll
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.InfoUtil
import com.deniscerri.ytdlnis.util.UiUtil
-import com.deniscerri.ytdlnis.work.UpdatePlaylistFormatsWorker
-import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.bottomappbar.BottomAppBar
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
@@ -63,7 +54,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat
import java.util.Locale
@@ -80,6 +70,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
private lateinit var behavior: BottomSheetBehavior
private lateinit var bottomAppBar: BottomAppBar
private lateinit var filesize : TextView
+ private lateinit var count : TextView
private lateinit var sharedPreferences: SharedPreferences
override fun onCreate(savedInstanceState: Bundle?) {
@@ -135,6 +126,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
val scheduleBtn = view.findViewById(R.id.bottomsheet_schedule_button)
val download = view.findViewById