This commit is contained in:
deniscerri 2023-04-16 08:57:44 +02:00
parent 7c86be083f
commit bef9abda44
No known key found for this signature in database
GPG key ID: 95C43D517D830350
10 changed files with 516 additions and 21 deletions

View file

@ -59,4 +59,8 @@
-keepclassmembers enum * { *; }
-keepclassmembers class * extends androidx.work.Worker {
public <init>(android.content.Context,androidx.work.WorkerParameters);
}
}
-dontshrink
-dontobfuscate
-dontoptimize

View file

@ -0,0 +1,421 @@
{
"formatVersion": 1,
"database": {
"version": 4,
"identityHash": "f911bed4915605d5b09bfd82892e2d7a",
"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, `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": "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)",
"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
}
],
"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, `downloadSections` TEXT NOT NULL DEFAULT '', `allFormats` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `audioPreferences` TEXT NOT NULL, `videoPreferences` TEXT NOT NULL, `customFileNameTemplate` TEXT NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `downloadStartTime` INTEGER NOT NULL DEFAULT 0)",
"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": "downloadSections",
"columnName": "downloadSections",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"fieldPath": "allFormats",
"columnName": "allFormats",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadPath",
"columnName": "downloadPath",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "website",
"columnName": "website",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "downloadSize",
"columnName": "downloadSize",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "playlistTitle",
"columnName": "playlistTitle",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "audioPreferences",
"columnName": "audioPreferences",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "videoPreferences",
"columnName": "videoPreferences",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "customFileNameTemplate",
"columnName": "customFileNameTemplate",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "SaveThumb",
"columnName": "SaveThumb",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "status",
"columnName": "status",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'Queued'"
},
{
"fieldPath": "downloadStartTime",
"columnName": "downloadStartTime",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "commandTemplates",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "searchHistory",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `query` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "query",
"columnName": "query",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "templateShortcuts",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `content` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "cookies",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `content` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
}
],
"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, 'f911bed4915605d5b09bfd82892e2d7a')"
]
}
}

View file

@ -8,10 +8,11 @@ import com.deniscerri.ytdlnis.database.models.*
@TypeConverters(Converters::class)
@Database(
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class, SearchHistoryItem::class, TemplateShortcut::class, CookieItem::class],
version = 3,
version = 4,
autoMigrations = [
AutoMigration (from = 1, to = 2),
AutoMigration (from = 2, to = 3)
AutoMigration (from = 2, to = 3),
AutoMigration (from = 3, to = 4)
]
)
abstract class DBManager : RoomDatabase(){

View file

@ -1,6 +1,7 @@
package com.deniscerri.ytdlnis.ui.downloads
import android.content.Context
import android.content.DialogInterface
import android.os.Bundle
import android.view.MenuItem
import android.view.View
@ -13,6 +14,7 @@ import androidx.work.WorkManager
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.tabs.TabLayout
@ -81,14 +83,20 @@ class DownloadQueueActivity : AppCompatActivity(){
try{
when(m.itemId){
R.id.clear_queue -> {
cancelAllDownloads()
downloadViewModel.deleteQueued()
showDeleteDialog() {
cancelAllDownloads()
downloadViewModel.deleteQueued()
}
}
R.id.clear_cancelled -> {
downloadViewModel.deleteCancelled()
showDeleteDialog() {
downloadViewModel.deleteCancelled()
}
}
R.id.clear_errored -> {
downloadViewModel.deleteErrored()
showDeleteDialog() {
downloadViewModel.deleteErrored()
}
}
}
}catch (e: Exception){
@ -99,6 +107,16 @@ class DownloadQueueActivity : AppCompatActivity(){
}
}
private fun showDeleteDialog (deleteClicked: (deleteClicked: Boolean) -> Unit){
val deleteDialog = MaterialAlertDialogBuilder(this)
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
deleteClicked(true)
}
deleteDialog.show()
}
private fun cancelAllDownloads() {
workManager.cancelAllWork()
}

View file

@ -288,11 +288,11 @@ class DownloadWorker(
}
}.onSuccess {
//move file from internal to set download directory
setProgressAsync(workDataOf("progress" to 100, "output" to "Moving file to $downloadLocation", "id" to downloadItem.id, "log" to logDownloads))
setProgressAsync(workDataOf("progress" to 100, "output" to "Moving file to ${fileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
var finalPath : String?
try {
finalPath = moveFile(tempFileDir.absoluteFile, downloadLocation){ progress ->
setProgressAsync(workDataOf("progress" to progress, "output" to "Moving file to $downloadLocation", "id" to downloadItem.id, "log" to logDownloads))
setProgressAsync(workDataOf("progress" to progress, "output" to "Moving file to ${fileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
}
setProgressAsync(workDataOf("progress" to 100, "output" to "Moved file to $finalPath", "id" to downloadItem.id, "log" to logDownloads))
}catch (e: Exception){

View file

@ -9,6 +9,7 @@
<RelativeLayout
android:id="@+id/active_download_relative_layout"
android:layout_width="0dp"
android:layout_marginHorizontal="10dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,2:1"
app:layout_constraintStart_toStartOf="parent"

View file

@ -65,7 +65,6 @@
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/download_viewpager"
android:layout_marginHorizontal="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View file

@ -0,0 +1,41 @@
Moved all of the app to kotlin
Fixed Song Thumbnails not showing on music apps using mediastore (like Samsung Music)
Cards update and animate nicely when new items are added
Turned download service to a worker and combined default downloads with custom command
Added Formats and File Sizes on Results
Added ability to change download path from the download card
Combined Audio / Video / Command in a single card through tabs
Added ability to download multiple vids at the same time (Limit is 5 for now)
Added ability to schedule downloads. You can put the date and time.
Fixed File Scanning
Made downloads download to temporary folders. Each version of the file depending on the url and format type has its own folder. If you cancel a download and restart it, it will resume the downloads based on the correct format. After download, temp folder gets axed.
Fixed downloads not getting cancelled sometimes
Added ability to update yt-dlp from a nightly build
Changed search suggestion provider to google's own api
Added more sorting options in the history fragment
Implemented Language switcher in the app. For devices on Android 13 and up, go to App Details and change it there
Added material date and time pickers
Updated bottom sheet design
Added separate format selection card
Implemented bottom card in the share menu instead of opening the whole app. If its a txt file it will open the app
Added m-time as a preference
Added ability to get result item formats if you searched for it or if it is a playlist item since they don't have formats
Added Download Logs
Added Search History
Added Separate Download Queue Screen. (Double Click the download icon or go to more section to access)
Fixed bugs on terminal mode
Fixed downlaod logs crashing on older apis
Added long press to open download card even if the setting is disabled
Fixed bug of download card duplicating when switching formats in share activity
Implemented Custom Command Tab in the download card. (Disabled by default. You need to create at least one command template in the more section)
Added tabs to download queue section (running, queued, cancelled, errored)
Added ability to update custom command right from the download card & modify the chosen one just for that download
Fixed search history storing duplicate queries
Implemented Preferred Download Type. On Share Activity or when searching for one result, it will open the preferred tab on the download card
Implemented processing multiple items from a playlist in the share activity. You can select a portion of them, then you can modify each item just like you would on a normal link. You can change the download directory for all items at once, and you can schedule all of them like a normal download. You can also change their type to audio/video/command all at once
Fixed Download All button not showing up after reopening app with a playlist as result
Added copy log in the download log screen
Fixed download logs not properly live scrolling
Added ability to retry cancelled downloads
Added ability to open logs directly from the list of errored downloads (if logs were enabled for that download at the time)
Showed link copied to clipboard as item suggestion in searchview

View file

@ -1,10 +1,20 @@
Download audio and video files on different formats through yt-dlp.
Download videos, playlists, multi-select items.
Really user friendly.
Download History.
Command Line Functionality.
Material You Compatible.
Foreground Download Service.
Share links directly to the app.
Built in search functionality.
Automatically checks for app updates.
download audio/video files from more than 1000 websites using yt-dlp
download playlists or multi select items
queue downloads and schedule them by date and time
use custom commands and templates or go full terminal mode
remove sponsorblock chapters
embed subtitles/metadata/chapters etc
modify metadata such as title and author
split item into separate files depending on its chapters
select different download formats
process multiple items before download
quick share card right from the share menu
search or insert a link from the app
log downloads
re-download cancelled or failed downloads
incognito mode when you don't want to save a download history
download multiple items at the same time
change preferred audio/video formats and qualities
Material You interface
MVVM Architecture w/ WorkManager
easy to use :)

View file

@ -1 +1 @@
Android YouTube Downloader app
Android Video/Audio Downloader app using yt-dlp