fixed download cancelling and title and author not renaming
This commit is contained in:
parent
c653edb387
commit
144e8e9bc5
11 changed files with 159 additions and 113 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"identityHash": "d658de0453c49534c5971583f41854db",
|
"identityHash": "e53569dbe0c02d62eda598075d73d5b1",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "results",
|
"tableName": "results",
|
||||||
|
|
@ -160,7 +160,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "downloads",
|
"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": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
|
|
@ -265,12 +265,6 @@
|
||||||
"affinity": "TEXT",
|
"affinity": "TEXT",
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"defaultValue": "'Queued'"
|
"defaultValue": "'Queued'"
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "workID",
|
|
||||||
"columnName": "workID",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
|
@ -318,7 +312,7 @@
|
||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"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')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,8 +3,6 @@ package com.deniscerri.ytdlnis.database.dao
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface DownloadDao {
|
interface DownloadDao {
|
||||||
|
|
@ -21,9 +19,6 @@ interface DownloadDao {
|
||||||
@Query("SELECT * FROM downloads WHERE status='Processing'")
|
@Query("SELECT * FROM downloads WHERE status='Processing'")
|
||||||
fun getProcessingDownloads() : LiveData<List<DownloadItem>>
|
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")
|
@Query("SELECT * FROM downloads WHERE id=:id LIMIT 1")
|
||||||
fun getDownloadById(id: Long) : DownloadItem
|
fun getDownloadById(id: Long) : DownloadItem
|
||||||
|
|
||||||
|
|
@ -50,4 +45,8 @@ interface DownloadDao {
|
||||||
|
|
||||||
@Query("UPDATE downloads SET status='Queued' WHERE status='Processing'")
|
@Query("UPDATE downloads SET status='Queued' WHERE status='Processing'")
|
||||||
suspend fun queueAllProcessing()
|
suspend fun queueAllProcessing()
|
||||||
|
|
||||||
|
|
||||||
|
@Query("SELECT * FROM downloads WHERE url=:url AND (status='Error' OR status='Cancelled') LIMIT 1")
|
||||||
|
fun checkIfErrorOrCancelled(url: String) : DownloadItem
|
||||||
}
|
}
|
||||||
|
|
@ -25,6 +25,5 @@ data class DownloadItem(
|
||||||
val addChapters: Boolean,
|
val addChapters: Boolean,
|
||||||
val SaveThumb: Boolean,
|
val SaveThumb: Boolean,
|
||||||
@ColumnInfo(defaultValue = "Queued")
|
@ColumnInfo(defaultValue = "Queued")
|
||||||
var status: String,
|
var status: String
|
||||||
var workID: Long
|
|
||||||
)
|
)
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package com.deniscerri.ytdlnis.database.repository
|
package com.deniscerri.ytdlnis.database.repository
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
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.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
|
|
||||||
class DownloadRepository(private val downloadDao: DownloadDao) {
|
class DownloadRepository(private val downloadDao: DownloadDao) {
|
||||||
val allDownloads : LiveData<List<DownloadItem>> = downloadDao.getAllDownloads()
|
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 queuedDownloads : LiveData<List<DownloadItem>> = downloadDao.getQueuedDownloads()
|
||||||
val processingDownloads : LiveData<List<DownloadItem>> = downloadDao.getProcessingDownloads()
|
val processingDownloads : LiveData<List<DownloadItem>> = downloadDao.getProcessingDownloads()
|
||||||
|
|
||||||
enum class status {
|
enum class Status {
|
||||||
Active, Queued, Errored, Processing
|
Active, Queued, Error, Processing, Cancelled
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun insert(item: DownloadItem) : Long {
|
suspend fun insert(item: DownloadItem) : Long {
|
||||||
|
|
@ -27,12 +27,8 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
|
||||||
downloadDao.update(item)
|
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()
|
item.status = status.toString()
|
||||||
update(item);
|
update(item);
|
||||||
}
|
}
|
||||||
|
|
@ -52,4 +48,8 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
|
||||||
suspend fun queueAllProcessing(){
|
suspend fun queueAllProcessing(){
|
||||||
downloadDao.queueAllProcessing()
|
downloadDao.queueAllProcessing()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun checkIfPresent(item: ResultItem): DownloadItem{
|
||||||
|
return downloadDao.checkIfErrorOrCancelled(item.url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,10 +3,15 @@ package com.deniscerri.ytdlnis.database.viewmodel
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import android.util.Log
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
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.App
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.DBManager
|
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.Format
|
||||||
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.DownloadRepository
|
||||||
|
import com.deniscerri.ytdlnis.work.DownloadWorker
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -90,8 +96,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
resultItem.duration,
|
resultItem.duration,
|
||||||
type,
|
type,
|
||||||
getFormat(resultItem, type), false,
|
getFormat(resultItem, type), false,
|
||||||
"", resultItem.website, "", resultItem.playlistTitle, embedSubs, addChapters, saveThumb, DownloadRepository.status.Processing.toString(),
|
"", resultItem.website, "", resultItem.playlistTitle, embedSubs, addChapters, saveThumb, DownloadRepository.Status.Processing.toString()
|
||||||
0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -126,14 +131,23 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
return list
|
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>>()
|
val result = MutableLiveData<List<Long>>()
|
||||||
viewModelScope.launch(Dispatchers.IO){
|
viewModelScope.launch(Dispatchers.IO){
|
||||||
val list : MutableList<Long> = mutableListOf()
|
val list : MutableList<Long> = mutableListOf()
|
||||||
items.forEachIndexed { i, it ->
|
items.forEachIndexed { i, it ->
|
||||||
val tmpDownloadItem = createDownloadItemFromResult(it!!, "video")
|
val tmpDownloadItem = downloadItems[i]
|
||||||
val id = repository.insert(tmpDownloadItem)
|
try {
|
||||||
list.add(id)
|
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)
|
result.postValue(list)
|
||||||
}
|
}
|
||||||
|
|
@ -153,7 +167,22 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
return Gson().fromJson(string, DownloadItem::class.java)
|
return Gson().fromJson(string, DownloadItem::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun queueAllProcessing()= viewModelScope.launch(Dispatchers.IO) {
|
fun queueDownloads(items: List<DownloadItem>)= viewModelScope.launch(Dispatchers.IO) {
|
||||||
repository.queueAllProcessing();
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,14 +1,27 @@
|
||||||
package com.deniscerri.ytdlnis.receiver
|
package com.deniscerri.ytdlnis.receiver
|
||||||
|
|
||||||
import android.content.*
|
import android.content.*
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.work.WorkManager
|
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() {
|
class CancelDownloadNotificationReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(c: Context, intent: Intent) {
|
override fun onReceive(c: Context, intent: Intent) {
|
||||||
val message = intent.getStringExtra("cancel")
|
val message = intent.getStringExtra("cancel")
|
||||||
val id = intent.getIntExtra("workID", 0)
|
val id = intent.getIntExtra("workID", 0)
|
||||||
if (message != null) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -20,6 +20,7 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.work.WorkManager
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.HomeAdapter
|
import com.deniscerri.ytdlnis.adapter.HomeAdapter
|
||||||
|
|
@ -72,6 +73,8 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
||||||
private var sharedPreferences: SharedPreferences? = null
|
private var sharedPreferences: SharedPreferences? = null
|
||||||
private var _binding : FragmentHomeBinding? = null
|
private var _binding : FragmentHomeBinding? = null
|
||||||
|
|
||||||
|
private var workManager: WorkManager? = null
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
|
|
@ -188,6 +191,14 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
||||||
} else {
|
} else {
|
||||||
resultViewModel.checkTrending()
|
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() {
|
private fun initMenu() {
|
||||||
|
|
@ -341,8 +352,8 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
||||||
|
|
||||||
private fun showSingleDownloadSheet(resultItem : ResultItem, type: String){
|
private fun showSingleDownloadSheet(resultItem : ResultItem, type: String){
|
||||||
val downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, type)
|
val downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, type)
|
||||||
downloadViewModel.insertDownload(downloadItem).observe(viewLifecycleOwner) {
|
downloadViewModel.putDownloadsForProcessing(listOf(resultItem), listOf(downloadItem)).observe(viewLifecycleOwner) {
|
||||||
downloadItem.id = it
|
downloadItem.id = it[0]
|
||||||
val bottomSheet = DownloadBottomSheetDialog(downloadItem)
|
val bottomSheet = DownloadBottomSheetDialog(downloadItem)
|
||||||
bottomSheet.show(parentFragmentManager, "downloadSingleSheet")
|
bottomSheet.show(parentFragmentManager, "downloadSingleSheet")
|
||||||
}
|
}
|
||||||
|
|
@ -395,7 +406,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
||||||
if (viewIdName.isNotEmpty()) {
|
if (viewIdName.isNotEmpty()) {
|
||||||
if (viewIdName == "downloadSelected") {
|
if (viewIdName == "downloadSelected") {
|
||||||
val downloadList = downloadViewModel.turnResultItemstoDownloadItems(selectedObjects!!)
|
val downloadList = downloadViewModel.turnResultItemstoDownloadItems(selectedObjects!!)
|
||||||
downloadViewModel.putDownloadsForProcessing(selectedObjects!!).observe(viewLifecycleOwner) {
|
downloadViewModel.putDownloadsForProcessing(selectedObjects!!, downloadList).observe(viewLifecycleOwner) {
|
||||||
it.forEachIndexed { i, itemID ->
|
it.forEachIndexed { i, itemID ->
|
||||||
downloadList[i].id = itemID
|
downloadList[i].id = itemID
|
||||||
}
|
}
|
||||||
|
|
@ -405,7 +416,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
||||||
}
|
}
|
||||||
if (viewIdName == "downloadAll") {
|
if (viewIdName == "downloadAll") {
|
||||||
val downloadList = downloadViewModel.turnResultItemstoDownloadItems(resultsList!!)
|
val downloadList = downloadViewModel.turnResultItemstoDownloadItems(resultsList!!)
|
||||||
downloadViewModel.putDownloadsForProcessing(resultsList!!).observe(viewLifecycleOwner) {
|
downloadViewModel.putDownloadsForProcessing(resultsList!!, downloadList).observe(viewLifecycleOwner) {
|
||||||
it.forEachIndexed { i, itemID ->
|
it.forEachIndexed { i, itemID ->
|
||||||
downloadList[i].id = itemID
|
downloadList[i].id = itemID
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,20 +104,7 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
|
||||||
|
|
||||||
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
|
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
|
||||||
download!!.setOnClickListener {
|
download!!.setOnClickListener {
|
||||||
downloadItem.status = DownloadRepository.status.Queued.toString()
|
downloadViewModel.queueDownloads(listOf(downloadItem))
|
||||||
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()
|
|
||||||
|
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,23 +81,7 @@ class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) :
|
||||||
|
|
||||||
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
|
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
|
||||||
download!!.setOnClickListener {
|
download!!.setOnClickListener {
|
||||||
downloadViewModel.queueAllProcessing()
|
downloadViewModel.queueDownloads(items)
|
||||||
// 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()
|
|
||||||
// }
|
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ class FileUtil() {
|
||||||
|
|
||||||
return context.getString(R.string.unfound_file);
|
return context.getString(R.string.unfound_file);
|
||||||
}
|
}
|
||||||
|
@Throws(Exception::class)
|
||||||
fun moveFile(originDir: File, context: Context, destDir: String, progress: (p: Int) -> Unit) : String {
|
fun moveFile(originDir: File, context: Context, destDir: String, progress: (p: Int) -> Unit) : String {
|
||||||
originDir.listFiles()?.forEach {
|
originDir.listFiles()?.forEach {
|
||||||
if (it.name.equals("rList")){
|
if (it.name.equals("rList")){
|
||||||
|
|
@ -88,7 +89,7 @@ class FileUtil() {
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
|
||||||
val f = File(formatPath(destDir)+"/"+it.name)
|
val f = File(formatPath(destDir)+"/"+it.name)
|
||||||
if (!f.exists()) f.mkdir()
|
f.mkdirs()
|
||||||
Files.move(it.toPath(), f.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
Files.move(it.toPath(), f.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||||
progress(100)
|
progress(100)
|
||||||
}else{
|
}else{
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,18 @@ import android.app.PendingIntent
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.os.SystemClock
|
|
||||||
import android.provider.DocumentsContract
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.work.ForegroundInfo
|
import androidx.work.ForegroundInfo
|
||||||
import androidx.work.Worker
|
import androidx.work.Worker
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
import com.deniscerri.ytdlnis.BuildConfig
|
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
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.HistoryItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
|
|
@ -27,7 +25,6 @@ import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import kotlin.math.abs
|
|
||||||
|
|
||||||
|
|
||||||
class DownloadWorker(
|
class DownloadWorker(
|
||||||
|
|
@ -35,22 +32,35 @@ class DownloadWorker(
|
||||||
workerParams: WorkerParameters
|
workerParams: WorkerParameters
|
||||||
) : Worker(context, workerParams) {
|
) : Worker(context, workerParams) {
|
||||||
override fun doWork(): Result {
|
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 notificationUtil = NotificationUtil(context)
|
||||||
val dbManager = DBManager.getInstance(context)
|
val dbManager = DBManager.getInstance(context)
|
||||||
val dao = dbManager.downloadDao
|
val dao = dbManager.downloadDao
|
||||||
val repository = DownloadRepository(dao)
|
val repository = DownloadRepository(dao)
|
||||||
val commandTemplateDao = dbManager.commandTemplateDao
|
val commandTemplateDao = dbManager.commandTemplateDao
|
||||||
val historyDao = dbManager.historyDao
|
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{
|
runBlocking{
|
||||||
repository.setDownloadStatus(downloadItem, DownloadRepository.status.Active)
|
repository.setDownloadStatus(downloadItem, DownloadRepository.Status.Active)
|
||||||
}
|
}
|
||||||
val intent = Intent(context, MainActivity::class.java)
|
val intent = Intent(context, MainActivity::class.java)
|
||||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
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 notification = notificationUtil.createDownloadServiceNotification(pendingIntent, downloadItem.title, downloadItem.id.toInt(), NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||||
val foregroundInfo = ForegroundInfo(workID.toInt(), notification)
|
val foregroundInfo = ForegroundInfo(downloadItem.id.toInt(), notification)
|
||||||
setForegroundAsync(foregroundInfo)
|
setForegroundAsync(foregroundInfo)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -61,7 +71,7 @@ class DownloadWorker(
|
||||||
|
|
||||||
val tempFolder = StringBuilder(context.cacheDir.absolutePath + """/${downloadItem.title}##${downloadItem.type}""")
|
val tempFolder = StringBuilder(context.cacheDir.absolutePath + """/${downloadItem.title}##${downloadItem.type}""")
|
||||||
tempFolder.append("##${downloadItem.format.format_id}")
|
tempFolder.append("##${downloadItem.format.format_id}")
|
||||||
var tempFileDir = File(tempFolder.toString())
|
val tempFileDir = File(tempFolder.toString())
|
||||||
tempFileDir.delete()
|
tempFileDir.delete()
|
||||||
tempFileDir.mkdir()
|
tempFileDir.mkdir()
|
||||||
|
|
||||||
|
|
@ -90,6 +100,9 @@ class DownloadWorker(
|
||||||
request.addOption("--sponsorblock-remove", filters)
|
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){
|
when(type){
|
||||||
"audio" -> {
|
"audio" -> {
|
||||||
request.addOption("-x")
|
request.addOption("-x")
|
||||||
|
|
@ -171,24 +184,32 @@ class DownloadWorker(
|
||||||
runCatching {
|
runCatching {
|
||||||
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
|
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
|
||||||
setProgressAsync(workDataOf("progress" to progress.toInt()))
|
setProgressAsync(workDataOf("progress" to progress.toInt()))
|
||||||
|
setProgressAsync(workDataOf("output" to line))
|
||||||
val title: String = downloadItem.title
|
val title: String = downloadItem.title
|
||||||
notificationUtil.updateDownloadNotification(
|
notificationUtil.updateDownloadNotification(
|
||||||
downloadItem.workID.toInt(),
|
downloadItem.id.toInt(),
|
||||||
line, progress.toInt(), 0, title,
|
line, progress.toInt(), 0, title,
|
||||||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
//move file from internal to set download directory
|
//move file from internal to set download directory
|
||||||
|
var finalPath : String?
|
||||||
val finalPath = moveFile(tempFileDir.absoluteFile, downloadLocation){ progress ->
|
try {
|
||||||
setProgressAsync(workDataOf("progress" to progress))
|
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
|
//put download in history
|
||||||
val incognito = sharedPreferences.getBoolean("incognito", false)
|
val incognito = sharedPreferences.getBoolean("incognito", false)
|
||||||
if (!incognito) {
|
if (!incognito) {
|
||||||
val unixtime = System.currentTimeMillis() / 1000
|
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 {
|
runBlocking {
|
||||||
historyDao.insert(historyItem)
|
historyDao.insert(historyItem)
|
||||||
}
|
}
|
||||||
|
|
@ -197,43 +218,51 @@ class DownloadWorker(
|
||||||
dao.delete(downloadItem.id)
|
dao.delete(downloadItem.id)
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
tempFileDir.delete()
|
if (it is YoutubeDL.CanceledException) {
|
||||||
Looper.prepare()
|
downloadItem.status = DownloadRepository.Status.Cancelled.toString()
|
||||||
Toast.makeText(context, it.message, Toast.LENGTH_LONG).show()
|
runBlocking {
|
||||||
Log.e(TAG, context.getString(R.string.failed_download), it)
|
dao.update(downloadItem)
|
||||||
notificationUtil.updateDownloadNotification(
|
}
|
||||||
downloadItem.workID.toInt(),
|
return Result.failure()
|
||||||
context.getString(R.string.failed_download), 0, 0, downloadItem.title,
|
}else{
|
||||||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
tempFileDir.delete()
|
||||||
)
|
handler.postDelayed({
|
||||||
|
Toast.makeText(context, it.message, Toast.LENGTH_SHORT).show()
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
downloadItem.status = DownloadRepository.status.Errored.toString()
|
Log.e(TAG, context.getString(R.string.failed_download), it)
|
||||||
runBlocking {
|
notificationUtil.updateDownloadNotification(
|
||||||
dao.update(downloadItem)
|
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()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDownloadLocation(type: String, context: Context): String? {
|
// private fun getDownloadLocation(type: String, context: Context): String? {
|
||||||
val sharedPreferences = context.getSharedPreferences("root_preferences",
|
// val sharedPreferences = context.getSharedPreferences("root_preferences",
|
||||||
Service.MODE_PRIVATE
|
// Service.MODE_PRIVATE
|
||||||
)
|
// )
|
||||||
val downloadsDir: String? = if (type == "audio") {
|
// val downloadsDir: String? = if (type == "audio") {
|
||||||
sharedPreferences.getString("music_path", context.getString(R.string.music_path))
|
// sharedPreferences.getString("music_path", context.getString(R.string.music_path))
|
||||||
} else {
|
// } else {
|
||||||
sharedPreferences.getString("video_path", context.getString(R.string.video_path))
|
// sharedPreferences.getString("video_path", context.getString(R.string.video_path))
|
||||||
}
|
// }
|
||||||
return downloadsDir
|
// return downloadsDir
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
private fun moveFile(originDir: File, downLocation: String, progress: (progress: Int) -> Unit) : String{
|
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 fileUtil = FileUtil()
|
||||||
val path = fileUtil.moveFile(originDir, context, downLocation){ p ->
|
val path = fileUtil.moveFile(originDir, context, downLocation){ p ->
|
||||||
progress(p)
|
progress(p)
|
||||||
|
|
@ -242,7 +271,7 @@ class DownloadWorker(
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var workID: Long = 0
|
var itemId: Long = 0
|
||||||
const val TAG = "DownloadWorker"
|
const val TAG = "DownloadWorker"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue