reverted terminal mode to rxjava for simplicity sake

This commit is contained in:
Denis Çerri 2023-02-19 21:19:01 +01:00
parent 5482105a18
commit 3937dd6e4c
No known key found for this signature in database
GPG key ID: 95C43D517D830350
6 changed files with 142 additions and 99 deletions

View file

@ -38,8 +38,7 @@ class Converters {
return when(string){ return when(string){
"audio" -> DownloadViewModel.Type.audio "audio" -> DownloadViewModel.Type.audio
"video" -> DownloadViewModel.Type.video "video" -> DownloadViewModel.Type.video
"command" -> DownloadViewModel.Type.command else -> DownloadViewModel.Type.command
else -> DownloadViewModel.Type.terminal
} }
} }

View file

@ -52,7 +52,4 @@ interface DownloadDao {
@Query("SELECT * FROM downloads WHERE url=:url AND format=:format AND (status='Error' OR status='Cancelled') LIMIT 1") @Query("SELECT * FROM downloads WHERE url=:url AND format=:format AND (status='Error' OR status='Cancelled') LIMIT 1")
fun getUnfinishedByURLAndFormat(url: String, format: String) : DownloadItem fun getUnfinishedByURLAndFormat(url: String, format: String) : DownloadItem
@Query("SELECT * FROM downloads WHERE type='terminal' ORDER BY id DESC LIMIT 1")
fun getTerminalDownload() : DownloadItem
} }

View file

@ -65,7 +65,4 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
} }
} }
fun getTerminalDownload() : Long {
return downloadDao.getTerminalDownload().id
}
} }

View file

@ -37,7 +37,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
private var bestVideoFormat : Format private var bestVideoFormat : Format
private var bestAudioFormat : Format private var bestAudioFormat : Format
enum class Type { enum class Type {
audio, video, command, terminal audio, video, command
} }
init { init {
@ -204,39 +204,4 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
} }
} }
fun startTerminalDownload(command: String) = viewModelScope.launch(Dispatchers.IO) {
val downloadPath = sharedPreferences.getString("command_path", getApplication<App>().resources.getString(R.string.command_path))
val downloadItem = DownloadItem(0,
"",
"",
"",
"",
"",
Type.terminal,
Format("", "", 0, command),
downloadPath!!, "", "", "", AudioPreferences(), VideoPreferences(), "", false, DownloadRepository.Status.Processing.toString(), 0
)
downloadItem.status = DownloadRepository.Status.Queued.toString()
Log.e("aaaaaaaa", downloadItem.toString())
val id = repository.insert(downloadItem)
downloadItem.id = id
val workRequest = OneTimeWorkRequestBuilder<DownloadWorker>()
.setInputData(Data.Builder().putLong("id", downloadItem.id).build())
.addTag("terminal")
.build()
val context = getApplication<App>().applicationContext
WorkManager.getInstance(context).beginUniqueWork(
downloadItem.id.toString(),
ExistingWorkPolicy.KEEP,
workRequest
).enqueue()
}
fun getTerminalDownload(): Long {
return repository.getTerminalDownload();
}
} }

View file

@ -1,6 +1,8 @@
package com.deniscerri.ytdlnis.ui package com.deniscerri.ytdlnis.ui
import android.Manifest import android.Manifest
import android.app.Notification
import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
@ -10,36 +12,36 @@ import android.view.View
import android.widget.EditText import android.widget.EditText
import android.widget.ScrollView import android.widget.ScrollView
import android.widget.TextView import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.lifecycle.Observer import androidx.core.app.NotificationManagerCompat
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.work.WorkInfo
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.service.IDownloaderService
import com.deniscerri.ytdlnis.util.NotificationUtil import com.deniscerri.ytdlnis.util.NotificationUtil
import com.deniscerri.ytdlnis.work.DownloadWorker
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.yausername.youtubedl_android.YoutubeDL import com.yausername.youtubedl_android.YoutubeDL
import kotlinx.coroutines.Dispatchers import com.yausername.youtubedl_android.YoutubeDLRequest
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import java.io.File
import kotlinx.coroutines.withContext import java.util.regex.Pattern
class CustomCommandActivity : AppCompatActivity() { class CustomCommandActivity : AppCompatActivity() {
private var topAppBar: MaterialToolbar? = null private var topAppBar: MaterialToolbar? = null
private lateinit var downloadViewModel: DownloadViewModel
private lateinit var notificationUtil: NotificationUtil private lateinit var notificationUtil: NotificationUtil
private lateinit var workManager: WorkManager
private var isDownloadServiceRunning = false
private var output: TextView? = null private var output: TextView? = null
private var input: EditText? = null private var input: EditText? = null
private var fab: ExtendedFloatingActionButton? = null private var fab: ExtendedFloatingActionButton? = null
private var cancelFab: ExtendedFloatingActionButton? = null private var cancelFab: ExtendedFloatingActionButton? = null
private var iDownloaderService: IDownloaderService? = null
private var scrollView: ScrollView? = null private var scrollView: ScrollView? = null
var context: Context? = null var context: Context? = null
@ -56,6 +58,9 @@ class CustomCommandActivity : AppCompatActivity() {
input!!.requestFocus() input!!.requestFocus()
fab = findViewById(R.id.command_fab) fab = findViewById(R.id.command_fab)
fab!!.setOnClickListener { fab!!.setOnClickListener {
input!!.isEnabled = false
output!!.text = ""
swapFabs()
startDownload( startDownload(
input!!.text.toString() input!!.text.toString()
) )
@ -65,9 +70,7 @@ class CustomCommandActivity : AppCompatActivity() {
cancelDownload() cancelDownload()
input!!.isEnabled = true input!!.isEnabled = true
} }
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
notificationUtil = NotificationUtil(this) notificationUtil = NotificationUtil(this)
workManager = WorkManager.getInstance(this)
handleIntent(intent) handleIntent(intent)
} }
@ -88,33 +91,141 @@ class CustomCommandActivity : AppCompatActivity() {
} }
private fun swapFabs() {
val cancel = cancelFab!!.visibility
val start = fab!!.visibility
cancelFab!!.visibility = start
fab!!.visibility = cancel
}
private fun startDownload(command: String?) { private fun startDownload(command: String?) {
if (isDownloadServiceRunning) return downloadID = System.currentTimeMillis().toInt()
downloadViewModel.startTerminalDownload(command!!)
output!!.text = "" val theIntent = Intent(this, CustomCommandActivity::class.java)
workManager.getWorkInfosByTagLiveData("terminal") val pendingIntent = PendingIntent.getActivity(this, 0, theIntent, PendingIntent.FLAG_IMMUTABLE)
.observe(this){ list ->
list.forEach { val commandNotification: Notification =
if(it.progress.getString("output") != null){ notificationUtil.createDownloadServiceNotification(
output?.append("\n" + it.progress.getString("output") + "\n") pendingIntent,
output?.scrollTo(0, output!!.height) getString(R.string.terminal),
scrollView?.fullScroll(View.FOCUS_DOWN) downloadID,
NotificationUtil.COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID
)
with(NotificationManagerCompat.from(this)){
if (ActivityCompat.checkSelfPermission(
context!!,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
) {
notify(downloadID, commandNotification)
}
}
val commandRegex = "\"([^\"]*)\"|(\\S+)"
val request = YoutubeDLRequest(emptyList())
val tempFolder = StringBuilder(context!!.cacheDir.absolutePath + """/${command}##terminal""")
val tempFileDir = File(tempFolder.toString())
tempFileDir.delete()
tempFileDir.mkdir()
val m = Pattern.compile(commandRegex).matcher(command!!)
while (m.find()) {
if (m.group(1) != null) {
request.addOption(m.group(1)!!)
} else {
request.addOption(m.group(2)!!)
}
}
request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s")
cancelFab!!.visibility = View.VISIBLE
fab!!.visibility = View.GONE
val disposable: Disposable = Observable.fromCallable {
try{
YoutubeDL.getInstance().execute(request, downloadID.toString()){ progress, _, line ->
runOnUiThread {
output!!.append("\n" + line)
output!!.scrollTo(0, output!!.height)
scrollView!!.fullScroll(View.FOCUS_DOWN)
val title: String = getString(R.string.terminal)
notificationUtil.updateDownloadNotification(
downloadID,
line, progress.toInt(), 0, title,
NotificationUtil.COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID
)
} }
} }
}catch (e: Exception){
e.printStackTrace()
runOnUiThread {
input!!.isEnabled = true
cancelFab!!.visibility = View.GONE
fab!!.visibility = View.VISIBLE
}
} }
}
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
scrollView!!.scrollTo(0, scrollView!!.maxScrollAmount);
input!!.setText("yt-dlp ");
input!!.isEnabled = true;
cancelFab!!.visibility = View.GONE
fab!!.visibility = View.VISIBLE
//move file from internal to set download directory
try {
moveFile(tempFileDir.absoluteFile, getString(R.string.command_path)){ }
}catch (e: Exception){
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
}
notificationUtil.cancelDownloadNotification(downloadID)
}) { e ->
scrollView!!.scrollTo(0, scrollView!!.maxScrollAmount)
input!!.setText("yt-dlp ")
input!!.isEnabled = true
cancelFab!!.visibility = View.GONE
fab!!.visibility = View.VISIBLE
tempFileDir.delete()
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
Log.e(DownloadWorker.TAG, context?.getString(R.string.failed_download), e)
notificationUtil.cancelDownloadNotification(downloadID)
}
compositeDisposable.add(disposable)
}
@Throws(Exception::class)
private fun moveFile(originDir: File, downLocation: String, progress: (progress: Int) -> Unit){
val fileUtil = FileUtil()
fileUtil.moveFile(originDir, context!!, downLocation){ p ->
progress(p)
}
} }
private fun cancelDownload() { private fun cancelDownload() {
lifecycleScope.launch { lifecycleScope.launch {
val id = withContext(Dispatchers.IO){ downloadViewModel.getTerminalDownload(); } compositeDisposable.dispose()
YoutubeDL.getInstance().destroyProcessById(id.toString()) YoutubeDL.getInstance().destroyProcessById(downloadID.toString())
WorkManager.getInstance(this@CustomCommandActivity).cancelUniqueWork(id.toString()) notificationUtil.cancelDownloadNotification(downloadID)
notificationUtil.cancelDownloadNotification(id.toInt())
} }
} }
companion object { companion object {
private const val TAG = "CustomCommandActivity" private const val TAG = "CustomCommandActivity"
private var downloadID = System.currentTimeMillis().toInt()
private val compositeDisposable = CompositeDisposable()
} }
} }

View file

@ -190,32 +190,6 @@ class DownloadWorker(
} }
} }
} }
DownloadViewModel.Type.terminal -> {
if(downloadItem.format.format_note.startsWith("yt-dlp ")){
downloadItem.format.format_note = downloadItem.format.format_note.substring(6).trim();
}
val commandRegex = "\"([^\"]*)\"|(\\S+)"
request = YoutubeDLRequest(emptyList())
tempFolder = StringBuilder(context.cacheDir.absolutePath + """/${downloadItem.format.format_id}##terminal""")
tempFileDir = File(tempFolder.toString())
tempFileDir.delete()
tempFileDir.mkdir()
val m = Pattern.compile(commandRegex).matcher(downloadItem.format.format_note)
while (m.find()) {
if (m.group(1) != null) {
request.addOption(m.group(1)!!)
} else {
request.addOption(m.group(2)!!)
}
}
request.addOption("-o", tempFileDir.absolutePath + "/${downloadItem.customFileNameTemplate}.%(ext)s")
}
} }
runCatching { runCatching {