created download worker

This commit is contained in:
Denis Çerri 2023-01-18 19:52:27 +01:00
parent ec465f8bda
commit 335be8299c
No known key found for this signature in database
GPG key ID: 96B3554AF5B193EE
18 changed files with 367 additions and 373 deletions

View file

@ -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')"
]
}
}

View file

@ -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"

View file

@ -432,6 +432,8 @@ class DownloaderService : Service() {
Log.e(TAG, downloadInfo.downloadPath)
downloadInfo.downloadType = type
try {
for (activity in activities.keys) {
activity.runOnUiThread {

View file

@ -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

View file

@ -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)
}

View file

@ -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)

View file

@ -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
)

View file

@ -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
)

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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())
}
}
}

View file

@ -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) {
}
}
}

View file

@ -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,

View file

@ -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();
}
}

View 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>
}
}

View file

@ -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)
}

View file

@ -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"

View file

@ -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"