added livedata to results

This commit is contained in:
Denis Çerri 2023-01-18 22:51:58 +01:00
parent 335be8299c
commit 09bddccb61
No known key found for this signature in database
GPG key ID: 96B3554AF5B193EE
29 changed files with 1901 additions and 2014 deletions

View file

@ -82,6 +82,7 @@ android {
composeOptions { composeOptions {
kotlinCompilerExtensionVersion composeVer kotlinCompilerExtensionVersion composeVer
} }
namespace 'com.deniscerri.ytdlnis'
} }

View file

@ -0,0 +1,312 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "1391e7ec82bbacc310cf6f23e3d1f85a",
"entities": [
{
"tableName": "results",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
"fields": [
{
"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": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "history",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
"fields": [
{
"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": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "downloads",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `audioQualityId` TEXT NOT NULL, `videoQualityId` TEXT NOT NULL, `customTemplateId` INTEGER NOT NULL, `audioFormat` TEXT NOT NULL, `videoFormat` TEXT NOT NULL, `formatDesc` TEXT NOT NULL, `removeAudio` INTEGER NOT NULL DEFAULT 0, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
"fields": [
{
"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": "audioQualityId",
"columnName": "audioQualityId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "videoQualityId",
"columnName": "videoQualityId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "customTemplateId",
"columnName": "customTemplateId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "audioFormat",
"columnName": "audioFormat",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "videoFormat",
"columnName": "videoFormat",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "formatDesc",
"columnName": "formatDesc",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "removeAudio",
"columnName": "removeAudio",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"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": "status",
"columnName": "status",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'Queued'"
},
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "commandTemplates",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`title` TEXT NOT NULL, `content` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
"fields": [
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"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, '1391e7ec82bbacc310cf6f23e3d1f85a')"
]
}
}

View file

@ -1,26 +0,0 @@
package com.deniscerri.ytdlnis;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.deniscerri.ytdl", appContext.getPackageName());
}
}

View file

@ -0,0 +1,22 @@
package com.deniscerri.ytdlnis
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
/**
* Instrumented test, which will execute on an Android device.
*
* @see [Testing documentation](http://d.android.com/tools/testing)
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
Assert.assertEquals("com.deniscerri.ytdl", appContext.packageName)
}
}

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android">
package="com.deniscerri.ytdlnis" >
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

View file

@ -15,7 +15,7 @@ import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager import androidx.work.WorkManager
import androidx.work.workDataOf import androidx.work.workDataOf
import com.deniscerri.ytdlnis.database.Video import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.service.DownloadInfo import com.deniscerri.ytdlnis.service.DownloadInfo
import com.deniscerri.ytdlnis.service.IDownloaderListener import com.deniscerri.ytdlnis.service.IDownloaderListener
import com.deniscerri.ytdlnis.service.IDownloaderService import com.deniscerri.ytdlnis.service.IDownloaderService
@ -46,7 +46,7 @@ class DownloaderService : Service() {
ConcurrentHashMap() ConcurrentHashMap()
private val fileUtil = FileUtil() private val fileUtil = FileUtil()
private val downloadInfo = DownloadInfo() private val downloadInfo = DownloadInfo()
private var downloadQueue = LinkedList<Video>() private var downloadQueue = LinkedList<ResultItem>()
private val compositeDisposable = CompositeDisposable() private val compositeDisposable = CompositeDisposable()
private val notificationUtil = App.notificationUtil private val notificationUtil = App.notificationUtil
private var context: Context? = null private var context: Context? = null
@ -91,44 +91,45 @@ class DownloaderService : Service() {
} }
override fun onBind(intent: Intent): IBinder? { override fun onBind(intent: Intent): IBinder? {
val theIntent: Intent // val theIntent: Intent
val pendingIntent: PendingIntent // val pendingIntent: PendingIntent
if (intent.getBooleanExtra("rebind", false)) { // if (intent.getBooleanExtra("rebind", false)) {
return binder // return binder
} // }
when (val id = intent.getIntExtra("id", 1)) { // when (val id = intent.getIntExtra("id", 1)) {
NotificationUtil.DOWNLOAD_NOTIFICATION_ID -> { // NotificationUtil.DOWNLOAD_NOTIFICATION_ID -> {
notificationChannelID = NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID // notificationChannelID = NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
theIntent = Intent(this, MainActivity::class.java) // theIntent = Intent(this, MainActivity::class.java)
pendingIntent = // pendingIntent =
PendingIntent.getActivity(this, 0, theIntent, PendingIntent.FLAG_IMMUTABLE) // PendingIntent.getActivity(this, 0, theIntent, PendingIntent.FLAG_IMMUTABLE)
downloadNotificationID = id // downloadNotificationID = id
val queue: ArrayList<out Video>? = intent.getParcelableArrayListExtra("queue") // val queue: ArrayList<out ResultItem>? = intent.getParcelableArrayListExtra("queue")
downloadQueue = LinkedList() // downloadQueue = LinkedList()
downloadQueue.addAll(queue!!) // downloadQueue.addAll(queue!!)
downloadInfo.downloadQueue = downloadQueue // downloadInfo.downloadQueue = downloadQueue
val title = downloadInfo.video.title // val title = downloadInfo.video.title
val notification = // val notification =
App.notificationUtil.createDownloadServiceNotification(pendingIntent, title, NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID) // App.notificationUtil.createDownloadServiceNotification(pendingIntent, title, 1, NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
startForeground(downloadNotificationID, notification) // startForeground(downloadNotificationID, notification)
startDownload(downloadQueue) // startDownload(downloadQueue)
} // }
NotificationUtil.COMMAND_DOWNLOAD_NOTIFICATION_ID -> { // NotificationUtil.COMMAND_DOWNLOAD_NOTIFICATION_ID -> {
notificationChannelID = NotificationUtil.COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID // notificationChannelID = NotificationUtil.COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID
theIntent = Intent(this, CustomCommandActivity::class.java) // theIntent = Intent(this, CustomCommandActivity::class.java)
pendingIntent = // pendingIntent =
PendingIntent.getActivity(this, 0, theIntent, PendingIntent.FLAG_IMMUTABLE) // PendingIntent.getActivity(this, 0, theIntent, PendingIntent.FLAG_IMMUTABLE)
downloadNotificationID = id // downloadNotificationID = id
val command = intent.getStringExtra("command") // val command = intent.getStringExtra("command")
val commandNotification = App.notificationUtil.createDownloadServiceNotification( // val commandNotification = App.notificationUtil.createDownloadServiceNotification(
pendingIntent, // pendingIntent,
getString(R.string.running_ytdlp_command), // getString(R.string.running_ytdlp_command),
NotificationUtil.COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID // 1,
) // NotificationUtil.COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID
startForeground(downloadNotificationID, commandNotification) // )
startCommandDownload(command) // startForeground(downloadNotificationID, commandNotification)
} // startCommandDownload(command)
} // }
// }
return binder return binder
} }
@ -160,23 +161,24 @@ class DownloaderService : Service() {
activities.remove(activity) activities.remove(activity)
} }
override fun updateQueue(queue: ArrayList<Video>) {
try { override fun updateQueue(queue: ArrayList<ResultItem>) {
for (i in queue.indices) { // try {
downloadQueue.add(queue[i].clone() as Video) // for (i in queue.indices) {
} // downloadQueue.add(queue[i].clone() as ResultItem)
if (downloadQueue.size == queue.size) { // }
downloadInfo.downloadQueue = downloadQueue // if (downloadQueue.size == queue.size) {
startDownload(downloadQueue) // downloadInfo.downloadQueue = downloadQueue
} else { // startDownload(downloadQueue)
downloadInfo.downloadQueue = downloadQueue // } else {
Toast.makeText(context, getString(R.string.added_to_queue), Toast.LENGTH_SHORT) // downloadInfo.downloadQueue = downloadQueue
.show() // Toast.makeText(context, getString(R.string.added_to_queue), Toast.LENGTH_SHORT)
} // .show()
} catch (e: Exception) { // }
Toast.makeText(context, "Couldn't update download queue! :(", Toast.LENGTH_SHORT) // } catch (e: Exception) {
.show() // Toast.makeText(context, "Couldn't update download queue! :(", Toast.LENGTH_SHORT)
} // .show()
// }
} }
override fun cancelDownload(cancelAll: Boolean) { override fun cancelDownload(cancelAll: Boolean) {
@ -192,30 +194,31 @@ class DownloaderService : Service() {
} }
} }
override fun removeItemFromDownloadQueue(video: Video, type: String) {
//if its the same video with the same download type as the current downloading one override fun removeItemFromDownloadQueue(video: ResultItem?, type: String?) {
if (downloadInfo.video.getURL() == video.getURL() && downloadInfo.video.downloadedType == video.downloadedType) { // //if its the same video with the same download type as the current downloading one
cancelDownload(false) // if (downloadInfo.video.url == video.url && downloadInfo.video.type == video.downloadedType) {
downloadInfo.downloadType = type // cancelDownload(false)
onDownloadCancel(downloadInfo) // downloadInfo.downloadType = type
downloadQueue.pop() // onDownloadCancel(downloadInfo)
downloadInfo.downloadQueue = downloadQueue // downloadQueue.pop()
startDownload(downloadQueue) // downloadInfo.downloadQueue = downloadQueue
} else { // startDownload(downloadQueue)
downloadQueue.remove(video) // } else {
try { // downloadQueue.remove(video)
val info = DownloadInfo() // try {
info.video = video // val info = DownloadInfo()
info.downloadType = type // info.video = video
onDownloadCancel(info) // info.downloadType = type
} catch (ignored: Exception) { // onDownloadCancel(info)
} // } catch (ignored: Exception) {
} // }
Toast.makeText( // }
context, // Toast.makeText(
video.title + " " + getString(R.string.removed_from_queue), // context,
Toast.LENGTH_SHORT // video.title + " " + getString(R.string.removed_from_queue),
).show() // Toast.LENGTH_SHORT
// ).show()
} }
} }
@ -277,212 +280,212 @@ class DownloaderService : Service() {
} }
} }
private fun startDownload(videos: LinkedList<Video>) { private fun startDownload(videos: LinkedList<ResultItem>) {
if (videos.size == 0) { // if (videos.size == 0) {
finishService() // finishService()
return // return
} // }
val video: Video = try { // val video: ResultItem = try {
videos.peek() as Video // videos.peek() as ResultItem
} catch (e: Exception) { // } catch (e: Exception) {
finishService() // finishService()
return // return
} // }
try { // try {
for (activity in activities.keys) { // for (activity in activities.keys) {
activity.runOnUiThread { // activity.runOnUiThread {
for (i in activities[activity]!!.indices) { // for (i in activities[activity]!!.indices) {
val callback = activities[activity]!![i] // val callback = activities[activity]!![i]
callback.onDownloadStart(downloadInfo) // callback.onDownloadStart(downloadInfo)
} // }
} // }
} // }
} catch (err: Exception) { // } catch (err: Exception) {
err.printStackTrace() // err.printStackTrace()
} // }
val url = video.getURL() // val url = video.getURL()
val request = YoutubeDLRequest(url) // val request = YoutubeDLRequest(url)
val type = video.downloadedType // val type = video.downloadedType
val downloadLocation = getDownloadLocation(type) // val downloadLocation = getDownloadLocation(type)
//
var tempFileDir = File(cacheDir.absolutePath + """/${video.title}##${video.downloadedType}""") // var tempFileDir = File(cacheDir.absolutePath + """/${video.title}##${video.downloadedType}""")
tempFileDir.delete() // tempFileDir.delete()
tempFileDir.mkdir() // tempFileDir.mkdir()
//
val sharedPreferences = context!!.getSharedPreferences("root_preferences", MODE_PRIVATE) // val sharedPreferences = context!!.getSharedPreferences("root_preferences", MODE_PRIVATE)
val aria2 = sharedPreferences.getBoolean("aria2", false) // val aria2 = sharedPreferences.getBoolean("aria2", false)
if (aria2) { // if (aria2) {
request.addOption("--downloader", "libaria2c.so") // request.addOption("--downloader", "libaria2c.so")
request.addOption("--external-downloader-args", "aria2c:\"--summary-interval=1\"") // request.addOption("--external-downloader-args", "aria2c:\"--summary-interval=1\"")
} else { // } else {
val concurrentFragments = sharedPreferences.getInt("concurrent_fragments", 1) // val concurrentFragments = sharedPreferences.getInt("concurrent_fragments", 1)
if (concurrentFragments > 1) request.addOption("-N", concurrentFragments) // if (concurrentFragments > 1) request.addOption("-N", concurrentFragments)
} // }
val limitRate = sharedPreferences.getString("limit_rate", "") // val limitRate = sharedPreferences.getString("limit_rate", "")
if (limitRate != "") request.addOption("-r", limitRate!!) // if (limitRate != "") request.addOption("-r", limitRate!!)
val writeThumbnail = sharedPreferences.getBoolean("write_thumbnail", false) // val writeThumbnail = sharedPreferences.getBoolean("write_thumbnail", false)
if (writeThumbnail) { // if (writeThumbnail) {
request.addOption("--write-thumbnail") // request.addOption("--write-thumbnail")
request.addOption("--convert-thumbnails", "png") // request.addOption("--convert-thumbnails", "png")
} // }
request.addOption("--no-mtime") // request.addOption("--no-mtime")
val sponsorBlockFilters = sharedPreferences.getStringSet("sponsorblock_filters", emptySet()) // val sponsorBlockFilters = sharedPreferences.getStringSet("sponsorblock_filters", emptySet())
if (sponsorBlockFilters!!.isNotEmpty()) { // if (sponsorBlockFilters!!.isNotEmpty()) {
val filters = java.lang.String.join(",", sponsorBlockFilters) // val filters = java.lang.String.join(",", sponsorBlockFilters)
request.addOption("--sponsorblock-remove", filters) // request.addOption("--sponsorblock-remove", filters)
} // }
if (type == "audio") { // if (type == "audio") {
if (downloadLocation.equals(getString(R.string.music_path))){ // if (downloadLocation.equals(getString(R.string.music_path))){
tempFileDir = File(getString(R.string.music_path)) // tempFileDir = File(getString(R.string.music_path))
} // }
//
request.addOption("-x") // request.addOption("-x")
var format = video.audioFormat // var format = video.audioFormat
if (format == null) format = sharedPreferences.getString("audio_format", "") // if (format == null) format = sharedPreferences.getString("audio_format", "")
request.addOption("--audio-format", format!!) // request.addOption("--audio-format", format!!)
request.addOption("--embed-metadata") // request.addOption("--embed-metadata")
//
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false) // val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
if (embedThumb) { // if (embedThumb) {
request.addOption("--embed-thumbnail") // request.addOption("--embed-thumbnail")
request.addOption("--convert-thumbnails", "png") // request.addOption("--convert-thumbnails", "png")
try { // try {
val config = File(cacheDir, "config" + video.videoId + ".txt") // val config = File(cacheDir, "config" + video.videoId + ".txt")
val config_data = // val config_data =
"--ppa \"ffmpeg: -c:v png -vf crop=\\\"'if(gt(ih,iw),iw,ih)':'if(gt(iw,ih),ih,iw)'\\\"\"" // "--ppa \"ffmpeg: -c:v png -vf crop=\\\"'if(gt(ih,iw),iw,ih)':'if(gt(iw,ih),ih,iw)'\\\"\""
val stream = FileOutputStream(config) // val stream = FileOutputStream(config)
stream.write(config_data.toByteArray()) // stream.write(config_data.toByteArray())
stream.close() // stream.close()
request.addOption("--config", config.absolutePath) // request.addOption("--config", config.absolutePath)
} catch (ignored: java.lang.Exception) { // } catch (ignored: java.lang.Exception) {
} // }
} // }
request.addOption("--parse-metadata", "%(release_year,upload_date)s:%(meta_date)s") // request.addOption("--parse-metadata", "%(release_year,upload_date)s:%(meta_date)s")
request.addCommands(Arrays.asList("--replace-in-metadata", "title", ".*.", video.title)) // request.addCommands(Arrays.asList("--replace-in-metadata", "title", ".*.", video.title))
request.addCommands(Arrays.asList("--replace-in-metadata", "uploader", ".*.", video.author)) // request.addCommands(Arrays.asList("--replace-in-metadata", "uploader", ".*.", video.author))
//
if (!video.playlistTitle.isEmpty()) { // if (!video.playlistTitle.isEmpty()) {
request.addOption("--parse-metadata", "%(album,playlist,title)s:%(meta_album)s") // request.addOption("--parse-metadata", "%(album,playlist,title)s:%(meta_album)s")
request.addOption("--parse-metadata", "%(track_number,playlist_index)d:%(meta_track)s") // request.addOption("--parse-metadata", "%(track_number,playlist_index)d:%(meta_track)s")
} else { // } else {
request.addOption("--parse-metadata", "%(album,title)s:%(meta_album)s") // request.addOption("--parse-metadata", "%(album,title)s:%(meta_album)s")
} // }
request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s") // request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s")
} else if (type == "video") { // } else if (type == "video") {
if (downloadLocation.equals(getString(R.string.video_path))){ // if (downloadLocation.equals(getString(R.string.video_path))){
tempFileDir = File(getString(R.string.video_path)) // tempFileDir = File(getString(R.string.video_path))
} // }
//
val addChapters = sharedPreferences.getBoolean("add_chapters", false) // val addChapters = sharedPreferences.getBoolean("add_chapters", false)
if (addChapters) { // if (addChapters) {
request.addOption("--sponsorblock-mark", "all") // request.addOption("--sponsorblock-mark", "all")
} // }
val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false) // val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false)
if (embedSubs) { // if (embedSubs) {
request.addOption("--embed-subs", "") // request.addOption("--embed-subs", "")
} // }
var videoQuality = video.videoQuality // var videoQuality = video.videoQuality
if (videoQuality == null) videoQuality = // if (videoQuality == null) videoQuality =
sharedPreferences.getString("video_quality", "") // sharedPreferences.getString("video_quality", "")
var formatArgument = "bestvideo+bestaudio/best" // var formatArgument = "bestvideo+bestaudio/best"
if (videoQuality == "Worst Quality") { // if (videoQuality == "Worst Quality") {
formatArgument = "worst" // formatArgument = "worst"
} else if (!videoQuality!!.isEmpty() && videoQuality != "Best Quality") { // } else if (!videoQuality!!.isEmpty() && videoQuality != "Best Quality") {
formatArgument = "bestvideo[height<=" + videoQuality.substring( // formatArgument = "bestvideo[height<=" + videoQuality.substring(
0, // 0,
videoQuality.length - 1 // videoQuality.length - 1
) + "]+bestaudio/best" // ) + "]+bestaudio/best"
} // }
request.addOption("-f", formatArgument) // request.addOption("-f", formatArgument)
var format = video.videoFormat // var format = video.videoFormat
if (format == null) format = sharedPreferences.getString("video_format", "") // if (format == null) format = sharedPreferences.getString("video_format", "")
if (format != "DEFAULT") request.addOption("--merge-output-format", format!!) // if (format != "DEFAULT") request.addOption("--merge-output-format", format!!)
if (format != "webm") { // if (format != "webm") {
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false) // val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
if (embedThumb) { // if (embedThumb) {
request.addOption("--embed-thumbnail") // request.addOption("--embed-thumbnail")
} // }
} // }
request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s") // request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s")
} // }
//
val disposable = Observable.fromCallable { // val disposable = Observable.fromCallable {
YoutubeDL.getInstance().execute(request, downloadProcessID, callback) // YoutubeDL.getInstance().execute(request, downloadProcessID, callback)
} // }
.subscribeOn(Schedulers.newThread()) // .subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread()) // .observeOn(AndroidSchedulers.mainThread())
.subscribe({ // .subscribe({
val workTag = video.getURL() // val workTag = video.getURL()
val workData = workDataOf( // val workData = workDataOf(
originDir to tempFileDir.absolutePath, // originDir to tempFileDir.absolutePath,
downLocation to downloadLocation, // downLocation to downloadLocation,
title to video.title // title to video.title
) // )
val fileTransferWorkRequest = OneTimeWorkRequestBuilder<FileTransferWorker>() // val fileTransferWorkRequest = OneTimeWorkRequestBuilder<FileTransferWorker>()
.addTag(workTag) // .addTag(workTag)
.setInputData(workData) // .setInputData(workData)
.build() // .build()
workManager.enqueueUniqueWork( // workManager.enqueueUniqueWork(
workTag, // workTag,
ExistingWorkPolicy.KEEP, // ExistingWorkPolicy.KEEP,
fileTransferWorkRequest // fileTransferWorkRequest
) // )
//
downloadInfo.downloadPath = fileUtil.formatPath(getDownloadLocation(type)!!) // downloadInfo.downloadPath = fileUtil.formatPath(getDownloadLocation(type)!!)
Log.e(TAG, downloadInfo.downloadPath) // Log.e(TAG, downloadInfo.downloadPath)
downloadInfo.downloadType = type // downloadInfo.downloadType = type
//
//
//
try { // try {
for (activity in activities.keys) { // for (activity in activities.keys) {
activity.runOnUiThread { // activity.runOnUiThread {
for (i in activities[activity]!!.indices) { // for (i in activities[activity]!!.indices) {
val callback = activities[activity]!![i] // val callback = activities[activity]!![i]
callback.onDownloadEnd(downloadInfo) // callback.onDownloadEnd(downloadInfo)
} // }
} // }
} // }
} catch (e: Exception) { // } catch (e: Exception) {
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show() // Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
e.printStackTrace() // e.printStackTrace()
} // }
//
// SCAN NEXT IN QUEUE // // SCAN NEXT IN QUEUE
videos.remove() // videos.remove()
downloadInfo.downloadQueue = videos // downloadInfo.downloadQueue = videos
startDownload(videos) // startDownload(videos)
}) { e: Throwable? -> // }) { e: Throwable? ->
tempFileDir.delete() // tempFileDir.delete()
if (BuildConfig.DEBUG) { // if (BuildConfig.DEBUG) {
Toast.makeText(context, e!!.message, Toast.LENGTH_LONG).show() // Toast.makeText(context, e!!.message, Toast.LENGTH_LONG).show()
Log.e(TAG, getString(R.string.failed_download), e) // Log.e(TAG, getString(R.string.failed_download), e)
} // }
notificationUtil.updateDownloadNotification( // notificationUtil.updateDownloadNotification(
NotificationUtil.DOWNLOAD_NOTIFICATION_ID, // NotificationUtil.DOWNLOAD_NOTIFICATION_ID,
getString(R.string.failed_download), 0, 0, downloadQueue.peek()?.title, // getString(R.string.failed_download), 0, 0, downloadQueue.peek()?.title,
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID // NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
) // )
downloadInfo.downloadType = type // downloadInfo.downloadType = type
try { // try {
for (activity in activities.keys) { // for (activity in activities.keys) {
activity.runOnUiThread { // activity.runOnUiThread {
for (i in activities[activity]!!.indices) { // for (i in activities[activity]!!.indices) {
val callback = activities[activity]!![i] // val callback = activities[activity]!![i]
callback.onDownloadError(downloadInfo) // callback.onDownloadError(downloadInfo)
} // }
} // }
} // }
} catch (err: Exception) { // } catch (err: Exception) {
err.printStackTrace() // err.printStackTrace()
} // }
//
// SCAN NEXT IN QUEUE // // SCAN NEXT IN QUEUE
videos.remove() // videos.remove()
downloadInfo.downloadQueue = videos // downloadInfo.downloadQueue = videos
startDownload(videos) // startDownload(videos)
} // }
compositeDisposable.add(disposable) // compositeDisposable.add(disposable)
} }
private fun startCommandDownload(text: String?) { private fun startCommandDownload(text: String?) {

View file

@ -19,7 +19,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import com.deniscerri.ytdlnis.DownloaderService.LocalBinder import com.deniscerri.ytdlnis.DownloaderService.LocalBinder
import com.deniscerri.ytdlnis.database.DatabaseManager import com.deniscerri.ytdlnis.database.DatabaseManager
import com.deniscerri.ytdlnis.database.Video import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.databinding.ActivityMainBinding import com.deniscerri.ytdlnis.databinding.ActivityMainBinding
import com.deniscerri.ytdlnis.ui.DownloadsFragment import com.deniscerri.ytdlnis.ui.DownloadsFragment
import com.deniscerri.ytdlnis.ui.HomeFragment import com.deniscerri.ytdlnis.ui.HomeFragment
@ -193,7 +193,6 @@ class MainActivity : AppCompatActivity() {
.commit() .commit()
lastFragment = homeFragment lastFragment = homeFragment
listeners = ArrayList() listeners = ArrayList()
listeners.add(homeFragment.listener)
} }
private fun replaceFragment(f: Fragment) { private fun replaceFragment(f: Fragment) {
@ -202,37 +201,38 @@ class MainActivity : AppCompatActivity() {
} }
fun startDownloadService( fun startDownloadService(
downloadQueue: ArrayList<Video>, downloadQueue: ArrayList<ResultItem>,
awaitingListener: IDownloaderListener awaitingListener: IDownloaderListener
) { ) {
addQueueToDownloads(downloadQueue) // addQueueToDownloads(downloadQueue)
if (isDownloadServiceRunning) { // if (isDownloadServiceRunning) {
iDownloaderService?.updateQueue(downloadQueue) // iDownloaderService?.updateQueue(downloadQueue)
return // return
} // }
if (!listeners.contains(awaitingListener)) listeners.add(awaitingListener) // if (!listeners.contains(awaitingListener)) listeners.add(awaitingListener)
val serviceIntent = Intent(context, DownloaderService::class.java) // val serviceIntent = Intent(context, DownloaderService::class.java)
serviceIntent.putParcelableArrayListExtra("queue", downloadQueue) // serviceIntent.putParcelableArrayListExtra("queue", downloadQueue)
context.applicationContext.startService(serviceIntent) // context.applicationContext.startService(serviceIntent)
context.applicationContext.bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE) // context.applicationContext.bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE)
} }
private fun addQueueToDownloads(downloadQueue: ArrayList<Video>) { private fun addQueueToDownloads(downloadQueue: ArrayList<ResultItem>) {
try { // try {
val sharedPreferences = context.getSharedPreferences("root_preferences", MODE_PRIVATE) // val sharedPreferences = context.getSharedPreferences("root_preferences", MODE_PRIVATE)
if (!sharedPreferences.getBoolean("incognito", false)) { // if (!sharedPreferences.getBoolean("incognito", false)) {
val databaseManager = DatabaseManager(context) // val databaseManager = DatabaseManager(context)
for (i in downloadQueue.indices.reversed()) { // for (i in downloadQueue.indices.reversed()) {
val v = downloadQueue[i] // val v = downloadQueue[i]
v.isQueuedDownload = true // v.isQueuedDownload = true
databaseManager.addToHistory(v) // databaseManager.addToHistory(v)
} // }
databaseManager.close() // databaseManager.close()
//downloadsFragment.initCards() // //downloadsFragment.initCards()
} // }
} catch (e: Exception) { // } catch (e: Exception) {
e.printStackTrace() // e.printStackTrace()
} // }
} }
fun stopDownloadService() { fun stopDownloadService() {
@ -257,7 +257,7 @@ class MainActivity : AppCompatActivity() {
stopDownloadService() stopDownloadService()
} }
fun removeItemFromDownloadQueue(video: Video?, type: String?) { fun removeItemFromDownloadQueue(video: ResultItem?, type: String?) {
iDownloaderService!!.removeItemFromDownloadQueue(video, type) iDownloaderService!!.removeItemFromDownloadQueue(video, type)
} }

View file

@ -84,7 +84,6 @@ public class HistoryAdapter extends ListAdapter<HistoryItem, HistoryAdapter.View
@Override @Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) { public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
HistoryItem video = getItem(position); HistoryItem video = getItem(position);
Log.e("AAA", String.valueOf(position));
MaterialCardView card = holder.cardView; MaterialCardView card = holder.cardView;
// THUMBNAIL ---------------------------------- // THUMBNAIL ----------------------------------
ImageView thumbnail = card.findViewById(R.id.downloads_image_view); ImageView thumbnail = card.findViewById(R.id.downloads_image_view);

View file

@ -4,6 +4,7 @@ import android.app.Activity;
import android.graphics.Color; import android.graphics.Color;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -12,10 +13,12 @@ import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.deniscerri.ytdlnis.R; import com.deniscerri.ytdlnis.R;
import com.deniscerri.ytdlnis.database.Video; import com.deniscerri.ytdlnis.database.models.ResultItem;
import com.google.android.material.button.MaterialButton; import com.google.android.material.button.MaterialButton;
import com.google.android.material.card.MaterialCardView; import com.google.android.material.card.MaterialCardView;
import com.google.android.material.progressindicator.LinearProgressIndicator; import com.google.android.material.progressindicator.LinearProgressIndicator;
@ -23,19 +26,33 @@ import com.squareup.picasso.Picasso;
import java.util.ArrayList; import java.util.ArrayList;
public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.ViewHolder> { public class HomeAdapter extends ListAdapter<ResultItem, HomeAdapter.ViewHolder> {
private ArrayList<Video> videoList; private final ArrayList<Integer> checkedVideos;
private ArrayList<Integer> checkedVideos;
private final OnItemClickListener onItemClickListener; private final OnItemClickListener onItemClickListener;
private Activity activity; private Activity activity;
public HomeAdapter(ArrayList<Video> videos, OnItemClickListener onItemClickListener, Activity activity){ public HomeAdapter(HomeAdapter.OnItemClickListener onItemClickListener, Activity activity){
this.videoList = videos; super(DIFF_CALLBACK);
this.checkedVideos = new ArrayList<>(); this.checkedVideos = new ArrayList<>();
this.onItemClickListener = onItemClickListener; this.onItemClickListener = onItemClickListener;
this.activity = activity; this.activity = activity;
Log.e("TAG", "adapter");
} }
private static final DiffUtil.ItemCallback<ResultItem> DIFF_CALLBACK = new DiffUtil.ItemCallback<ResultItem>() {
@Override
public boolean areItemsTheSame(@NonNull ResultItem oldItem, @NonNull ResultItem newItem) {
Log.e("TAG", "adapter2");
return oldItem.getId() == newItem.getId();
}
@Override
public boolean areContentsTheSame(@NonNull ResultItem oldItem, @NonNull ResultItem newItem) {
Log.e("TAG", "adapter3");
return oldItem.getUrl().equals(newItem.getUrl());
}
};
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
return super.getItemViewType(position); return super.getItemViewType(position);
@ -61,8 +78,8 @@ public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.ViewHolder> {
@Override @Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) { public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Video video = videoList.get(position); ResultItem video = getItem(position);
Log.e("TAG", "adapter4");
MaterialCardView card = holder.cardView; MaterialCardView card = holder.cardView;
// THUMBNAIL ---------------------------------- // THUMBNAIL ----------------------------------
ImageView thumbnail = card.findViewById(R.id.result_image_view); ImageView thumbnail = card.findViewById(R.id.result_image_view);
@ -97,7 +114,7 @@ public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.ViewHolder> {
} }
// BUTTONS ---------------------------------- // BUTTONS ----------------------------------
String videoID = video.getVideoId(); int videoID = video.getId();
LinearLayout buttonLayout = card.findViewById(R.id.download_button_layout); LinearLayout buttonLayout = card.findViewById(R.id.download_button_layout);
@ -116,39 +133,42 @@ public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.ViewHolder> {
LinearProgressIndicator progressBar = card.findViewById(R.id.download_progress); LinearProgressIndicator progressBar = card.findViewById(R.id.download_progress);
progressBar.setTag(videoID + "##progress"); progressBar.setTag(videoID + "##progress");
progressBar.setProgress(0);
progressBar.setIndeterminate(true);
progressBar.setVisibility(View.GONE);
if (video.isDownloading()){ // if (video.isDownloading()){
progressBar.setVisibility(View.VISIBLE); // progressBar.setVisibility(View.VISIBLE);
}else { // }else {
progressBar.setProgress(0); // progressBar.setProgress(0);
progressBar.setIndeterminate(true); // progressBar.setIndeterminate(true);
progressBar.setVisibility(View.GONE); // progressBar.setVisibility(View.GONE);
} // }
//
if (video.isDownloadingAudio()) { // if (video.isDownloadingAudio()) {
musicBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_cancel)); // musicBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_cancel));
musicBtn.setTag(R.id.cancelDownload, "true"); // musicBtn.setTag(R.id.cancelDownload, "true");
}else{ // }else{
if(video.isAudioDownloaded() == 1){ // if(video.isAudioDownloaded() == 1){
musicBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded)); // musicBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded));
}else{ // }else{
musicBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_music)); // musicBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_music));
} // }
} // }
//
if (video.isDownloadingVideo()){ // if (video.isDownloadingVideo()){
videoBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_cancel)); // videoBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_cancel));
videoBtn.setTag(R.id.cancelDownload, "true"); // videoBtn.setTag(R.id.cancelDownload, "true");
}else{ // }else{
if(video.isVideoDownloaded() == 1){ // if(video.isVideoDownloaded() == 1){
videoBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded)); // videoBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded));
}else{ // }else{
videoBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_video)); // videoBtn.setIcon(ContextCompat.getDrawable(activity, R.drawable.ic_video));
} // }
} // }
if(checkedVideos.contains(position)){ if(checkedVideos.contains(videoID)){
card.setChecked(true); card.setChecked(true);
card.setStrokeWidth(5); card.setStrokeWidth(5);
}else{ }else{
@ -158,41 +178,32 @@ public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.ViewHolder> {
card.setTag(videoID + "##card"); card.setTag(videoID + "##card");
card.setOnLongClickListener(view -> { card.setOnLongClickListener(view -> {
checkCard(card, position); checkCard(card, videoID);
return true; return true;
}); });
card.setOnClickListener(view -> { card.setOnClickListener(view -> {
if(checkedVideos.size() > 0){ if(checkedVideos.size() > 0){
checkCard(card, position); checkCard(card, videoID);
} }
}); });
} }
private void checkCard(MaterialCardView card, int position){ private void checkCard(MaterialCardView card, int videoID){
if(card.isChecked()){ if(card.isChecked()){
card.setStrokeWidth(0); card.setStrokeWidth(0);
checkedVideos.remove(Integer.valueOf(position)); checkedVideos.remove(Integer.valueOf(videoID));
}else{ }else{
card.setStrokeWidth(5); card.setStrokeWidth(5);
checkedVideos.add(position); checkedVideos.add(videoID);
} }
card.setChecked(!card.isChecked()); card.setChecked(!card.isChecked());
onItemClickListener.onCardClick(position, card.isChecked()); onItemClickListener.onCardClick(videoID, card.isChecked());
} }
@Override
public int getItemCount() {
return videoList.size();
}
public interface OnItemClickListener { public interface OnItemClickListener {
void onButtonClick(int position, String type); void onButtonClick(int videoID, String type);
void onCardClick(int position, boolean add); void onCardClick(int videoID, boolean add);
}
public void updateVideoListItem(Video v, int position){
videoList.set(position, v);
notifyItemChanged(position);
} }
public void clearCheckedVideos(){ public void clearCheckedVideos(){
@ -203,16 +214,4 @@ public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.ViewHolder> {
} }
checkedVideos.clear(); checkedVideos.clear();
} }
public void clear(){
int size = videoList.size();
videoList = new ArrayList<>();
notifyItemRangeRemoved(0, size);
}
public void add(ArrayList<Video> vids){
int position = videoList.size() + 1;
videoList.addAll(vids);
notifyItemRangeInserted(position, vids.size());
}
} }

View file

@ -9,6 +9,8 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast; import android.widget.Toast;
import com.deniscerri.ytdlnis.R; import com.deniscerri.ytdlnis.R;
import com.deniscerri.ytdlnis.database.models.HistoryItem;
import com.deniscerri.ytdlnis.database.models.ResultItem;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@ -90,63 +92,63 @@ public class DatabaseManager extends SQLiteOpenHelper {
} }
@SuppressLint("Range") @SuppressLint("Range")
public void clearHistoryItem(Video video, boolean delete_file){ public void clearHistoryItem(HistoryItem video, boolean delete_file){
SQLiteDatabase db = this.getWritableDatabase(); // SQLiteDatabase db = this.getWritableDatabase();
//
if (delete_file){ // if (delete_file){
try{ // try{
Cursor cursor = db.rawQuery("SELECT * FROM " + history_table_name + " WHERE url='" + // Cursor cursor = db.rawQuery("SELECT * FROM " + history_table_name + " WHERE url='" +
video.getURL() + "' AND type='"+video.getDownloadedType() + "' LIMIT 1", null); // video.getURL() + "' AND type='"+video.getDownloadedType() + "' LIMIT 1", null);
//
if(cursor.moveToFirst()){ // if(cursor.moveToFirst()){
String path = cursor.getString(cursor.getColumnIndex(downloadPath)); // String path = cursor.getString(cursor.getColumnIndex(downloadPath));
File file = new File(path); // File file = new File(path);
if(file.exists()){ // if(file.exists()){
file.delete(); // file.delete();
} // }
} // }
}catch (Exception e){ // }catch (Exception e){
Toast.makeText(context, R.string.error_deleting_file, Toast.LENGTH_SHORT).show(); // Toast.makeText(context, R.string.error_deleting_file, Toast.LENGTH_SHORT).show();
} // }
} // }
//
//
db.execSQL("DELETE FROM " + history_table_name + " WHERE id=" + video.getId()); // db.execSQL("DELETE FROM " + history_table_name + " WHERE id=" + video.getId());
//
String where = ""; // String where = "";
switch(video.getDownloadedType()){ // switch(video.getDownloadedType()){
case "audio": // case "audio":
where = " SET downloadedAudio=0 WHERE downloadedAudio=1 AND videoId='" + video.getVideoId()+"'"; // where = " SET downloadedAudio=0 WHERE downloadedAudio=1 AND videoId='" + video.getVideoId()+"'";
break; // break;
case "video": // case "video":
where = " SET downloadedVideo=0 WHERE downloadedVideo=1 AND videoId='" + video.getVideoId()+"'"; // where = " SET downloadedVideo=0 WHERE downloadedVideo=1 AND videoId='" + video.getVideoId()+"'";
break; // break;
} // }
//
//remove downloaded status from results // //remove downloaded status from results
db.execSQL("UPDATE "+results_table_name+ where); // db.execSQL("UPDATE "+results_table_name+ where);
} }
public void clearDeletedHistory(){ public void clearDeletedHistory(){
ArrayList<Video> videos = getHistory("","","",""); // ArrayList<ResultItem> videos = getHistory("","","","");
for (int i = 0; i < videos.size(); i++){ // for (int i = 0; i < videos.size(); i++){
Video video = videos.get(i); // ResultItem video = videos.get(i);
String path = video.getDownloadPath(); // String path = video.getDownloadPath();
File file = new File(path); // File file = new File(path);
if(!file.exists() && !path.isEmpty()){ // if(!file.exists() && !path.isEmpty()){
clearHistoryItem(video, false); // clearHistoryItem(video, false);
} // }
} // }
} }
public void clearDownloadingHistory(){ public void clearDownloadingHistory(){
ArrayList<Video> videos = getHistory("","","",""); // ArrayList<ResultItem> videos = getHistory("","","","");
for (int i = 0; i < videos.size(); i++){ // for (int i = 0; i < videos.size(); i++){
Video video = videos.get(i); // ResultItem video = videos.get(i);
if(video.isQueuedDownload()){ // if(video.isQueuedDownload()){
clearHistoryItem(video, false); // clearHistoryItem(video, false);
} // }
} // }
} }
public void clearDuplicateHistory(){ public void clearDuplicateHistory(){
@ -176,36 +178,36 @@ public class DatabaseManager extends SQLiteOpenHelper {
@SuppressLint("Range") @SuppressLint("Range")
public ArrayList<Video> getResults(){ public ArrayList<ResultItem> getResults(){
SQLiteDatabase db = this.getReadableDatabase(); SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM " + results_table_name, null); Cursor cursor = db.rawQuery("SELECT * FROM " + results_table_name, null);
ArrayList<Video> list = new ArrayList<>(); ArrayList<ResultItem> list = new ArrayList<>();
if(cursor.moveToFirst()){ // if(cursor.moveToFirst()){
do { // do {
// on below line we are adding the data from cursor to our array list. // // on below line we are adding the data from cursor to our array list.
list.add(new Video(cursor.getString(cursor.getColumnIndex(videoId)), // list.add(new ResultItem(cursor.getString(cursor.getColumnIndex(videoId)),
cursor.getString(cursor.getColumnIndex(url)), // cursor.getString(cursor.getColumnIndex(url)),
cursor.getString(cursor.getColumnIndex(title)), // cursor.getString(cursor.getColumnIndex(title)),
cursor.getString(cursor.getColumnIndex(author)), // cursor.getString(cursor.getColumnIndex(author)),
cursor.getString(cursor.getColumnIndex(duration)), // cursor.getString(cursor.getColumnIndex(duration)),
cursor.getString(cursor.getColumnIndex(thumb)), // cursor.getString(cursor.getColumnIndex(thumb)),
cursor.getInt(cursor.getColumnIndex(downloadedAudio)), // cursor.getInt(cursor.getColumnIndex(downloadedAudio)),
cursor.getInt(cursor.getColumnIndex(downloadedVideo)), // cursor.getInt(cursor.getColumnIndex(downloadedVideo)),
cursor.getInt(cursor.getColumnIndex(isPlaylistItem)), // cursor.getInt(cursor.getColumnIndex(isPlaylistItem)),
cursor.getString(cursor.getColumnIndex(website)), // cursor.getString(cursor.getColumnIndex(website)),
cursor.getInt(cursor.getColumnIndex(downloadedAudio)), // cursor.getInt(cursor.getColumnIndex(downloadedAudio)),
cursor.getInt(cursor.getColumnIndex(downloadingVideo)), // cursor.getInt(cursor.getColumnIndex(downloadingVideo)),
cursor.getString(cursor.getColumnIndex(playlistTitle)))); // cursor.getString(cursor.getColumnIndex(playlistTitle))));
} while (cursor.moveToNext()); // } while (cursor.moveToNext());
} // }
//
cursor.close(); // cursor.close();
return list; return list;
} }
@SuppressLint("Range") @SuppressLint("Range")
public ArrayList<Video> getHistory(String query, String format, String site, String sort){ public ArrayList<ResultItem> getHistory(String query, String format, String site, String sort){
SQLiteDatabase db = this.getReadableDatabase(); SQLiteDatabase db = this.getReadableDatabase();
if (sort == null || sort.isEmpty()) sort = "DESC"; if (sort == null || sort.isEmpty()) sort = "DESC";
@ -215,91 +217,91 @@ public class DatabaseManager extends SQLiteOpenHelper {
" AND website LIKE '%"+site+"%'"+ " AND website LIKE '%"+site+"%'"+
" ORDER BY id "+sort, " ORDER BY id "+sort,
null); null);
ArrayList<Video> list = new ArrayList<>(); ArrayList<ResultItem> list = new ArrayList<>();
//
if(cursor.moveToFirst()){ // if(cursor.moveToFirst()){
do { // do {
// on below line we are adding the data from cursor to our array list. // // on below line we are adding the data from cursor to our array list.
list.add(new Video(cursor.getInt(cursor.getColumnIndex(id)), // list.add(new ResultItem(cursor.getInt(cursor.getColumnIndex(id)),
cursor.getString(cursor.getColumnIndex(url)), // cursor.getString(cursor.getColumnIndex(url)),
cursor.getString(cursor.getColumnIndex(title)), // cursor.getString(cursor.getColumnIndex(title)),
cursor.getString(cursor.getColumnIndex(author)), // cursor.getString(cursor.getColumnIndex(author)),
cursor.getString(cursor.getColumnIndex(duration)), // cursor.getString(cursor.getColumnIndex(duration)),
cursor.getString(cursor.getColumnIndex(thumb)), // cursor.getString(cursor.getColumnIndex(thumb)),
cursor.getString(cursor.getColumnIndex(type)), // cursor.getString(cursor.getColumnIndex(type)),
cursor.getString(cursor.getColumnIndex(time)), // cursor.getString(cursor.getColumnIndex(time)),
cursor.getString(cursor.getColumnIndex(downloadPath)), // cursor.getString(cursor.getColumnIndex(downloadPath)),
cursor.getString(cursor.getColumnIndex(website)), // cursor.getString(cursor.getColumnIndex(website)),
cursor.getInt(cursor.getColumnIndex(isQueuedDownload)))); // cursor.getInt(cursor.getColumnIndex(isQueuedDownload))));
} while (cursor.moveToNext()); // } while (cursor.moveToNext());
} // }
//
cursor.close(); // cursor.close();
return list; return list;
} }
public void addToResults(ArrayList<Video> videot){ public void addToResults(ArrayList<ResultItem> videot){
SQLiteDatabase db = this.getWritableDatabase(); SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
for(Video v : videot){ // for(ResultItem v : videot){
values.put(videoId, v.getVideoId()); // values.put(videoId, v.getVideoId());
values.put(url, v.getURL()); // values.put(url, v.getURL());
values.put(title, v.getTitle()); // values.put(title, v.getTitle());
values.put(author, v.getAuthor()); // values.put(author, v.getAuthor());
values.put(duration, v.getDuration()); // values.put(duration, v.getDuration());
values.put(thumb, v.getThumb()); // values.put(thumb, v.getThumb());
values.put(downloadedAudio, v.isAudioDownloaded()); // values.put(downloadedAudio, v.isAudioDownloaded());
values.put(downloadedVideo, v.isVideoDownloaded()); // values.put(downloadedVideo, v.isVideoDownloaded());
values.put(isPlaylistItem, v.getIsPlaylistItem()); // values.put(isPlaylistItem, v.getIsPlaylistItem());
values.put(website, v.getWebsite()); // values.put(website, v.getWebsite());
values.put(downloadingAudio, 0); // values.put(downloadingAudio, 0);
values.put(downloadingVideo, 0); // values.put(downloadingVideo, 0);
values.put(playlistTitle, v.getPlaylistTitle()); // values.put(playlistTitle, v.getPlaylistTitle());
//
db.insert(results_table_name, null, values); // db.insert(results_table_name, null, values);
} // }
//
db.close(); // db.close();
} }
public void addToHistory(Video v){ public void addToHistory(ResultItem v){
SQLiteDatabase db = this.getWritableDatabase(); SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
//
values.put(url, v.getURL()); // values.put(url, v.getURL());
values.put(title, v.getTitle()); // values.put(title, v.getTitle());
values.put(author, v.getAuthor()); // values.put(author, v.getAuthor());
values.put(duration, v.getDuration()); // values.put(duration, v.getDuration());
values.put(thumb, v.getThumb()); // values.put(thumb, v.getThumb());
values.put(type, v.getDownloadedType()); // values.put(type, v.getDownloadedType());
values.put(time, v.getDownloadedTime()); // values.put(time, v.getDownloadedTime());
values.put(downloadPath, v.getDownloadPath()); // values.put(downloadPath, v.getDownloadPath());
values.put(website, v.getWebsite()); // values.put(website, v.getWebsite());
values.put(isQueuedDownload, (v.isQueuedDownload()) ? 1 : 0); // values.put(isQueuedDownload, (v.isQueuedDownload()) ? 1 : 0);
//
db.insert(history_table_name, null, values); // db.insert(history_table_name, null, values);
db.close(); // db.close();
} }
public void updateHistoryItem(Video v){ public void updateHistoryItem(ResultItem v){
SQLiteDatabase db = this.getWritableDatabase(); SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(url, v.getURL()); // values.put(url, v.getURL());
values.put(title, v.getTitle()); // values.put(title, v.getTitle());
values.put(author, v.getAuthor()); // values.put(author, v.getAuthor());
values.put(duration, v.getDuration()); // values.put(duration, v.getDuration());
values.put(thumb, v.getThumb()); // values.put(thumb, v.getThumb());
values.put(type, v.getDownloadedType()); // values.put(type, v.getDownloadedType());
values.put(time, v.getDownloadedTime()); // values.put(time, v.getDownloadedTime());
values.put(downloadPath, v.getDownloadPath()); // values.put(downloadPath, v.getDownloadPath());
values.put(website, v.getWebsite()); // values.put(website, v.getWebsite());
values.put(isQueuedDownload, (v.isQueuedDownload()) ? 1 : 0); // values.put(isQueuedDownload, (v.isQueuedDownload()) ? 1 : 0);
//
String where = url + "='"+v.getURL()+"' AND "+isQueuedDownload+"=1 AND "+type+"='"+v.getDownloadedType()+"'"; // String where = url + "='"+v.getURL()+"' AND "+isQueuedDownload+"=1 AND "+type+"='"+v.getDownloadedType()+"'";
db.update(history_table_name, values, where, null); // db.update(history_table_name, values, where, null);
db.close(); // db.close();
} }
public void updateDownloadStatusOnResult(String id, String type, boolean downloaded){ public void updateDownloadStatusOnResult(String id, String type, boolean downloaded){

View file

@ -1,338 +0,0 @@
package com.deniscerri.ytdlnis.database;
import android.os.Parcel;
import android.os.Parcelable;
public class Video implements Parcelable, Cloneable {
private int id;
private String videoId;
private String title;
private String author;
private String duration;
private String thumb;
private String url;
private String downloadedType;
private int downloadedAudio;
private int downloadedVideo;
private String downloadedTime;
private int isPlaylistItem;
private String downloadPath;
private String website;
private boolean downloadingAudio;
private boolean downloadingVideo;
private boolean queuedDownload;
private String playlistTitle;
private String audioFormat;
private String videoFormat;
private String videoQuality;
// RESULTS OBJECT
public Video(String videoId, String url, String title, String author, String duration, String thumb,
int downloadedAudio, int downloadedVideo, int isPlaylistItem, String website, int downloadingAudio, int downloadingVideo, String playlistTitle) {
this.videoId = videoId;
this.url = url;
this.title = title;
this.author = author;
this.duration = duration;
this.thumb = thumb;
this.downloadedVideo = downloadedVideo;
this.downloadedAudio = downloadedAudio;
this.isPlaylistItem = isPlaylistItem;
this.website = website;
this.downloadingAudio = intToBoolean(downloadingAudio);
this.downloadingVideo = intToBoolean(downloadingVideo);
this.playlistTitle = playlistTitle;
}
//HISTORY OBJECT
public Video(int id, String url, String title, String author, String duration, String thumb,
String downloadedType, String downloadedTime, String downloadPath, String website, int queued) {
this.id = id;
this.url = url;
this.title = title;
this.author = author;
this.duration = duration;
this.thumb = thumb;
this.downloadedType = downloadedType;
this.downloadedTime = downloadedTime;
this.downloadPath = downloadPath;
this.website = website;
this.queuedDownload = (queued == 1);
}
private boolean intToBoolean(int i){
return i == 1;
}
protected Video(Parcel in) {
id = in.readInt();
videoId = in.readString();
title = in.readString();
author = in.readString();
duration = in.readString();
thumb = in.readString();
url = in.readString();
downloadedType = in.readString();
downloadedAudio = in.readInt();
downloadedVideo = in.readInt();
downloadedTime = in.readString();
isPlaylistItem = in.readInt();
downloadPath = in.readString();
website = in.readString();
playlistTitle = in.readString();
audioFormat = in.readString();
videoFormat = in.readString();
videoQuality = in.readString();
}
public static final Creator<Video> CREATOR = new Creator<Video>() {
@Override
public Video createFromParcel(Parcel in) {
return new Video(in);
}
@Override
public Video[] newArray(int size) {
return new Video[size];
}
};
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getVideoId() {
return videoId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public String getDuration() {
return duration;
}
public String getThumb() {
return thumb;
}
public String getDownloadedType() {
return downloadedType;
}
public void setDownloadedType(String downloadedType) {
this.downloadedType = downloadedType;
}
public String getDownloadedTime() {
return downloadedTime;
}
public void setDownloadedTime(String downloadedTime) {
this.downloadedTime = downloadedTime;
}
public int getIsPlaylistItem() {
return isPlaylistItem;
}
public void setIsPlaylistItem(int playlistItem) {
this.isPlaylistItem = playlistItem;
}
public int isAudioDownloaded() {
return downloadedAudio;
}
public int isVideoDownloaded() {
return downloadedVideo;
}
public String getURL(){ return url; }
public void setURL(String url) { this.url = url;}
public String getWebsite() { return website; }
public void setWebsite(String site){ this.website = site; }
public void setVideoId(String videoId) {
this.videoId = videoId;
}
public void setAuthor(String author) {
this.author = author;
}
public void setDuration(String duration) {
this.duration = duration;
}
public void setThumb(String thumb) {
this.thumb = thumb;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getDownloadedAudio() {
return downloadedAudio;
}
public void setDownloadedAudio(int downloadedAudio) {
this.downloadedAudio = downloadedAudio;
}
public int getDownloadedVideo() {
return downloadedVideo;
}
public void setDownloadedVideo(int downloadedVideo) {
this.downloadedVideo = downloadedVideo;
}
public String getDownloadPath() {
return downloadPath;
}
public void setDownloadPath(String downloadPath) {
this.downloadPath = downloadPath;
}
public boolean isDownloadingAudio() {
return downloadingAudio;
}
public void setDownloadingAudio(boolean downloadingAudio) {
this.downloadingAudio = downloadingAudio;
}
public boolean isDownloadingVideo() {
return downloadingVideo;
}
public void setDownloadingVideo(boolean downloadingVideo) {
this.downloadingVideo = downloadingVideo;
}
public boolean isDownloading() {
return this.downloadingAudio || this.downloadingVideo;
}
public String getPlaylistTitle() {
return playlistTitle;
}
public void setPlaylistTitle(String playlistTitle) {
this.playlistTitle = playlistTitle;
}
public boolean isQueuedDownload() {
return queuedDownload;
}
public void setQueuedDownload(boolean queuedDownload) {
this.queuedDownload = queuedDownload;
}
public String getAudioFormat() {
return audioFormat;
}
public void setAudioFormat(String audioFormat) {
this.audioFormat = audioFormat;
}
public String getVideoFormat() {
return videoFormat;
}
public void setVideoFormat(String videoFormat) {
this.videoFormat = videoFormat;
}
public String getVideoQuality() {
return videoQuality;
}
public void setVideoQuality(String videoQuality) {
this.videoQuality = videoQuality;
}
public Object clone() throws CloneNotSupportedException
{
return super.clone();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(id);
parcel.writeString(videoId);
parcel.writeString(title);
parcel.writeString(author);
parcel.writeString(duration);
parcel.writeString(thumb);
parcel.writeString(url);
parcel.writeString(downloadedType);
parcel.writeInt(downloadedAudio);
parcel.writeInt(downloadedVideo);
parcel.writeString(downloadedTime);
parcel.writeInt(isPlaylistItem);
parcel.writeString(downloadPath);
parcel.writeString(website);
parcel.writeString(playlistTitle);
parcel.writeString(audioFormat);
parcel.writeString(videoFormat);
parcel.writeString(videoQuality);
}
@Override
public String toString() {
return "Video{" +
"id=" + id +
", videoId='" + videoId + '\'' +
", title='" + title + '\'' +
", author='" + author + '\'' +
", duration='" + duration + '\'' +
", thumb='" + thumb + '\'' +
", url='" + url + '\'' +
", downloadedType='" + downloadedType + '\'' +
", downloadedAudio=" + downloadedAudio +
", downloadedVideo=" + downloadedVideo +
", downloadedTime='" + downloadedTime + '\'' +
", isPlaylistItem=" + isPlaylistItem +
", downloadPath='" + downloadPath + '\'' +
", website='" + website + '\'' +
", downloadingAudio=" + downloadingAudio +
", downloadingVideo=" + downloadingVideo +
", queuedDownload=" + queuedDownload +
", playlistTitle='" + playlistTitle + '\'' +
", audioFormat='" + audioFormat + '\'' +
", videoFormat='" + videoFormat + '\'' +
", videoQuality='" + videoQuality + '\'' +
'}';
}
}

View file

@ -10,7 +10,7 @@ import com.deniscerri.ytdlnis.util.FileUtil
interface DownloadDao { interface DownloadDao {
@Query("SELECT * FROM downloads") @Query("SELECT * FROM downloads")
fun getAllDownloads() : List<DownloadItem> fun getAllDownloads() : LiveData<List<DownloadItem>>
@Query("SELECT * FROM downloads WHERE status='Queued'") @Query("SELECT * FROM downloads WHERE status='Queued'")
fun getQueuedDownloads() : List<DownloadItem> fun getQueuedDownloads() : List<DownloadItem>

View file

@ -4,10 +4,11 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
@Entity(tableName = "downloads") @Entity(tableName = "commandTemplates")
data class CommandTemplate( data class CommandTemplate(
@PrimaryKey(autoGenerate = true)
val id: Int,
val title: String, val title: String,
val content: String val content: String
) ){
@PrimaryKey(autoGenerate = true)
var id: Int? = null
}

View file

@ -6,8 +6,6 @@ import androidx.room.PrimaryKey
@Entity(tableName = "downloads") @Entity(tableName = "downloads")
data class DownloadItem( data class DownloadItem(
@PrimaryKey(autoGenerate = true)
val id: Int,
val url: String, val url: String,
val title: String, val title: String,
val author: String, val author: String,
@ -28,4 +26,7 @@ data class DownloadItem(
val playlistTitle: String, val playlistTitle: String,
@ColumnInfo(defaultValue = "Queued") @ColumnInfo(defaultValue = "Queued")
var status: String var status: String
) ){
@PrimaryKey(autoGenerate = true)
var id: Int? = null
}

View file

@ -8,13 +8,14 @@ import com.yausername.youtubedl_android.mapper.VideoInfo
@Entity(tableName = "results") @Entity(tableName = "results")
data class ResultItem( data class ResultItem(
@PrimaryKey(autoGenerate = true)
val id: Int,
val url: String, val url: String,
val title: String, val title: String,
val author: String, val author: String,
val duration: String, val duration: String,
val thumb: String, val thumb: String,
val website: String, val website: String,
val playlistTitle: String var playlistTitle: String
) ){
@PrimaryKey(autoGenerate = true)
var id: Int? = null
}

View file

@ -5,6 +5,7 @@ import com.deniscerri.ytdlnis.database.dao.DownloadDao
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
class DownloadRepository(private val downloadDao: DownloadDao) { class DownloadRepository(private val downloadDao: DownloadDao) {
val allDownloads : LiveData<List<DownloadItem>> = downloadDao.getAllDownloads()
suspend fun insert(item: DownloadItem){ suspend fun insert(item: DownloadItem){
downloadDao.insert(item) downloadDao.insert(item)
@ -19,7 +20,7 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
} }
suspend fun getQueuedDownloads() : List<DownloadItem>{ suspend fun getQueuedDownloads() : List<DownloadItem>{
var items = downloadDao.getQueuedDownloads(); val items = downloadDao.getQueuedDownloads()
for (i in items){ for (i in items){
i.status = "Downloading" i.status = "Downloading"
downloadDao.update(i) downloadDao.update(i)

View file

@ -30,7 +30,7 @@ class HistoryRepository(private val historyDao: HistoryDao) {
} }
suspend fun delete(item: HistoryItem, deleteFile: Boolean){ suspend fun delete(item: HistoryItem, deleteFile: Boolean){
historyDao.delete(item.id) historyDao.delete(item.id!!)
if (deleteFile){ if (deleteFile){
val fileUtil = FileUtil() val fileUtil = FileUtil()
fileUtil.deleteFile(item.downloadPath) fileUtil.deleteFile(item.downloadPath)
@ -53,7 +53,7 @@ class HistoryRepository(private val historyDao: HistoryDao) {
val fileUtil = FileUtil() val fileUtil = FileUtil()
items.value?.forEach { item -> items.value?.forEach { item ->
if (!fileUtil.exists(item.downloadPath)){ if (!fileUtil.exists(item.downloadPath)){
historyDao.delete(item.id) historyDao.delete(item.id!!)
} }
} }
} }

View file

@ -1,17 +1,26 @@
package com.deniscerri.ytdlnis.database.repository package com.deniscerri.ytdlnis.database.repository
import android.content.Context
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import com.deniscerri.ytdlnis.database.dao.DownloadDao import com.deniscerri.ytdlnis.database.dao.DownloadDao
import com.deniscerri.ytdlnis.database.dao.ResultDao import com.deniscerri.ytdlnis.database.dao.ResultDao
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ResultItem import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.util.InfoUtil
class ResultRepository(private val resultDao: ResultDao) { class ResultRepository(private val resultDao: ResultDao) {
val allResults : LiveData<List<ResultItem>> = resultDao.getResults() val allResults : LiveData<List<ResultItem>> = resultDao.getResults()
suspend fun insert(items: List<ResultItem>){ suspend fun insert(it: ResultItem){
items.forEach { resultDao.insert(it)
resultDao.insert(it) }
suspend fun updateTrending(context: Context){
resultDao.deleteAll();
val infoUtil = InfoUtil(context)
val items = infoUtil.getTrending(context)
for (i in items){
resultDao.insert(i!!);
} }
} }

View file

@ -3,27 +3,37 @@ package com.deniscerri.ytdlnis.database.viewmodel
import android.app.Application import android.app.Application
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.deniscerri.ytdlnis.database.DBManager import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.models.ResultItem import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.repository.ResultRepository import com.deniscerri.ytdlnis.database.repository.ResultRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class ResultViewModel(application: Application) : AndroidViewModel(application) { class ResultViewModel(application: Application) : AndroidViewModel(application) {
private val repository : ResultRepository private val repository : ResultRepository
private val allResults : LiveData<List<ResultItem>> val items : LiveData<List<ResultItem>>
init { init {
val dao = DBManager.getInstance(application).resultDao val dao = DBManager.getInstance(application).resultDao
repository = ResultRepository(dao) repository = ResultRepository(dao)
allResults = repository.allResults items = repository.allResults
} }
fun insert(items: List<ResultItem>) = viewModelScope.launch(Dispatchers.IO){ fun checkTrending() : Boolean{
repository.insert(items) return items.value?.get(0)?.playlistTitle.equals("ytdlnis-TRENDING");
}
fun getTrending() = viewModelScope.launch(Dispatchers.IO){
repository.updateTrending(getApplication<Application>().applicationContext);
}
fun insert(items: ArrayList<ResultItem?>) = viewModelScope.launch(Dispatchers.IO){
items.forEach {
repository.insert(it!!)
}
} }
fun deleteAll() = viewModelScope.launch(Dispatchers.IO) { fun deleteAll() = viewModelScope.launch(Dispatchers.IO) {

View file

@ -1,13 +1,13 @@
package com.deniscerri.ytdlnis.service; package com.deniscerri.ytdlnis.service;
import com.deniscerri.ytdlnis.database.Video; import com.deniscerri.ytdlnis.database.models.ResultItem;
import java.util.LinkedList; import java.util.LinkedList;
public class DownloadInfo { public class DownloadInfo {
private Video video; private ResultItem video;
private int progress; private int progress;
private LinkedList<Video> downloadQueue; private LinkedList<ResultItem> downloadQueue;
private String outputLine; private String outputLine;
private String downloadStatus; private String downloadStatus;
private String downloadPath; private String downloadPath;
@ -15,11 +15,11 @@ public class DownloadInfo {
public DownloadInfo(){} public DownloadInfo(){}
public Video getVideo() { public ResultItem getVideo() {
return video; return video;
} }
public void setVideo(Video video) { public void setVideo(ResultItem video) {
this.video = video; this.video = video;
} }
@ -31,11 +31,11 @@ public class DownloadInfo {
this.progress = progress; this.progress = progress;
} }
public LinkedList<Video> getDownloadQueue() { public LinkedList<ResultItem> getDownloadQueue() {
return downloadQueue; return downloadQueue;
} }
public void setDownloadQueue(LinkedList<Video> downloadQueue) { public void setDownloadQueue(LinkedList<ResultItem> downloadQueue) {
this.downloadQueue = downloadQueue; this.downloadQueue = downloadQueue;
this.video = downloadQueue.peek(); this.video = downloadQueue.peek();
} }

View file

@ -1,7 +1,5 @@
package com.deniscerri.ytdlnis.service; package com.deniscerri.ytdlnis.service;
import com.deniscerri.ytdlnis.database.Video;
public interface IDownloaderListener { public interface IDownloaderListener {
void onDownloadStart(DownloadInfo downloadInfo); void onDownloadStart(DownloadInfo downloadInfo);
void onDownloadProgress(DownloadInfo downloadInfo); void onDownloadProgress(DownloadInfo downloadInfo);

View file

@ -1,14 +1,16 @@
package com.deniscerri.ytdlnis.service; package com.deniscerri.ytdlnis.service;
import android.app.Activity; import android.app.Activity;
import com.deniscerri.ytdlnis.database.Video;
import com.deniscerri.ytdlnis.database.models.ResultItem;
import java.util.ArrayList; import java.util.ArrayList;
public interface IDownloaderService { public interface IDownloaderService {
DownloadInfo getInfo(); DownloadInfo getInfo();
void addActivity(Activity activity, ArrayList<IDownloaderListener> callback); void addActivity(Activity activity, ArrayList<IDownloaderListener> callback);
void removeActivity(Activity activity); void removeActivity(Activity activity);
void updateQueue(ArrayList<Video> queue); void updateQueue(ArrayList<ResultItem> queue);
void cancelDownload(boolean cancelAll); void cancelDownload(boolean cancelAll);
void removeItemFromDownloadQueue(Video video, String type); void removeItemFromDownloadQueue(ResultItem video, String type);
} }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,921 @@
package com.deniscerri.ytdlnis.ui
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.text.InputType
import android.util.Log
import android.view.*
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.*
import androidx.appcompat.widget.SearchView
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.HomeAdapter
import com.deniscerri.ytdlnis.database.DatabaseManager
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.databinding.FragmentDownloadsBinding
import com.deniscerri.ytdlnis.service.DownloadInfo
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.InfoUtil
import com.facebook.shimmer.ShimmerFrameLayout
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton
import com.google.android.material.chip.ChipGroup
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.textfield.TextInputLayout
import java.util.*
import java.util.regex.Pattern
import kotlin.collections.ArrayList
class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickListener {
private var progressBar: LinearProgressIndicator? = null
private var inputQuery: String? = null
private var inputQueries: LinkedList<String?>? = null
private var inputQueriesLength = 0
private var homeAdapter: HomeAdapter? = null
private var searchSuggestions: ScrollView? = null
private var searchSuggestionsLinearLayout: LinearLayout? = null
private var downloadFabs: CoordinatorLayout? = null
private var downloadAllFabCoordinator: CoordinatorLayout? = null
private var homeFabs: CoordinatorLayout? = null
private var infoUtil: InfoUtil? = null
private var downloadQueue: ArrayList<ResultItem>? = null
private var downloadInfo: DownloadInfo? = null
private lateinit var resultViewModel : ResultViewModel
private var downloading = false
private var fragmentView: View? = null
private var databaseManager: DatabaseManager? = null
private var activity: Activity? = null
private var mainActivity: MainActivity? = null
private var fragmentContext: Context? = null
private var layoutinflater: LayoutInflater? = null
private var shimmerCards: ShimmerFrameLayout? = null
private var topAppBar: MaterialToolbar? = null
private var recyclerView: RecyclerView? = null
private var bottomSheet: BottomSheetDialog? = null
private var sortSheet: BottomSheetDialog? = null
private var uiHandler: Handler? = null
private var noResults: RelativeLayout? = null
private var selectionChips: LinearLayout? = null
private var websiteGroup: ChipGroup? = null
private var resultsList: List<ResultItem?>? = null
private var selectedObjects: ArrayList<ResultItem>? = null
private var deleteFab: ExtendedFloatingActionButton? = null
private var fileUtil: FileUtil? = null
private var _binding : FragmentDownloadsBinding? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentDownloadsBinding.inflate(inflater, container, false)
fragmentView = inflater.inflate(R.layout.fragment_home, container, false)
activity = getActivity()
mainActivity = activity as MainActivity?
return fragmentView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
fragmentContext = context
layoutinflater = LayoutInflater.from(context)
shimmerCards = view.findViewById(R.id.shimmer_downloads_framelayout)
topAppBar = view.findViewById(R.id.downloads_toolbar)
noResults = view.findViewById(R.id.downloads_no_results)
selectionChips = view.findViewById(R.id.downloads_selection_chips)
websiteGroup = view.findViewById(R.id.website_chip_group)
deleteFab = view.findViewById(R.id.delete_selected_fab)
fileUtil = FileUtil()
deleteFab?.tag = "deleteSelected"
deleteFab?.setOnClickListener(this)
uiHandler = Handler(Looper.getMainLooper())
selectedObjects = ArrayList()
downloading = mainActivity!!.isDownloadServiceRunning()
downloadQueue = ArrayList()
resultsList = mutableListOf()
selectedObjects = ArrayList()
//initViews
shimmerCards = view.findViewById(R.id.shimmer_results_framelayout)
topAppBar = view.findViewById(R.id.home_toolbar)
searchSuggestions = view.findViewById(R.id.search_suggestions_scroll_view)
searchSuggestionsLinearLayout = view.findViewById(R.id.search_suggestions_linear_layout)
homeAdapter =
HomeAdapter(
this,
activity
)
recyclerView = view.findViewById(R.id.recyclerViewHome)
recyclerView?.layoutManager = LinearLayoutManager(context)
recyclerView?.adapter = homeAdapter
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
resultViewModel.items.observe(viewLifecycleOwner) {
homeAdapter!!.submitList(it)
resultsList = it
shimmerCards!!.stopShimmer()
shimmerCards!!.visibility = GONE
}
initMenu()
homeFabs = view.findViewById(R.id.home_fabs)
downloadFabs = homeFabs!!.findViewById(R.id.download_selected_coordinator)
downloadAllFabCoordinator = homeFabs!!.findViewById(R.id.download_all_coordinator)
val musicFab = downloadFabs!!.findViewById<FloatingActionButton>(R.id.audio_fab)
val videoFab = downloadFabs!!.findViewById<FloatingActionButton>(R.id.video_fab)
musicFab.tag = "SELECT##audio"
videoFab.tag = "SELECT##video"
musicFab.setOnClickListener(this)
videoFab.setOnClickListener(this)
val downloadAllFab =
downloadAllFabCoordinator!!.findViewById<ExtendedFloatingActionButton>(R.id.download_all_fab)
downloadAllFab.tag = "downloadAll"
downloadAllFab.setOnClickListener(this)
if (inputQueries != null) {
resultViewModel.deleteAll()
inputQueriesLength = inputQueries!!.size
shimmerCards!!.startShimmer()
shimmerCards!!.visibility = VISIBLE
val thread = Thread {
while (!inputQueries!!.isEmpty()) {
inputQuery = inputQueries!!.pop()
parseQuery(false)
}
try {
Handler(Looper.getMainLooper()).post {
// DOWNLOAD ALL BUTTON
if (resultsList!!.size > 1 || inputQueriesLength > 1) {
downloadAllFabCoordinator!!.visibility = VISIBLE
}
// databaseManager = DatabaseManager(context)
// databaseManager!!.clearResults()
// for (v in resultsList!!) v!!.isPlaylistItem = 1
// databaseManager!!.addToResults(resultsList)
}
} catch (ignored: Exception) {
}
}
thread.start()
} else {
if (resultViewModel.checkTrending()){
shimmerCards!!.startShimmer()
shimmerCards!!.visibility = VISIBLE
resultViewModel.getTrending()
}
}
}
//
// private fun initCards() {
// val uiHandler = Handler(Looper.getMainLooper())
// try {
// val thread = Thread {
// databaseManager = DatabaseManager(context)
// resultsList = databaseManager!!.results
// var playlistTitle = ""
// try {
// playlistTitle = resultsList.get(0).playlistTitle
// } catch (ignored: Exception) {
// }
// if (resultsList.size == 0 || playlistTitle == getString(R.string.trendingPlaylist) && !downloading) {
// try {
// databaseManager!!.clearResults()
// uiHandler.post {
// shimmerCards!!.startShimmer()
// shimmerCards!!.visibility = View.VISIBLE
// }
// infoUtil = InfoUtil(context!!)
// resultsList = infoUtil!!.getTrending(context!!)
// databaseManager!!.addToResults(resultsList)
// } catch (e: Exception) {
// Log.e(TAG, e.toString())
// }
// } else {
// if (!downloading) {
// homeAdapter!!.add(resultsList)
// for (i in resultsList.indices) {
// val tmp = resultsList.get(i)
// if (tmp!!.isDownloading) {
// updateDownloadingStatusOnResult(tmp, "audio", false)
// updateDownloadingStatusOnResult(tmp, "video", false)
// }
// }
// }
// }
// uiHandler.post {
// if (homeAdapter!!.itemCount != resultsList.size) {
// homeAdapter!!.add(resultsList)
// }
// shimmerCards!!.stopShimmer()
// shimmerCards!!.visibility = View.GONE
// }
// databaseManager!!.close()
// if (resultsList != null) {
// uiHandler.post { scrollToTop() }
// if (resultsList!!.size > 1 && resultsList!![1]!!.isPlaylistItem == 1) {
// uiHandler.post { downloadAllFabCoordinator!!.visibility = View.VISIBLE }
// }
// }
// }
// thread.start()
// } catch (e: Exception) {
// Log.e(TAG, e.toString())
// uiHandler.post {
// shimmerCards!!.stopShimmer()
// shimmerCards!!.visibility = View.GONE
// }
// }
// }
private fun initMenu() {
val onActionExpandListener: MenuItem.OnActionExpandListener =
object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(menuItem: MenuItem): Boolean {
homeFabs!!.visibility = View.GONE
recyclerView!!.visibility = View.GONE
searchSuggestions!!.visibility = View.VISIBLE
return true
}
override fun onMenuItemActionCollapse(menuItem: MenuItem): Boolean {
homeFabs!!.visibility = View.VISIBLE
recyclerView!!.visibility = View.VISIBLE
searchSuggestions!!.visibility = View.GONE
return true
}
}
if (downloading) {
topAppBar!!.menu.findItem(R.id.cancel_download).isVisible = true
}
topAppBar!!.menu.findItem(R.id.search).setOnActionExpandListener(onActionExpandListener)
val searchView = topAppBar!!.menu.findItem(R.id.search).actionView as SearchView?
searchView!!.inputType = InputType.TYPE_TEXT_VARIATION_URI
searchView.queryHint = getString(R.string.search_hint)
databaseManager = DatabaseManager(context)
infoUtil = InfoUtil(requireContext())
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
topAppBar!!.menu.findItem(R.id.search).collapseActionView()
downloadAllFabCoordinator!!.visibility = GONE
downloadFabs!!.visibility = View.GONE
selectedObjects = ArrayList()
inputQuery = query.trim { it <= ' ' }
shimmerCards!!.startShimmer()
shimmerCards!!.visibility = View.VISIBLE
resultViewModel.deleteAll()
val thread = Thread {
parseQuery(true)
// DOWNLOAD ALL BUTTON
if (resultsList!!.size > 1 && resultsList!![1]!!.playlistTitle.isNotEmpty()) {
Handler(Looper.getMainLooper()).post {
downloadAllFabCoordinator!!.visibility = View.VISIBLE
}
}
}
thread.start()
return true
}
override fun onQueryTextChange(newText: String): Boolean {
searchSuggestionsLinearLayout!!.removeAllViews()
if (newText.isEmpty()) return false
val thread = Thread {
val suggestions = infoUtil!!.getSearchSuggestions(newText)
for (i in suggestions.indices) {
val v = LayoutInflater.from(fragmentContext)
.inflate(R.layout.search_suggestion_item, null)
val textView = v.findViewById<TextView>(R.id.suggestion_text)
textView.text = suggestions[i]
Handler(Looper.getMainLooper()).post {
searchSuggestionsLinearLayout!!.addView(
v
)
}
textView.setOnClickListener { onQueryTextSubmit(textView.text.toString()) }
val mb = v.findViewById<MaterialButton>(R.id.set_search_query_button)
mb.setOnClickListener {
searchView.setQuery(
textView.text,
false
)
}
}
}
thread.start()
return false
}
})
topAppBar!!.setOnClickListener { view: View? -> scrollToTop() }
topAppBar!!.setOnMenuItemClickListener { m: MenuItem ->
val itemId = m.itemId
if (itemId == R.id.delete_results) {
resultViewModel.getTrending()
selectedObjects = ArrayList()
downloadAllFabCoordinator!!.visibility = View.GONE
downloadFabs!!.visibility = View.GONE
}
// } else if (itemId == R.id.cancel_download) {
// try {
// mainActivity!!.cancelDownloadService()
// topAppBar!!.menu.findItem(itemId).isVisible = false
// for (i in downloadInfo!!.downloadQueue.indices) {
// val vid = downloadInfo!!.downloadQueue[i]
// val type = vid.downloadedType
// updateDownloadingStatusOnResult(vid, type, false)
// }
// downloadQueue = ArrayList()
// downloading = false
// } catch (ignored: Exception) {
// }
// }
true
}
}
fun handleIntent(intent: Intent) {
inputQueries = LinkedList()
inputQueries!!.add(intent.getStringExtra(Intent.EXTRA_TEXT))
}
fun handleFileIntent(lines: LinkedList<String?>?) {
inputQueries = lines
}
fun scrollToTop() {
recyclerView!!.scrollToPosition(0)
(topAppBar!!.parent as AppBarLayout).setExpanded(true, true)
}
private fun parseQuery(resetResults: Boolean) {
databaseManager = DatabaseManager(context)
infoUtil = InfoUtil(requireContext())
Handler(Looper.getMainLooper()).post { scrollToTop() }
var type = "Search"
val p = Pattern.compile("^(https?)://(www.)?youtu(.be)?")
val m = p.matcher(inputQuery!!)
if (m.find()) {
type = "Video"
if (inputQuery!!.contains("playlist?list=")) {
type = "Playlist"
}
} else if (inputQuery!!.contains("http")) {
type = "Default"
}
Log.e(TAG, "$inputQuery $type")
try {
when (type) {
"Search" -> {
try {
val res = infoUtil!!.search(
inputQuery!!
)
Handler(Looper.getMainLooper()).post {
if (resetResults) resultViewModel.deleteAll()
resultViewModel.insert(res)
}
} catch (e: Exception) {
Log.e(TAG, e.toString())
Handler(Looper.getMainLooper()).post {
shimmerCards!!.stopShimmer()
shimmerCards!!.visibility = View.GONE
}
}
}
"Video" -> {
var el: Array<String?> =
inputQuery!!.split("/".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
inputQuery = el[el.size - 1]
if (inputQuery!!.contains("watch?v=")) {
inputQuery = inputQuery!!.substring(8)
}
el = inputQuery!!.split("&".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
inputQuery = el[0]
el = inputQuery!!.split("\\?".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
inputQuery = el[0]
try {
val v = infoUtil!!.getVideo(inputQuery!!)
val res = ArrayList<ResultItem?>()
res.add(v)
Handler(Looper.getMainLooper()).post {
if (resetResults) resultViewModel.deleteAll()
resultViewModel.insert(res)
}
} catch (e: Exception) {
Log.e(TAG, e.toString())
Handler(Looper.getMainLooper()).post {
shimmerCards!!.stopShimmer()
shimmerCards!!.visibility = View.GONE
}
}
}
"Playlist" -> {
inputQuery =
inputQuery!!.split("list=".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()[1]
var nextPageToken = ""
if (resetResults) resultViewModel.deleteAll()
do {
val tmp = infoUtil!!.getPlaylist(inputQuery!!, nextPageToken)
val tmp_vids = tmp.videos
val tmp_token = tmp.nextPageToken
Handler(Looper.getMainLooper()).post {
resultViewModel.insert(tmp_vids)
}
if (tmp_token.isEmpty()) break
if (tmp_token == nextPageToken) break
nextPageToken = tmp_token
} while (true)
}
"Default" -> {
try {
val video = infoUtil!!.getFromYTDL(
inputQuery!!
)
Handler(Looper.getMainLooper()).post {
if (resetResults) resultViewModel.deleteAll()
resultViewModel.insert(video)
}
Handler(Looper.getMainLooper()).post {
shimmerCards!!.stopShimmer()
shimmerCards!!.visibility = View.GONE
}
} catch (e: Exception) {
Log.e(TAG, e.toString())
}
}
}
} catch (e: Exception) {
Log.e(TAG, e.toString())
}
databaseManager!!.close()
}
fun findVideo(url: String): ResultItem? {
for (i in resultsList!!.indices) {
val v = resultsList!![i]
if (v!!.url == url) {
return v
}
}
return null
}
@SuppressLint("ResourceType")
override fun onButtonClick(position: Int, type: String) {
// Log.e(TAG, type)
// val vid = resultsList!![position]
// vid!!.downloadedType = type
// val btn = recyclerView!!.findViewWithTag<MaterialButton>(vid.videoId + "##" + type)
// if (downloading) {
// try {
// if (btn.getTag(R.id.cancelDownload) == "true") {
// mainActivity!!.removeItemFromDownloadQueue(vid, type)
// return
// }
// } catch (ignored: Exception) {
// }
// }
// val sharedPreferences =
// context!!.getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
// if (sharedPreferences.getBoolean("download_card", true)) {
// selectedObjects!!.clear()
// selectedObjects!!.add(resultsList!![position])
// showConfigureDownloadCard(type)
// } else {
// downloadQueue!!.add(vid)
// updateDownloadingStatusOnResult(vid, type, true)
// if (isStoragePermissionGranted) {
// mainActivity!!.startDownloadService(downloadQueue, listener)
// downloadQueue!!.clear()
// }
// }
}
private val isStoragePermissionGranted: Boolean
get() = if (ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
== PackageManager.PERMISSION_GRANTED
) {
true
} else {
downloadQueue = ArrayList()
ActivityCompat.requestPermissions(
requireActivity(),
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
1
)
false
}
fun updateDownloadStatusOnResult(v: ResultItem?, type: String?, downloaded: Boolean) {
// if (v != null) {
// databaseManager = DatabaseManager(context)
// try {
// databaseManager!!.updateDownloadStatusOnResult(v.videoId, type, downloaded)
// databaseManager!!.close()
// } catch (ignored: Exception) {
// }
// }
}
fun updateDownloadingStatusOnResult(v: ResultItem?, type: String, isDownloading: Boolean) {
// if (v != null) {
// if (type == "audio") v.isDownloadingAudio =
// isDownloading else if (type == "video") v.isDownloadingVideo = isDownloading
// homeAdapter!!.updateVideoListItem(v, resultsList!!.indexOf(v))
// databaseManager = DatabaseManager(context)
// try {
// databaseManager!!.updateDownloadingStatusOnResult(v.videoId, type, isDownloading)
// databaseManager!!.close()
// } catch (ignored: Exception) {
// }
// }
}
override fun onCardClick(position: Int, add: Boolean) {
val item = resultsList!![position]
if (add) selectedObjects!!.add(item!!) else selectedObjects!!.remove(item)
if (selectedObjects!!.size > 1) {
downloadAllFabCoordinator!!.visibility = View.GONE
downloadFabs!!.visibility = View.VISIBLE
} else {
downloadFabs!!.visibility = View.GONE
if (resultsList!!.size > 1 && resultsList!![1]!!.playlistTitle.isNotEmpty()) {
downloadAllFabCoordinator!!.visibility = View.VISIBLE
}
}
}
override fun onClick(v: View) {
val viewIdName: String
viewIdName = try {
v.tag.toString()
} catch (e: Exception) {
""
}
if (!viewIdName.isEmpty()) {
if (viewIdName.contains("audio") || viewIdName.contains("video")) {
val buttonData =
viewIdName.split("##".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
if (buttonData[0] == "SELECT") {
initSelectedDownload(buttonData[1])
}
}
if (viewIdName == "downloadAll") {
//remove previously selected
for (i in selectedObjects!!.indices) {
val vid = findVideo(
selectedObjects!![i]!!.url
)
homeAdapter!!.notifyItemChanged(resultsList!!.indexOf(vid))
}
selectedObjects = ArrayList()
downloadFabs!!.visibility = View.GONE
bottomSheet = BottomSheetDialog(fragmentContext!!)
bottomSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
bottomSheet!!.setContentView(R.layout.home_download_all_bottom_sheet)
val first = bottomSheet!!.findViewById<TextInputLayout>(R.id.first_textinput)
first!!.editText!!.setText(1.toString())
val last = bottomSheet!!.findViewById<TextInputLayout>(R.id.last_textinput)
last!!.editText!!.setText(resultsList!!.size.toString())
val audio = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_audio_button)
audio!!.setOnClickListener { view: View? ->
val start = first.editText!!.text.toString().toInt()
val end = last.editText!!.text.toString().toInt()
initDownloadAll(bottomSheet!!, start, end, "audio")
}
val video = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_video_button)
video!!.setOnClickListener { view: View? ->
val start = first.editText!!.text.toString().toInt()
val end = last.editText!!.text.toString().toInt()
initDownloadAll(bottomSheet!!, start, end, "video")
}
bottomSheet!!.show()
bottomSheet!!.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
}
}
private fun initDownloadAll(
bottomSheet: BottomSheetDialog,
start: Int,
end: Int,
type: String
) {
// var start = start
// var end = end
// if (start > end) {
// val first = bottomSheet.findViewById<TextInputLayout>(R.id.first_textinput)
// first!!.error = getString(R.string.first_cant_be_larger_than_last)
// val last = bottomSheet.findViewById<TextInputLayout>(R.id.last_textinput)
// last!!.error = getString(R.string.last_cant_be_smaller_than_first)
// return
// }
// bottomSheet.cancel()
// start--
// end--
// if (start <= 1) start = 0
// val sharedPreferences =
// requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
// if (sharedPreferences.getBoolean("download_card", true)) {
// selectedObjects!!.clear()
// selectedObjects!!.addAll(resultsList!!.subList(start, end + 1) as ArrayList<ResultItem>)
// showConfigureDownloadCard(type)
// } else {
// for (i in start..end) {
// val vid = findVideo(
// resultsList!![i]!!.getURL()
// )
// vid!!.downloadedType = type
// updateDownloadingStatusOnResult(vid, type, true)
// downloadQueue!!.add(vid)
// }
// if (isStoragePermissionGranted) {
// mainActivity!!.startDownloadService(downloadQueue, listener)
// downloadQueue!!.clear()
// }
// }
}
private fun initSelectedDownload(type: String) {
// val sharedPreferences =
// context!!.getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
// val editor = sharedPreferences.edit()
// if (sharedPreferences.getBoolean("download_card", true)) {
// showConfigureDownloadCard(type)
// } else {
// for (i in selectedObjects!!.indices) {
// val vid = findVideo(
// selectedObjects!![i]!!.getURL()
// )
// vid!!.downloadedType = type
// updateDownloadingStatusOnResult(vid, type, true)
// homeAdapter!!.notifyItemChanged(resultsList!!.indexOf(vid))
// downloadQueue!!.add(vid)
// }
// selectedObjects = ArrayList()
// homeAdapter!!.clearCheckedVideos()
// downloadFabs!!.visibility = View.GONE
// if (isStoragePermissionGranted) {
// mainActivity!!.startDownloadService(downloadQueue, listener)
// downloadQueue!!.clear()
// }
// }
}
private fun showConfigureDownloadCard(type: String) {
// val sharedPreferences =
// context!!.getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
// val editor = sharedPreferences.edit()
// try {
// bottomSheet = BottomSheetDialog(fragmentContext!!)
// bottomSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
// if (type == "audio") {
// bottomSheet!!.setContentView(R.layout.home_download_audio_bottom_sheet)
// val title = bottomSheet!!.findViewById<TextInputLayout>(R.id.title_textinput)
// if (selectedObjects!!.size > 1) {
// title!!.editText!!.setText(getString(R.string.mutliple_titles))
// title.editText!!.isClickable = false
// title.editText!!.isLongClickable = false
// } else {
// title!!.editText!!.setText(selectedObjects!![0]!!.title)
// title.editText!!.addTextChangedListener(object : TextWatcher {
// override fun beforeTextChanged(
// charSequence: CharSequence,
// i: Int,
// i1: Int,
// i2: Int
// ) {
// }
//
// override fun onTextChanged(
// charSequence: CharSequence,
// i: Int,
// i1: Int,
// i2: Int
// ) {
// }
//
// override fun afterTextChanged(editable: Editable) {
// val index = resultsList!!.indexOf(selectedObjects!![0])
// resultsList!![index]!!.title = editable.toString()
// }
// })
// }
// val author = bottomSheet!!.findViewById<TextInputLayout>(R.id.author_textinput)
// if (selectedObjects!!.size > 1) {
// author!!.editText!!.setText(getString(R.string.mutliple_authors))
// author.editText!!.isClickable = false
// author.editText!!.isLongClickable = false
// } else {
// author!!.editText!!.setText(selectedObjects!![0]!!.author)
// author.editText!!.addTextChangedListener(object : TextWatcher {
// override fun beforeTextChanged(
// charSequence: CharSequence,
// i: Int,
// i1: Int,
// i2: Int
// ) {
// }
//
// override fun onTextChanged(
// charSequence: CharSequence,
// i: Int,
// i1: Int,
// i2: Int
// ) {
// }
//
// override fun afterTextChanged(editable: Editable) {
// val index = resultsList!!.indexOf(selectedObjects!![0])
// resultsList!![index]!!.author = editable.toString()
// }
// })
// }
// val audioFormats = context!!.resources.getStringArray(R.array.music_formats)
// val audioFormat = bottomSheet!!.findViewById<TextInputLayout>(R.id.audio_format)
// val autoCompleteTextView =
// bottomSheet!!.findViewById<AutoCompleteTextView>(R.id.audio_format_textview)
// val preference = sharedPreferences.getString("audio_format", "mp3")
// autoCompleteTextView!!.setText(preference, false)
// (audioFormat!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
// AdapterView.OnItemClickListener { adapterView: AdapterView<*>?, view: View?, index: Int, l: Long ->
// for (i in selectedObjects!!.indices) {
// val vid = findVideo(
// selectedObjects!![i]!!.getURL()
// )
// vid!!.audioFormat = audioFormats[index]
// }
// editor.putString("audio_format", audioFormats[index])
// editor.apply()
// }
// } else {
// bottomSheet!!.setContentView(R.layout.home_download_video_bottom_sheet)
// val title = bottomSheet!!.findViewById<TextInputLayout>(R.id.title_textinput)
// if (selectedObjects!!.size > 1) {
// title!!.editText!!.setText(getString(R.string.mutliple_titles))
// title.editText!!.isClickable = false
// title.editText!!.isLongClickable = false
// } else {
// title!!.editText!!.setText(selectedObjects!![0]!!.title)
// title.editText!!.addTextChangedListener(object : TextWatcher {
// override fun beforeTextChanged(
// charSequence: CharSequence,
// i: Int,
// i1: Int,
// i2: Int
// ) {
// }
//
// override fun onTextChanged(
// charSequence: CharSequence,
// i: Int,
// i1: Int,
// i2: Int
// ) {
// }
//
// override fun afterTextChanged(editable: Editable) {
// val index = resultsList!!.indexOf(selectedObjects!![0])
// resultsList!![index]!!.title = editable.toString()
// }
// })
// }
// val videoFormats = context!!.resources.getStringArray(R.array.video_formats)
// val videoQualities = context!!.resources.getStringArray(R.array.video_quality)
// val videoFormat = bottomSheet!!.findViewById<TextInputLayout>(R.id.video_format)
// var autoCompleteTextView =
// bottomSheet!!.findViewById<AutoCompleteTextView>(R.id.video_format_textview)
// var preference = sharedPreferences.getString("video_format", "webm")
// autoCompleteTextView!!.setText(preference, false)
// (videoFormat!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
// AdapterView.OnItemClickListener { adapterView: AdapterView<*>?, view: View?, index: Int, l: Long ->
// for (i in selectedObjects!!.indices) {
// val vid = findVideo(
// selectedObjects!![i]!!.getURL()
// )
// vid!!.videoFormat = videoFormats[index]
// }
// editor.putString("video_format", videoFormats[index])
// editor.apply()
// }
// val videoQuality = bottomSheet!!.findViewById<TextInputLayout>(R.id.video_quality)
// autoCompleteTextView = bottomSheet!!.findViewById(R.id.video_quality_textview)
// preference = sharedPreferences.getString("video_quality", "Best Quality")
// autoCompleteTextView!!.setText(preference, false)
// (videoQuality!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
// AdapterView.OnItemClickListener { adapterView: AdapterView<*>?, view: View?, index: Int, l: Long ->
// for (i in selectedObjects!!.indices) {
// val vid = findVideo(
// selectedObjects!![i]!!.getURL()
// )
// vid!!.videoQuality = videoQualities[index]
// }
// editor.putString("video_quality", videoQualities[index])
// editor.apply()
// }
// val embedSubs = bottomSheet!!.findViewById<Chip>(R.id.embed_subtitles)
// embedSubs!!.isChecked = sharedPreferences.getBoolean("embed_subtitles", false)
// embedSubs.setOnClickListener { view: View? ->
// if (embedSubs.isChecked) {
// editor.putBoolean("embed_subtitles", true)
// } else {
// editor.putBoolean("embed_subtitles", false)
// }
// editor.apply()
// }
// val addChapters = bottomSheet!!.findViewById<Chip>(R.id.add_chapters)
// addChapters!!.isChecked = sharedPreferences.getBoolean("add_chapters", false)
// addChapters.setOnClickListener { view: View? ->
// if (addChapters.isChecked) {
// editor.putBoolean("add_chapters", true)
// } else {
// editor.putBoolean("add_chapters", false)
// }
// editor.apply()
// }
// val saveThumbnail = bottomSheet!!.findViewById<Chip>(R.id.save_thumbnail)
// saveThumbnail!!.isChecked = sharedPreferences.getBoolean("write_thumbnail", false)
// saveThumbnail.setOnClickListener { view: View? ->
// if (saveThumbnail.isChecked) {
// editor.putBoolean("write_thumbnail", true)
// } else {
// editor.putBoolean("write_thumbnail", false)
// }
// editor.apply()
// }
// }
// val cancel = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_cancel_button)
// cancel!!.setOnClickListener { view: View? -> bottomSheet!!.cancel() }
// val download = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_download_button)
// download!!.setOnClickListener { view: View? ->
// for (i in selectedObjects!!.indices) {
// val vid = findVideo(
// selectedObjects!![i]!!.getURL()
// )
// vid!!.downloadedType = type
// updateDownloadingStatusOnResult(vid, type, true)
// homeAdapter!!.notifyItemChanged(resultsList!!.indexOf(vid))
// downloadQueue!!.add(vid)
// }
// selectedObjects = ArrayList()
// homeAdapter!!.clearCheckedVideos()
// downloadFabs!!.visibility = View.GONE
// if (isStoragePermissionGranted) {
// mainActivity!!.startDownloadService(downloadQueue, listener)
// downloadQueue!!.clear()
// }
// bottomSheet!!.cancel()
// }
// bottomSheet!!.show()
// bottomSheet!!.window!!.setLayout(
// ViewGroup.LayoutParams.MATCH_PARENT,
// ViewGroup.LayoutParams.MATCH_PARENT
// )
// } catch (e: Exception) {
// Toast.makeText(fragmentContext, e.message, Toast.LENGTH_LONG).show()
// }
}
companion object {
private const val TAG = "HomeFragment"
}
}

View file

@ -3,17 +3,13 @@ package com.deniscerri.ytdlnis.util
import android.content.Context import android.content.Context
import android.media.MediaScannerConnection import android.media.MediaScannerConnection
import android.net.Uri import android.net.Uri
import android.os.FileUtils
import android.provider.DocumentsContract import android.provider.DocumentsContract
import android.util.Log
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import android.widget.Toast import android.widget.Toast
import com.deniscerri.ytdlnis.DownloaderService
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.Video import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ResultItem
import java.io.File import java.io.File
import java.io.InputStream
import java.io.OutputStream
import java.net.URLDecoder import java.net.URLDecoder
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@ -55,7 +51,7 @@ class FileUtil() {
return formattedPath.toString() return formattedPath.toString()
} }
fun scanMedia(video: Video, context: Context) : String { fun scanMedia(video: DownloadItem, context: Context) : String {
val files = ArrayList<File>() val files = ArrayList<File>()
val title: String = video.title.replace("[^a-zA-Z0-9]".toRegex(), "") val title: String = video.title.replace("[^a-zA-Z0-9]".toRegex(), "")
var pathTmp: String var pathTmp: String

View file

@ -5,7 +5,7 @@ import android.content.Context
import android.util.Log import android.util.Log
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.DatabaseManager import com.deniscerri.ytdlnis.database.DatabaseManager
import com.deniscerri.ytdlnis.database.Video import com.deniscerri.ytdlnis.database.models.ResultItem
import com.yausername.youtubedl_android.YoutubeDL import com.yausername.youtubedl_android.YoutubeDL
import com.yausername.youtubedl_android.YoutubeDLRequest import com.yausername.youtubedl_android.YoutubeDLRequest
import org.json.JSONArray import org.json.JSONArray
@ -16,9 +16,10 @@ import java.io.InputStreamReader
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URL import java.net.URL
import java.util.* import java.util.*
import kotlin.collections.ArrayList
class InfoUtil(context: Context) { class InfoUtil(context: Context) {
private var videos: ArrayList<Video?> private var items: ArrayList<ResultItem?>
private var key: String? = null private var key: String? = null
private var useInvidous = false private var useInvidous = false
private var databaseManager: DatabaseManager? = null private var databaseManager: DatabaseManager? = null
@ -32,7 +33,7 @@ class InfoUtil(context: Context) {
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
videos = ArrayList() items = ArrayList()
} }
private fun init(){ private fun init(){
@ -51,16 +52,16 @@ class InfoUtil(context: Context) {
} }
@Throws(JSONException::class) @Throws(JSONException::class)
fun search(query: String): ArrayList<Video?> { fun search(query: String): ArrayList<ResultItem?> {
init() init()
videos = ArrayList() items = ArrayList()
return if (key!!.isEmpty()) { return if (key!!.isEmpty()) {
if (useInvidous) searchFromInvidous(query) else getFromYTDL(query) if (useInvidous) searchFromInvidous(query) else getFromYTDL(query)
} else searchFromKey(query) } else searchFromKey(query)
} }
@Throws(JSONException::class) @Throws(JSONException::class)
fun searchFromKey(query: String): ArrayList<Video?> { fun searchFromKey(query: String): ArrayList<ResultItem?> {
//short data //short data
val res = val res =
genericRequest("https://youtube.googleapis.com/youtube/v3/search?part=snippet&q=$query&maxResults=25&regionCode=$countryCODE&key=$key") genericRequest("https://youtube.googleapis.com/youtube/v3/search?part=snippet&q=$query&maxResults=25&regionCode=$countryCODE&key=$key")
@ -102,14 +103,14 @@ class InfoUtil(context: Context) {
if (v == null || v.thumb.isEmpty()) { if (v == null || v.thumb.isEmpty()) {
continue continue
} }
videos.add(createVideofromJSON(snippet)) items.add(createVideofromJSON(snippet))
} }
} }
return videos return items
} }
@Throws(JSONException::class) @Throws(JSONException::class)
fun searchFromInvidous(query: String): ArrayList<Video?> { fun searchFromInvidous(query: String): ArrayList<ResultItem?> {
val dataArray = genericArrayRequest(invidousURL + "search?q=" + query + "?type=video") val dataArray = genericArrayRequest(invidousURL + "search?q=" + query + "?type=video")
if (dataArray.length() == 0) return getFromYTDL(query) if (dataArray.length() == 0) return getFromYTDL(query)
for (i in 0 until dataArray.length()) { for (i in 0 until dataArray.length()) {
@ -128,15 +129,15 @@ class InfoUtil(context: Context) {
if (v == null || v.thumb.isEmpty()) { if (v == null || v.thumb.isEmpty()) {
continue continue
} }
videos.add(v) items.add(v)
} }
return videos return items
} }
@Throws(JSONException::class) @Throws(JSONException::class)
fun getPlaylist(id: String, nextPageToken: String): PlaylistTuple { fun getPlaylist(id: String, nextPageToken: String): PlaylistTuple {
init() init()
videos = ArrayList() items = ArrayList()
if (key!!.isEmpty()) { if (key!!.isEmpty()) {
return if (useInvidous) getPlaylistFromInvidous(id) else PlaylistTuple( return if (useInvidous) getPlaylistFromInvidous(id) else PlaylistTuple(
"", "",
@ -186,12 +187,12 @@ class InfoUtil(context: Context) {
} else { } else {
j++ j++
} }
v.isPlaylistItem = 1 v.playlistTitle = "YTDLnis"
videos.add(v) items.add(v)
i++ i++
} }
val next = res.optString("nextPageToken") val next = res.optString("nextPageToken")
return PlaylistTuple(next, videos) return PlaylistTuple(next, items)
} }
private fun getPlaylistFromInvidous(id: String): PlaylistTuple { private fun getPlaylistFromInvidous(id: String): PlaylistTuple {
@ -208,17 +209,16 @@ class InfoUtil(context: Context) {
val v = createVideofromInvidiousJSON(element) val v = createVideofromInvidiousJSON(element)
if (v == null || v.thumb.isEmpty()) continue if (v == null || v.thumb.isEmpty()) continue
v.playlistTitle = res.getString("title") v.playlistTitle = res.getString("title")
v.isPlaylistItem = 1 items.add(v)
videos.add(v)
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
return PlaylistTuple("", videos) return PlaylistTuple("", items)
} }
@Throws(JSONException::class) @Throws(JSONException::class)
fun getVideo(id: String): Video? { fun getVideo(id: String): ResultItem? {
init() init()
if (key!!.isEmpty()) { if (key!!.isEmpty()) {
return if (useInvidous) { return if (useInvidous) {
@ -245,8 +245,8 @@ class InfoUtil(context: Context) {
return createVideofromJSON(res) return createVideofromJSON(res)
} }
private fun createVideofromJSON(obj: JSONObject): Video? { private fun createVideofromJSON(obj: JSONObject): ResultItem? {
var video: Video? = null var video: ResultItem? = null
try { try {
val id = obj.getString("videoID") val id = obj.getString("videoID")
val title = obj.getString("title").toString() val title = obj.getString("title").toString()
@ -257,20 +257,14 @@ class InfoUtil(context: Context) {
val downloadedAudio = databaseManager!!.checkDownloaded(url, "audio") val downloadedAudio = databaseManager!!.checkDownloaded(url, "audio")
val downloadedVideo = databaseManager!!.checkDownloaded(url, "video") val downloadedVideo = databaseManager!!.checkDownloaded(url, "video")
val isPlaylist = 0 val isPlaylist = 0
video = Video( video = ResultItem(
id, id,
url, url,
title, title,
author, author,
duration, duration,
thumb, thumb,
downloadedAudio, "youtube"
downloadedVideo,
isPlaylist,
"youtube",
0,
0,
""
) )
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, e.toString()) Log.e(TAG, e.toString())
@ -278,8 +272,8 @@ class InfoUtil(context: Context) {
return video return video
} }
private fun createVideofromInvidiousJSON(obj: JSONObject): Video? { private fun createVideofromInvidiousJSON(obj: JSONObject): ResultItem? {
var video: Video? = null var video: ResultItem? = null
try { try {
val id = obj.getString("videoId") val id = obj.getString("videoId")
val title = obj.getString("title").toString() val title = obj.getString("title").toString()
@ -290,20 +284,14 @@ class InfoUtil(context: Context) {
val downloadedAudio = databaseManager!!.checkDownloaded(url, "audio") val downloadedAudio = databaseManager!!.checkDownloaded(url, "audio")
val downloadedVideo = databaseManager!!.checkDownloaded(url, "video") val downloadedVideo = databaseManager!!.checkDownloaded(url, "video")
val isPlaylist = 0 val isPlaylist = 0
video = Video( video = ResultItem(
id, id,
url, url,
title, title,
author, author,
duration, duration,
thumb, thumb,
downloadedAudio, "youtube"
downloadedVideo,
isPlaylist,
"youtube",
0,
0,
""
) )
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, e.toString()) Log.e(TAG, e.toString())
@ -395,16 +383,16 @@ class InfoUtil(context: Context) {
} }
@Throws(JSONException::class) @Throws(JSONException::class)
fun getTrending(context: Context): ArrayList<Video?> { fun getTrending(context: Context): ArrayList<ResultItem?> {
init() init()
videos = ArrayList() items = ArrayList()
return if (key!!.isEmpty()) { return if (key!!.isEmpty()) {
if (useInvidous) getTrendingFromInvidous(context) else ArrayList() if (useInvidous) getTrendingFromInvidous(context) else ArrayList()
} else getTrendingFromKey(context) } else getTrendingFromKey(context)
} }
@Throws(JSONException::class) @Throws(JSONException::class)
fun getTrendingFromKey(context: Context): ArrayList<Video?> { fun getTrendingFromKey(context: Context): ArrayList<ResultItem?> {
val url = "https://www.googleapis.com/youtube/v3/videos?part=snippet&chart=mostPopular&videoCategoryId=10&regionCode=$countryCODE&maxResults=25&key=$key" val url = "https://www.googleapis.com/youtube/v3/videos?part=snippet&chart=mostPopular&videoCategoryId=10&regionCode=$countryCODE&maxResults=25&key=$key"
//short data //short data
val res = genericRequest(url) val res = genericRequest(url)
@ -428,12 +416,12 @@ class InfoUtil(context: Context) {
continue continue
} }
v.playlistTitle = context.getString(R.string.trendingPlaylist) v.playlistTitle = context.getString(R.string.trendingPlaylist)
videos.add(v) items.add(v)
} }
return videos return items
} }
private fun getTrendingFromInvidous(context: Context): ArrayList<Video?> { private fun getTrendingFromInvidous(context: Context): ArrayList<ResultItem?> {
val url = invidousURL + "trending?type=music&region=" + countryCODE val url = invidousURL + "trending?type=music&region=" + countryCODE
val res = genericArrayRequest(url) val res = genericArrayRequest(url)
try { try {
@ -443,17 +431,17 @@ class InfoUtil(context: Context) {
val v = createVideofromInvidiousJSON(element) val v = createVideofromInvidiousJSON(element)
if (v == null || v.thumb.isEmpty()) continue if (v == null || v.thumb.isEmpty()) continue
v.playlistTitle = context.getString(R.string.trendingPlaylist) v.playlistTitle = context.getString(R.string.trendingPlaylist)
videos.add(v) items.add(v)
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
return videos return items
} }
fun getFromYTDL(query: String): ArrayList<Video?> { fun getFromYTDL(query: String): ArrayList<ResultItem?> {
init() init()
videos = ArrayList() items = ArrayList()
try { try {
val request = YoutubeDLRequest(query) val request = YoutubeDLRequest(query)
request.addOption("--flat-playlist") request.addOption("--flat-playlist")
@ -501,28 +489,22 @@ class InfoUtil(context: Context) {
val website = if (jsonObject.has("ie_key")) jsonObject.getString("ie_key") else jsonObject.getString("extractor") val website = if (jsonObject.has("ie_key")) jsonObject.getString("ie_key") else jsonObject.getString("extractor")
var playlistTitle: String? = "" var playlistTitle: String? = ""
if (jsonObject.has("playlist")) playlistTitle = jsonObject.getString("playlist") if (jsonObject.has("playlist")) playlistTitle = jsonObject.getString("playlist")
videos.add( items.add(
Video( ResultItem(
jsonObject.getString("id"),
url, url,
title, title,
author, author!!,
duration, duration,
thumb, thumb!!,
databaseManager!!.checkDownloaded(url, "audio"),
databaseManager!!.checkDownloaded(url, "video"),
isPlaylist,
website, website,
0, playlistTitle!!
0,
playlistTitle
) )
) )
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
return videos return items
} }
fun getSearchSuggestions(query: String): ArrayList<String> { fun getSearchSuggestions(query: String): ArrayList<String> {
@ -598,7 +580,7 @@ class InfoUtil(context: Context) {
class PlaylistTuple internal constructor( class PlaylistTuple internal constructor(
var nextPageToken: String, var nextPageToken: String,
var videos: ArrayList<Video?> var videos: ArrayList<ResultItem?>
) )
companion object { companion object {

View file

@ -50,7 +50,7 @@ class DownloadWorker(
setForeground(foregroundInfo) setForeground(foregroundInfo)
while (queue.isNotEmpty()){ while (queue.isNotEmpty()){
val item = dao.getDownloadById(queue[0].id) val item = dao.getDownloadById(queue[0].id!!)
queue.removeFirst() queue.removeFirst()
val url = item.url val url = item.url
val request = YoutubeDLRequest(url) val request = YoutubeDLRequest(url)

View file

@ -45,7 +45,7 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent" android:layout_width="match_parent"
android:id="@+id/recycler_view_home" android:id="@+id/recyclerViewHome"
android:nestedScrollingEnabled="false" android:nestedScrollingEnabled="false"
android:orientation="vertical" android:orientation="vertical"
android:layout_height="match_parent" android:layout_height="match_parent"

View file

@ -36,8 +36,8 @@ buildscript {
} }
plugins { plugins {
id 'com.android.application' version '7.3.1' apply false id 'com.android.application' version '7.4.0' apply false
id 'com.android.library' version '7.3.1' apply false id 'com.android.library' version '7.4.0' apply false
id 'org.jetbrains.kotlin.android' version '1.7.20' apply false id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
} }