created download worker
This commit is contained in:
parent
ec465f8bda
commit
335be8299c
18 changed files with 367 additions and 373 deletions
|
|
@ -1,254 +0,0 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "e2280d10a40623d3a51ecf5205500351",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "results",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `website` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "author",
|
||||
"columnName": "author",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "duration",
|
||||
"columnName": "duration",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "thumb",
|
||||
"columnName": "thumb",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "playlistTitle",
|
||||
"columnName": "playlistTitle",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "history",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "author",
|
||||
"columnName": "author",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "duration",
|
||||
"columnName": "duration",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "thumb",
|
||||
"columnName": "thumb",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "time",
|
||||
"columnName": "time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadPath",
|
||||
"columnName": "downloadPath",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "downloads",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `startTime` TEXT NOT NULL, `endTime` TEXT NOT NULL, `thumb` TEXT NOT NULL, `formatId` INTEGER NOT NULL, `formatDesc` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `progress` REAL NOT NULL, `custom` INTEGER NOT NULL, `customTemplateId` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "author",
|
||||
"columnName": "author",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "startTime",
|
||||
"columnName": "startTime",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "endTime",
|
||||
"columnName": "endTime",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "thumb",
|
||||
"columnName": "thumb",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "formatId",
|
||||
"columnName": "formatId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "formatDesc",
|
||||
"columnName": "formatDesc",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadPath",
|
||||
"columnName": "downloadPath",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "website",
|
||||
"columnName": "website",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "downloadSize",
|
||||
"columnName": "downloadSize",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "progress",
|
||||
"columnName": "progress",
|
||||
"affinity": "REAL",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "custom",
|
||||
"columnName": "custom",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "customTemplateId",
|
||||
"columnName": "customTemplateId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"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, 'e2280d10a40623d3a51ecf5205500351')"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
android:name=".DownloaderService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
<receiver android:name=".receiver.NotificationReceiver" />
|
||||
<receiver android:name=".receiver.CancelDownloadNotificationReceiver" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
|
|
|||
|
|
@ -432,6 +432,8 @@ class DownloaderService : Service() {
|
|||
Log.e(TAG, downloadInfo.downloadPath)
|
||||
downloadInfo.downloadType = type
|
||||
|
||||
|
||||
|
||||
try {
|
||||
for (activity in activities.keys) {
|
||||
activity.runOnUiThread {
|
||||
|
|
|
|||
|
|
@ -4,15 +4,17 @@ import android.content.Context
|
|||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
||||
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
||||
import com.deniscerri.ytdlnis.database.dao.HistoryDao
|
||||
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
|
||||
@Database(
|
||||
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class],
|
||||
entities = [ResultItem::class, HistoryItem::class, DownloadItem::class, CommandTemplate::class],
|
||||
version = 1,
|
||||
autoMigrations = []
|
||||
)
|
||||
|
|
@ -20,6 +22,7 @@ abstract class DBManager : RoomDatabase(){
|
|||
abstract val resultDao : ResultDao
|
||||
abstract val historyDao : HistoryDao
|
||||
abstract val downloadDao : DownloadDao
|
||||
abstract val commandTemplateDao : CommandTemplateDao
|
||||
|
||||
companion object {
|
||||
//prevents multiple instances of db getting created at the same time
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package com.deniscerri.ytdlnis.database.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
|
||||
@Dao
|
||||
interface CommandTemplateDao {
|
||||
|
||||
@Query("SELECT * FROM commandTemplates")
|
||||
fun getAllTemplates() : List<CommandTemplate>
|
||||
|
||||
@Query("SELECT * FROM commandTemplates WHERE id=:id LIMIT 1")
|
||||
fun getTemplateById(id: Int) : CommandTemplate
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insert(item: CommandTemplate)
|
||||
|
||||
@Query("DELETE FROM commandTemplates")
|
||||
suspend fun deleteAll()
|
||||
|
||||
@Delete
|
||||
suspend fun delete(item: CommandTemplate)
|
||||
|
||||
@Update(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun update(item: CommandTemplate)
|
||||
}
|
||||
|
|
@ -10,10 +10,13 @@ import com.deniscerri.ytdlnis.util.FileUtil
|
|||
interface DownloadDao {
|
||||
|
||||
@Query("SELECT * FROM downloads")
|
||||
fun getAllDownloads() : LiveData<List<DownloadItem>>
|
||||
fun getAllDownloads() : List<DownloadItem>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Queued'")
|
||||
fun getQueuedDownloads() : List<DownloadItem>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE id=:id LIMIT 1")
|
||||
suspend fun getDownloadById(id: Int) : DownloadItem
|
||||
fun getDownloadById(id: Int) : DownloadItem
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insert(item: DownloadItem)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "downloads")
|
||||
data class CommandTemplate(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Int,
|
||||
val title: String,
|
||||
val content: String
|
||||
)
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
|
|
@ -10,15 +11,21 @@ data class DownloadItem(
|
|||
val url: String,
|
||||
val title: String,
|
||||
val author: String,
|
||||
val startTime: String,
|
||||
val endTime: String,
|
||||
val thumb: String,
|
||||
val formatId: Int,
|
||||
val duration: String,
|
||||
val type: String,
|
||||
val audioQualityId: String,
|
||||
val videoQualityId: String,
|
||||
val customTemplateId: Int,
|
||||
val audioFormat: String,
|
||||
val videoFormat: String,
|
||||
val formatDesc: String,
|
||||
@ColumnInfo(defaultValue = "0")
|
||||
val removeAudio: Boolean,
|
||||
val downloadPath: String,
|
||||
val website: String,
|
||||
val downloadSize: String,
|
||||
val progress: Float,
|
||||
val custom: Boolean,
|
||||
val customTemplateId: Int
|
||||
val playlistTitle: String,
|
||||
@ColumnInfo(defaultValue = "Queued")
|
||||
var status: String
|
||||
)
|
||||
|
|
@ -5,8 +5,6 @@ import androidx.room.PrimaryKey
|
|||
|
||||
@Entity(tableName = "history")
|
||||
data class HistoryItem(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Int,
|
||||
val url: String,
|
||||
val title: String,
|
||||
val author: String,
|
||||
|
|
@ -16,5 +14,7 @@ data class HistoryItem(
|
|||
val time: Long,
|
||||
val downloadPath: String,
|
||||
val website: String
|
||||
//val isQueuedDownload: Int
|
||||
)
|
||||
){
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Int? = null
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
|||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
|
||||
class DownloadRepository(private val downloadDao: DownloadDao) {
|
||||
val allDownloads : LiveData<List<DownloadItem>> = downloadDao.getAllDownloads()
|
||||
|
||||
suspend fun insert(item: DownloadItem){
|
||||
downloadDao.insert(item)
|
||||
|
|
@ -19,5 +18,14 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
|
|||
downloadDao.update(item)
|
||||
}
|
||||
|
||||
suspend fun getQueuedDownloads() : List<DownloadItem>{
|
||||
var items = downloadDao.getQueuedDownloads();
|
||||
for (i in items){
|
||||
i.status = "Downloading"
|
||||
downloadDao.update(i)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.deniscerri.ytdlnis.receiver
|
||||
|
||||
import android.content.*
|
||||
import androidx.work.WorkManager
|
||||
|
||||
class CancelDownloadNotificationReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(c: Context, intent: Intent) {
|
||||
val message = intent.getStringExtra("cancel")
|
||||
val id = intent.getIntExtra("workID", 0)
|
||||
if (message != null) {
|
||||
WorkManager.getInstance(c).cancelAllWorkByTag(id.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
package com.deniscerri.ytdlnis.receiver
|
||||
|
||||
import android.content.*
|
||||
import android.os.IBinder
|
||||
import com.deniscerri.ytdlnis.DownloaderService
|
||||
import com.deniscerri.ytdlnis.DownloaderService.LocalBinder
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderService
|
||||
|
||||
class NotificationReceiver : BroadcastReceiver() {
|
||||
var downloaderService: DownloaderService? = null
|
||||
private var iDownloaderService: IDownloaderService? = null
|
||||
private var context: Context? = null
|
||||
private val serviceConnection: ServiceConnection = object : ServiceConnection {
|
||||
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
||||
downloaderService = (service as LocalBinder).service
|
||||
iDownloaderService = service
|
||||
cancelDownload()
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(componentName: ComponentName) {
|
||||
downloaderService = null
|
||||
iDownloaderService = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReceive(c: Context, intent: Intent) {
|
||||
context = c
|
||||
val message = intent.getStringExtra("cancel")
|
||||
if (message != null) {
|
||||
val serviceIntent = Intent(context!!.applicationContext, DownloaderService::class.java)
|
||||
serviceIntent.putExtra("rebind", true)
|
||||
context!!.applicationContext.bindService(
|
||||
serviceIntent,
|
||||
serviceConnection,
|
||||
Context.BIND_AUTO_CREATE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun cancelDownload() {
|
||||
try {
|
||||
iDownloaderService!!.cancelDownload(true)
|
||||
context!!.applicationContext.unbindService(serviceConnection)
|
||||
context!!.applicationContext.stopService(
|
||||
Intent(
|
||||
context!!.applicationContext,
|
||||
DownloaderService::class.java
|
||||
)
|
||||
)
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import android.graphics.BitmapFactory
|
|||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.receiver.NotificationReceiver
|
||||
import com.deniscerri.ytdlnis.receiver.CancelDownloadNotificationReceiver
|
||||
|
||||
class NotificationUtil(var context: Context) {
|
||||
private val downloadNotificationBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||
|
|
@ -53,7 +53,7 @@ class NotificationUtil(var context: Context) {
|
|||
pendingIntent: PendingIntent?,
|
||||
title: String?,
|
||||
) : Notification {
|
||||
val intent = Intent(context, NotificationReceiver::class.java)
|
||||
val intent = Intent(context, CancelDownloadNotificationReceiver::class.java)
|
||||
|
||||
return fileTransferNotificationBuilder
|
||||
.setContentTitle(title)
|
||||
|
|
@ -92,12 +92,14 @@ class NotificationUtil(var context: Context) {
|
|||
fun createDownloadServiceNotification(
|
||||
pendingIntent: PendingIntent?,
|
||||
title: String?,
|
||||
workID: Int,
|
||||
channel: String
|
||||
): Notification {
|
||||
val notificationBuilder = getBuilder(channel)
|
||||
|
||||
val intent = Intent(context, NotificationReceiver::class.java)
|
||||
val intent = Intent(context, CancelDownloadNotificationReceiver::class.java)
|
||||
intent.putExtra("cancel", "")
|
||||
intent.putExtra("workID", workID)
|
||||
val cancelNotificationPendingIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
0,
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
package com.deniscerri.ytdlnis.work;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.ForegroundInfo;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
|
||||
import com.deniscerri.ytdlnis.MainActivity;
|
||||
import com.deniscerri.ytdlnis.database.Video;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import kotlin.random.Random;
|
||||
|
||||
public class DownloadWorker extends Worker {
|
||||
private Context context;
|
||||
private WorkerParameters workerParams;
|
||||
public DownloadWorker(
|
||||
@NonNull Context appContext,
|
||||
@NonNull WorkerParameters workerParams) {
|
||||
super(appContext, workerParams);
|
||||
this.context = appContext;
|
||||
this.workerParams = workerParams;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
//TODO
|
||||
return Result.success();
|
||||
}
|
||||
}
|
||||
253
app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt
Normal file
253
app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
package com.deniscerri.ytdlnis.work
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.SystemClock
|
||||
import android.provider.DocumentsContract
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import com.deniscerri.ytdlnis.BuildConfig
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
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.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
class DownloadWorker(
|
||||
private val context: Context,
|
||||
workerParams: WorkerParameters
|
||||
) : CoroutineWorker(context, workerParams) {
|
||||
override suspend fun doWork(): Result {
|
||||
workID = inputData.getInt("workID", SystemClock.uptimeMillis().toInt())
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val dbManager = DBManager.getInstance(context)
|
||||
val dao = dbManager.downloadDao
|
||||
val repository = DownloadRepository(dao)
|
||||
val commandTemplateDao = dbManager.commandTemplateDao
|
||||
val historyDao = dbManager.historyDao
|
||||
|
||||
queue = repository.getQueuedDownloads() as MutableList<DownloadItem>
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, queue[0].title, workID, NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||
val foregroundInfo = ForegroundInfo(workID, notification)
|
||||
setForeground(foregroundInfo)
|
||||
|
||||
while (queue.isNotEmpty()){
|
||||
val item = dao.getDownloadById(queue[0].id)
|
||||
queue.removeFirst()
|
||||
val url = item.url
|
||||
val request = YoutubeDLRequest(url)
|
||||
val type = item.type
|
||||
val downloadLocation = item.downloadPath
|
||||
|
||||
val tempFolder = StringBuilder(context.cacheDir.absolutePath + """/${item.title}##${item.type}""")
|
||||
when(type){
|
||||
"audio" -> tempFolder.append("##${item.audioQualityId}")
|
||||
"video" -> tempFolder.append("##${item.videoQualityId}")
|
||||
"command" -> tempFolder.append("##${item.customTemplateId}")
|
||||
}
|
||||
var tempFileDir = File(tempFolder.toString())
|
||||
tempFileDir.delete()
|
||||
tempFileDir.mkdir()
|
||||
|
||||
val sharedPreferences = context.getSharedPreferences("root_preferences",
|
||||
Service.MODE_PRIVATE
|
||||
)
|
||||
val aria2 = sharedPreferences.getBoolean("aria2", false)
|
||||
if (aria2) {
|
||||
request.addOption("--downloader", "libaria2c.so")
|
||||
request.addOption("--external-downloader-args", "aria2c:\"--summary-interval=1\"")
|
||||
} else {
|
||||
val concurrentFragments = sharedPreferences.getInt("concurrent_fragments", 1)
|
||||
if (concurrentFragments > 1) request.addOption("-N", concurrentFragments)
|
||||
}
|
||||
val limitRate = sharedPreferences.getString("limit_rate", "")
|
||||
if (limitRate != "") request.addOption("-r", limitRate!!)
|
||||
val writeThumbnail = sharedPreferences.getBoolean("write_thumbnail", false)
|
||||
if (writeThumbnail) {
|
||||
request.addOption("--write-thumbnail")
|
||||
request.addOption("--convert-thumbnails", "png")
|
||||
}
|
||||
request.addOption("--no-mtime")
|
||||
val sponsorBlockFilters = sharedPreferences.getStringSet("sponsorblock_filters", emptySet())
|
||||
if (sponsorBlockFilters!!.isNotEmpty()) {
|
||||
val filters = java.lang.String.join(",", sponsorBlockFilters)
|
||||
request.addOption("--sponsorblock-remove", filters)
|
||||
}
|
||||
|
||||
when(type){
|
||||
"audio" -> {
|
||||
request.addOption("-x")
|
||||
var audioQualityId : String = item.audioQualityId
|
||||
if (audioQualityId == "0") audioQualityId = "ba"
|
||||
var format = item.audioFormat
|
||||
if (format.isEmpty()){
|
||||
format = sharedPreferences.getString("audio_format", "")!!
|
||||
}
|
||||
request.addOption("-f", audioQualityId)
|
||||
request.addOption("--audio-format", format)
|
||||
request.addOption("--embed-metadata")
|
||||
|
||||
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
||||
if (embedThumb) {
|
||||
request.addOption("--embed-thumbnail")
|
||||
request.addOption("--convert-thumbnails", "png")
|
||||
try {
|
||||
val config = File(context.cacheDir, "config" + item.title + "##" + item.audioQualityId + ".txt")
|
||||
val configData =
|
||||
"--ppa \"ffmpeg: -c:v png -vf crop=\\\"'if(gt(ih,iw),iw,ih)':'if(gt(iw,ih),ih,iw)'\\\"\""
|
||||
config.writeText(configData)
|
||||
request.addOption("--config", config.absolutePath)
|
||||
} catch (ignored: Exception) {}
|
||||
}
|
||||
request.addOption("--parse-metadata", "%(release_year,upload_date)s:%(meta_date)s")
|
||||
request.addCommands(listOf("--replace-in-metadata", "title", ".*.", item.title))
|
||||
request.addCommands(listOf("--replace-in-metadata", "uploader", ".*.", item.author))
|
||||
|
||||
if (item.playlistTitle.isNotEmpty()) {
|
||||
request.addOption("--parse-metadata", "%(album,playlist,title)s:%(meta_album)s")
|
||||
request.addOption("--parse-metadata", "%(track_number,playlist_index)d:%(meta_track)s")
|
||||
} else {
|
||||
request.addOption("--parse-metadata", "%(album,title)s:%(meta_album)s")
|
||||
}
|
||||
request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s")
|
||||
}
|
||||
"video" -> {
|
||||
if (downloadLocation == context.getString(R.string.video_path)){
|
||||
tempFileDir = File(context.getString(R.string.video_path))
|
||||
}
|
||||
|
||||
val addChapters = sharedPreferences.getBoolean("add_chapters", false)
|
||||
if (addChapters) {
|
||||
request.addOption("--sponsorblock-mark", "all")
|
||||
}
|
||||
val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false)
|
||||
if (embedSubs) {
|
||||
request.addOption("--embed-subs", "")
|
||||
}
|
||||
var videoQualityId = item.videoQualityId
|
||||
val audioQualityId = item.audioQualityId
|
||||
if (videoQualityId.isEmpty()) videoQualityId = "bestvideo"
|
||||
val formatArgument = StringBuilder(videoQualityId)
|
||||
if (videoQualityId != "worst"){
|
||||
if (audioQualityId != "0") formatArgument.append("+", audioQualityId, "/best")
|
||||
}
|
||||
request.addOption("-f", formatArgument.toString())
|
||||
var format = item.videoFormat
|
||||
if (format.isNotEmpty()) {
|
||||
format = sharedPreferences.getString("video_format", "")!!
|
||||
if (format != "DEFAULT") request.addOption("--merge-output-format", format)
|
||||
}
|
||||
|
||||
if (format != "webm") {
|
||||
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
||||
if (embedThumb) {
|
||||
request.addOption("--embed-thumbnail")
|
||||
}
|
||||
}
|
||||
request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s")
|
||||
}
|
||||
"command" -> {
|
||||
val commandRegex = "\"([^\"]*)\"|(\\S+)"
|
||||
val command = commandTemplateDao.getTemplateById(item.customTemplateId)
|
||||
val m = Pattern.compile(commandRegex).matcher(command.content)
|
||||
while (m.find()) {
|
||||
if (m.group(1) != null) {
|
||||
request.addOption(m.group(1)!!)
|
||||
} else {
|
||||
request.addOption(m.group(2)!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runCatching {
|
||||
YoutubeDL.getInstance().execute(request, item.id.toString()){ progress, _, line ->
|
||||
setProgressAsync(workDataOf("progress" to progress.toInt()))
|
||||
var title: String? = context.getString(R.string.download_start)
|
||||
if (queue.isNotEmpty()) {
|
||||
title = queue[0].title
|
||||
}
|
||||
notificationUtil.updateDownloadNotification(
|
||||
workID,
|
||||
line, progress.toInt(), queue.size, title,
|
||||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
||||
)
|
||||
}
|
||||
}.onSuccess {
|
||||
//move file from internal to set download directory
|
||||
moveFile(tempFileDir.absoluteFile, downloadLocation){ progress ->
|
||||
setProgressAsync(workDataOf("progress" to progress))
|
||||
}
|
||||
//put download in history
|
||||
val incognito = sharedPreferences.getBoolean("incognito", false)
|
||||
if (!incognito) {
|
||||
val unixtime = System.currentTimeMillis() / 1000
|
||||
val historyItem = HistoryItem(item.url, item.title, item.author, item.duration, item.thumb, item.type, unixtime, item.downloadPath, item.website)
|
||||
historyDao.insert(historyItem)
|
||||
}
|
||||
|
||||
}.onFailure {
|
||||
tempFileDir.delete()
|
||||
if (BuildConfig.DEBUG) {
|
||||
Toast.makeText(context, it.message, Toast.LENGTH_LONG).show()
|
||||
Log.e(DownloadWorker.TAG, context.getString(R.string.failed_download), it)
|
||||
}
|
||||
notificationUtil.updateDownloadNotification(
|
||||
workID,
|
||||
context.getString(R.string.failed_download), 0, 0, item.title,
|
||||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
||||
)
|
||||
return Result.failure()
|
||||
}
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
private fun getDownloadLocation(type: String, context: Context): String? {
|
||||
val sharedPreferences = context.getSharedPreferences("root_preferences",
|
||||
Service.MODE_PRIVATE
|
||||
)
|
||||
val downloadsDir: String? = if (type == "audio") {
|
||||
sharedPreferences.getString("music_path", context.getString(R.string.music_path))
|
||||
} else {
|
||||
sharedPreferences.getString("video_path", context.getString(R.string.video_path))
|
||||
}
|
||||
return downloadsDir
|
||||
}
|
||||
|
||||
|
||||
private fun moveFile(originDir: File, downLocation: String, progress: (progress: Int) -> Unit){
|
||||
val destDir = Uri.parse(downLocation).run {
|
||||
DocumentsContract.buildChildDocumentsUriUsingTree(this, DocumentsContract.getTreeDocumentId(this))
|
||||
}
|
||||
val fileUtil = FileUtil()
|
||||
fileUtil.moveFile(originDir, context, destDir){ p ->
|
||||
progress(p)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var workID: Int = 0
|
||||
const val TAG = "DownloadWorker"
|
||||
lateinit var queue: MutableList<DownloadItem>
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import android.provider.DocumentsContract
|
|||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
|
|
@ -39,6 +40,7 @@ class FileTransferWorker(
|
|||
setForeground(foregroundInfo)
|
||||
|
||||
fileUtil.moveFile(originDir, context, destDir){ progress ->
|
||||
setProgressAsync(workDataOf("progress" to progress))
|
||||
notificationUtil.updateFileTransferNotification(id, progress)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@
|
|||
android:id="@+id/downloads_title"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="100dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="20dp"
|
||||
android:paddingBottom="20dp"
|
||||
android:paddingLeft="20dp"
|
||||
android:textSize="16sp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingStart="10dp"
|
||||
android:textSize="15sp"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
android:shadowRadius="2"
|
||||
|
|
@ -67,9 +67,9 @@
|
|||
android:layout_height="match_parent"
|
||||
android:gravity="bottom"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingRight="20dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingLeft="20dp"
|
||||
android:paddingLeft="10dp"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
|
|
@ -82,11 +82,11 @@
|
|||
android:id="@+id/downloads_info_time"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="bottom|right"
|
||||
android:gravity="bottom|end"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingRight="20dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingLeft="20dp"
|
||||
android:paddingLeft="10dp"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
android:paddingTop="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingStart="10dp"
|
||||
android:textSize="15sp"
|
||||
android:textSize="17sp"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
android:shadowRadius="2"
|
||||
|
|
@ -75,7 +75,7 @@
|
|||
android:paddingEnd="10dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:paddingStart="10dp"
|
||||
android:textSize="10sp"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
android:shadowRadius="1.5"
|
||||
|
|
|
|||
Loading…
Reference in a new issue