fixed download cancelling and title and author not renaming

This commit is contained in:
Denis Çerri 2023-01-31 19:02:16 +01:00
parent c653edb387
commit 144e8e9bc5
No known key found for this signature in database
GPG key ID: 95C43D517D830350
11 changed files with 159 additions and 113 deletions

View file

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "d658de0453c49534c5971583f41854db",
"identityHash": "e53569dbe0c02d62eda598075d73d5b1",
"entities": [
{
"tableName": "results",
@ -160,7 +160,7 @@
},
{
"tableName": "downloads",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `format` TEXT NOT NULL, `removeAudio` INTEGER NOT NULL DEFAULT 0, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `embedSubs` INTEGER NOT NULL, `addChapters` INTEGER NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `workID` INTEGER NOT NULL)",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `format` TEXT NOT NULL, `removeAudio` INTEGER NOT NULL DEFAULT 0, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `embedSubs` INTEGER NOT NULL, `addChapters` INTEGER NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued')",
"fields": [
{
"fieldPath": "id",
@ -265,12 +265,6 @@
"affinity": "TEXT",
"notNull": true,
"defaultValue": "'Queued'"
},
{
"fieldPath": "workID",
"columnName": "workID",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
@ -318,7 +312,7 @@
"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, 'd658de0453c49534c5971583f41854db')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e53569dbe0c02d62eda598075d73d5b1')"
]
}
}

View file

@ -3,8 +3,6 @@ package com.deniscerri.ytdlnis.database.dao
import androidx.lifecycle.LiveData
import androidx.room.*
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.util.FileUtil
@Dao
interface DownloadDao {
@ -21,9 +19,6 @@ interface DownloadDao {
@Query("SELECT * FROM downloads WHERE status='Processing'")
fun getProcessingDownloads() : LiveData<List<DownloadItem>>
@Query("SELECT * FROM downloads WHERE workID=:workID")
fun getDownloadByWorkId(workID: Long) : DownloadItem
@Query("SELECT * FROM downloads WHERE id=:id LIMIT 1")
fun getDownloadById(id: Long) : DownloadItem
@ -50,4 +45,8 @@ interface DownloadDao {
@Query("UPDATE downloads SET status='Queued' WHERE status='Processing'")
suspend fun queueAllProcessing()
@Query("SELECT * FROM downloads WHERE url=:url AND (status='Error' OR status='Cancelled') LIMIT 1")
fun checkIfErrorOrCancelled(url: String) : DownloadItem
}

View file

@ -25,6 +25,5 @@ data class DownloadItem(
val addChapters: Boolean,
val SaveThumb: Boolean,
@ColumnInfo(defaultValue = "Queued")
var status: String,
var workID: Long
var status: String
)

View file

@ -1,9 +1,9 @@
package com.deniscerri.ytdlnis.database.repository
import android.util.Log
import androidx.lifecycle.LiveData
import com.deniscerri.ytdlnis.database.dao.DownloadDao
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ResultItem
class DownloadRepository(private val downloadDao: DownloadDao) {
val allDownloads : LiveData<List<DownloadItem>> = downloadDao.getAllDownloads()
@ -11,8 +11,8 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
val queuedDownloads : LiveData<List<DownloadItem>> = downloadDao.getQueuedDownloads()
val processingDownloads : LiveData<List<DownloadItem>> = downloadDao.getProcessingDownloads()
enum class status {
Active, Queued, Errored, Processing
enum class Status {
Active, Queued, Error, Processing, Cancelled
}
suspend fun insert(item: DownloadItem) : Long {
@ -27,12 +27,8 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
downloadDao.update(item)
}
fun getDownloadByWorkID(workID: Long) : DownloadItem{
return downloadDao.getDownloadByWorkId(workID)
}
suspend fun setDownloadStatus(item: DownloadItem, status: status){
suspend fun setDownloadStatus(item: DownloadItem, status: Status){
item.status = status.toString()
update(item);
}
@ -52,4 +48,8 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
suspend fun queueAllProcessing(){
downloadDao.queueAllProcessing()
}
fun checkIfPresent(item: ResultItem): DownloadItem{
return downloadDao.checkIfErrorOrCancelled(item.url)
}
}

View file

@ -3,10 +3,15 @@ package com.deniscerri.ytdlnis.database.viewmodel
import android.app.Activity
import android.app.Application
import android.content.SharedPreferences
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import androidx.work.Data
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.App
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.DBManager
@ -14,6 +19,7 @@ import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.work.DownloadWorker
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -90,8 +96,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
resultItem.duration,
type,
getFormat(resultItem, type), false,
"", resultItem.website, "", resultItem.playlistTitle, embedSubs, addChapters, saveThumb, DownloadRepository.status.Processing.toString(),
0
"", resultItem.website, "", resultItem.playlistTitle, embedSubs, addChapters, saveThumb, DownloadRepository.Status.Processing.toString()
)
}
@ -126,14 +131,23 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
return list
}
fun putDownloadsForProcessing(items: List<ResultItem?>) : LiveData<List<Long>> {
fun putDownloadsForProcessing(items: List<ResultItem?>, downloadItems: List<DownloadItem>) : LiveData<List<Long>> {
val result = MutableLiveData<List<Long>>()
viewModelScope.launch(Dispatchers.IO){
val list : MutableList<Long> = mutableListOf()
items.forEachIndexed { i, it ->
val tmpDownloadItem = createDownloadItemFromResult(it!!, "video")
val id = repository.insert(tmpDownloadItem)
list.add(id)
val tmpDownloadItem = downloadItems[i]
try {
val item = repository.checkIfPresent(it!!)
tmpDownloadItem.id = item.id
tmpDownloadItem.status = DownloadRepository.Status.Processing.toString()
repository.update(tmpDownloadItem)
list.add(tmpDownloadItem.id)
}catch (e: Exception){
val id = repository.insert(tmpDownloadItem)
list.add(id)
}
}
result.postValue(list)
}
@ -153,7 +167,22 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
return Gson().fromJson(string, DownloadItem::class.java)
}
fun queueAllProcessing()= viewModelScope.launch(Dispatchers.IO) {
repository.queueAllProcessing();
fun queueDownloads(items: List<DownloadItem>)= viewModelScope.launch(Dispatchers.IO) {
val context = getApplication<App>().applicationContext
items.forEach {
it.status = DownloadRepository.Status.Queued.toString()
repository.update(it)
val workRequest = OneTimeWorkRequestBuilder<DownloadWorker>()
.setInputData(Data.Builder().putLong("id", it.id).build())
.addTag("download")
.build()
WorkManager.getInstance(context).beginUniqueWork(
it.id.toString(),
ExistingWorkPolicy.KEEP,
workRequest
).enqueue()
}
}
}

View file

@ -1,14 +1,27 @@
package com.deniscerri.ytdlnis.receiver
import android.content.*
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.yausername.youtubedl_android.YoutubeDL
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
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())
val notificationUtil = NotificationUtil(c)
YoutubeDL.getInstance().destroyProcessById(id.toString());
WorkManager.getInstance(c).cancelUniqueWork(id.toString())
notificationUtil.cancelDownloadNotification(id)
}
}
}

View file

@ -20,6 +20,7 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.HomeAdapter
@ -72,6 +73,8 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
private var sharedPreferences: SharedPreferences? = null
private var _binding : FragmentHomeBinding? = null
private var workManager: WorkManager? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@ -188,6 +191,14 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
} else {
resultViewModel.checkTrending()
}
WorkManager.getInstance(requireContext())
.getWorkInfosByTagLiveData("download")
.observe(viewLifecycleOwner){ list ->
list.forEach {
//Toast.makeText(context, """${it.progress.getInt("progress", 0)} ${it.progress.getString("output")}""", Toast.LENGTH_SHORT).show()
}
}
}
private fun initMenu() {
@ -341,8 +352,8 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
private fun showSingleDownloadSheet(resultItem : ResultItem, type: String){
val downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, type)
downloadViewModel.insertDownload(downloadItem).observe(viewLifecycleOwner) {
downloadItem.id = it
downloadViewModel.putDownloadsForProcessing(listOf(resultItem), listOf(downloadItem)).observe(viewLifecycleOwner) {
downloadItem.id = it[0]
val bottomSheet = DownloadBottomSheetDialog(downloadItem)
bottomSheet.show(parentFragmentManager, "downloadSingleSheet")
}
@ -395,7 +406,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
if (viewIdName.isNotEmpty()) {
if (viewIdName == "downloadSelected") {
val downloadList = downloadViewModel.turnResultItemstoDownloadItems(selectedObjects!!)
downloadViewModel.putDownloadsForProcessing(selectedObjects!!).observe(viewLifecycleOwner) {
downloadViewModel.putDownloadsForProcessing(selectedObjects!!, downloadList).observe(viewLifecycleOwner) {
it.forEachIndexed { i, itemID ->
downloadList[i].id = itemID
}
@ -405,7 +416,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
}
if (viewIdName == "downloadAll") {
val downloadList = downloadViewModel.turnResultItemstoDownloadItems(resultsList!!)
downloadViewModel.putDownloadsForProcessing(resultsList!!).observe(viewLifecycleOwner) {
downloadViewModel.putDownloadsForProcessing(resultsList!!, downloadList).observe(viewLifecycleOwner) {
it.forEachIndexed { i, itemID ->
downloadList[i].id = itemID
}

View file

@ -104,20 +104,7 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener {
downloadItem.status = DownloadRepository.status.Queued.toString()
val workID = SystemClock.uptimeMillis()
downloadItem.workID = workID
downloadViewModel.insertDownload(downloadItem)
val workRequest = OneTimeWorkRequestBuilder<DownloadWorker>()
.setInputData(Data.Builder().putLong("workID", workID).build())
.build()
WorkManager.getInstance(requireContext()).beginUniqueWork(
downloadItem.id.toString(),
ExistingWorkPolicy.KEEP,
workRequest
).enqueue()
downloadViewModel.queueDownloads(listOf(downloadItem))
dismiss()
}
}

View file

@ -81,23 +81,7 @@ class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) :
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener {
downloadViewModel.queueAllProcessing()
// 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()
// }
downloadViewModel.queueDownloads(items)
dismiss()
}
}

View file

@ -79,6 +79,7 @@ class FileUtil() {
return context.getString(R.string.unfound_file);
}
@Throws(Exception::class)
fun moveFile(originDir: File, context: Context, destDir: String, progress: (p: Int) -> Unit) : String {
originDir.listFiles()?.forEach {
if (it.name.equals("rList")){
@ -88,7 +89,7 @@ class FileUtil() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
val f = File(formatPath(destDir)+"/"+it.name)
if (!f.exists()) f.mkdir()
f.mkdirs()
Files.move(it.toPath(), f.toPath(), StandardCopyOption.REPLACE_EXISTING)
progress(100)
}else{

View file

@ -4,20 +4,18 @@ import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.provider.DocumentsContract
import android.util.Log
import android.widget.Toast
import androidx.work.ForegroundInfo
import androidx.work.Worker
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
@ -27,7 +25,6 @@ import com.yausername.youtubedl_android.YoutubeDLRequest
import kotlinx.coroutines.runBlocking
import java.io.File
import java.util.regex.Pattern
import kotlin.math.abs
class DownloadWorker(
@ -35,22 +32,35 @@ class DownloadWorker(
workerParams: WorkerParameters
) : Worker(context, workerParams) {
override fun doWork(): Result {
workID = inputData.getLong("workID", SystemClock.uptimeMillis())
itemId = inputData.getLong("id", 0)
if (itemId == 0L) return Result.failure()
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
val handler = Handler(Looper.getMainLooper())
val downloadItem: DownloadItem?
try {
downloadItem = repository.getItemByID(itemId)
}catch (e: Exception){
e.printStackTrace()
return Result.failure()
}
Log.e(TAG, downloadItem.toString())
val downloadItem = repository.getDownloadByWorkID(workID)
runBlocking{
repository.setDownloadStatus(downloadItem, DownloadRepository.status.Active)
repository.setDownloadStatus(downloadItem, DownloadRepository.Status.Active)
}
val intent = Intent(context, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, downloadItem.title, workID.toInt(), NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
val foregroundInfo = ForegroundInfo(workID.toInt(), notification)
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, downloadItem.title, downloadItem.id.toInt(), NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
val foregroundInfo = ForegroundInfo(downloadItem.id.toInt(), notification)
setForegroundAsync(foregroundInfo)
@ -61,7 +71,7 @@ class DownloadWorker(
val tempFolder = StringBuilder(context.cacheDir.absolutePath + """/${downloadItem.title}##${downloadItem.type}""")
tempFolder.append("##${downloadItem.format.format_id}")
var tempFileDir = File(tempFolder.toString())
val tempFileDir = File(tempFolder.toString())
tempFileDir.delete()
tempFileDir.mkdir()
@ -90,6 +100,9 @@ class DownloadWorker(
request.addOption("--sponsorblock-remove", filters)
}
request.addCommands(listOf("--replace-in-metadata","title",".*.",downloadItem.title));
request.addCommands(listOf("--replace-in-metadata","uploader",".*.",downloadItem.author));
when(type){
"audio" -> {
request.addOption("-x")
@ -171,24 +184,32 @@ class DownloadWorker(
runCatching {
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
setProgressAsync(workDataOf("progress" to progress.toInt()))
setProgressAsync(workDataOf("output" to line))
val title: String = downloadItem.title
notificationUtil.updateDownloadNotification(
downloadItem.workID.toInt(),
downloadItem.id.toInt(),
line, progress.toInt(), 0, title,
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
)
}
}.onSuccess {
//move file from internal to set download directory
val finalPath = moveFile(tempFileDir.absoluteFile, downloadLocation){ progress ->
setProgressAsync(workDataOf("progress" to progress))
var finalPath : String?
try {
finalPath = moveFile(tempFileDir.absoluteFile, downloadLocation){ progress ->
setProgressAsync(workDataOf("progress" to progress))
}
}catch (e: Exception){
finalPath = context.getString(R.string.unfound_file)
handler.postDelayed({
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
}, 1000)
}
//put download in history
val incognito = sharedPreferences.getBoolean("incognito", false)
if (!incognito) {
val unixtime = System.currentTimeMillis() / 1000
val historyItem = HistoryItem(0, downloadItem.url, downloadItem.title, downloadItem.author, downloadItem.duration, downloadItem.thumb, downloadItem.type, unixtime, finalPath, downloadItem.website, downloadItem.format)
val historyItem = HistoryItem(0, downloadItem.url, downloadItem.title, downloadItem.author, downloadItem.duration, downloadItem.thumb, downloadItem.type, unixtime, finalPath!!, downloadItem.website, downloadItem.format)
runBlocking {
historyDao.insert(historyItem)
}
@ -197,43 +218,51 @@ class DownloadWorker(
dao.delete(downloadItem.id)
}
}.onFailure {
tempFileDir.delete()
Looper.prepare()
Toast.makeText(context, it.message, Toast.LENGTH_LONG).show()
Log.e(TAG, context.getString(R.string.failed_download), it)
notificationUtil.updateDownloadNotification(
downloadItem.workID.toInt(),
context.getString(R.string.failed_download), 0, 0, downloadItem.title,
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
)
if (it is YoutubeDL.CanceledException) {
downloadItem.status = DownloadRepository.Status.Cancelled.toString()
runBlocking {
dao.update(downloadItem)
}
return Result.failure()
}else{
tempFileDir.delete()
handler.postDelayed({
Toast.makeText(context, it.message, Toast.LENGTH_SHORT).show()
}, 1000)
downloadItem.status = DownloadRepository.status.Errored.toString()
runBlocking {
dao.update(downloadItem)
Log.e(TAG, context.getString(R.string.failed_download), it)
notificationUtil.updateDownloadNotification(
downloadItem.id.toInt(),
context.getString(R.string.failed_download), 0, 0, downloadItem.title,
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
)
downloadItem.status = DownloadRepository.Status.Error.toString()
runBlocking {
dao.update(downloadItem)
}
return Result.failure()
}
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 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
// }
@Throws(Exception::class)
private fun moveFile(originDir: File, downLocation: String, progress: (progress: Int) -> Unit) : String{
val destDir = Uri.parse(downLocation).run {
DocumentsContract.buildChildDocumentsUriUsingTree(this, DocumentsContract.getTreeDocumentId(this))
}
val fileUtil = FileUtil()
val path = fileUtil.moveFile(originDir, context, downLocation){ p ->
progress(p)
@ -242,7 +271,7 @@ class DownloadWorker(
}
companion object {
var workID: Long = 0
var itemId: Long = 0
const val TAG = "DownloadWorker"
}