diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/Converters.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/Converters.kt index ac3b999c..01ecc909 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/Converters.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/Converters.kt @@ -38,8 +38,7 @@ class Converters { return when(string){ "audio" -> DownloadViewModel.Type.audio "video" -> DownloadViewModel.Type.video - "command" -> DownloadViewModel.Type.command - else -> DownloadViewModel.Type.terminal + else -> DownloadViewModel.Type.command } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt index f0ea706a..abccc1f5 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt @@ -52,7 +52,4 @@ interface DownloadDao { @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 - - @Query("SELECT * FROM downloads WHERE type='terminal' ORDER BY id DESC LIMIT 1") - fun getTerminalDownload() : DownloadItem } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt index a73183f2..81ce5bb6 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt @@ -65,7 +65,4 @@ class DownloadRepository(private val downloadDao: DownloadDao) { } } - fun getTerminalDownload() : Long { - return downloadDao.getTerminalDownload().id - } } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt index 81e1d28f..1ff93e5a 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt @@ -37,7 +37,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application private var bestVideoFormat : Format private var bestAudioFormat : Format enum class Type { - audio, video, command, terminal + audio, video, command } 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().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() - .setInputData(Data.Builder().putLong("id", downloadItem.id).build()) - .addTag("terminal") - .build() - val context = getApplication().applicationContext - WorkManager.getInstance(context).beginUniqueWork( - downloadItem.id.toString(), - ExistingWorkPolicy.KEEP, - workRequest - ).enqueue() - } - - - fun getTerminalDownload(): Long { - return repository.getTerminalDownload(); - } - } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/CustomCommandActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/CustomCommandActivity.kt index 3559aaa4..bcc56403 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/CustomCommandActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/CustomCommandActivity.kt @@ -1,6 +1,8 @@ package com.deniscerri.ytdlnis.ui import android.Manifest +import android.app.Notification +import android.app.PendingIntent import android.content.Context import android.content.Intent import android.content.pm.PackageManager @@ -10,36 +12,36 @@ import android.view.View import android.widget.EditText import android.widget.ScrollView import android.widget.TextView +import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat -import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProvider +import androidx.core.app.NotificationManagerCompat import androidx.lifecycle.lifecycleScope -import androidx.work.WorkInfo -import androidx.work.WorkManager import com.deniscerri.ytdlnis.R -import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel -import com.deniscerri.ytdlnis.service.IDownloaderService +import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.NotificationUtil +import com.deniscerri.ytdlnis.work.DownloadWorker import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton 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.runBlocking -import kotlinx.coroutines.withContext +import java.io.File +import java.util.regex.Pattern + class CustomCommandActivity : AppCompatActivity() { private var topAppBar: MaterialToolbar? = null - private lateinit var downloadViewModel: DownloadViewModel private lateinit var notificationUtil: NotificationUtil - private lateinit var workManager: WorkManager - private var isDownloadServiceRunning = false private var output: TextView? = null private var input: EditText? = null private var fab: ExtendedFloatingActionButton? = null private var cancelFab: ExtendedFloatingActionButton? = null - private var iDownloaderService: IDownloaderService? = null private var scrollView: ScrollView? = null var context: Context? = null @@ -56,6 +58,9 @@ class CustomCommandActivity : AppCompatActivity() { input!!.requestFocus() fab = findViewById(R.id.command_fab) fab!!.setOnClickListener { + input!!.isEnabled = false + output!!.text = "" + swapFabs() startDownload( input!!.text.toString() ) @@ -65,9 +70,7 @@ class CustomCommandActivity : AppCompatActivity() { cancelDownload() input!!.isEnabled = true } - downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] notificationUtil = NotificationUtil(this) - workManager = WorkManager.getInstance(this) 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?) { - if (isDownloadServiceRunning) return - downloadViewModel.startTerminalDownload(command!!) - output!!.text = "" - workManager.getWorkInfosByTagLiveData("terminal") - .observe(this){ list -> - list.forEach { - if(it.progress.getString("output") != null){ - output?.append("\n" + it.progress.getString("output") + "\n") - output?.scrollTo(0, output!!.height) - scrollView?.fullScroll(View.FOCUS_DOWN) + downloadID = System.currentTimeMillis().toInt() + + val theIntent = Intent(this, CustomCommandActivity::class.java) + val pendingIntent = PendingIntent.getActivity(this, 0, theIntent, PendingIntent.FLAG_IMMUTABLE) + + val commandNotification: Notification = + notificationUtil.createDownloadServiceNotification( + pendingIntent, + getString(R.string.terminal), + 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() { lifecycleScope.launch { - val id = withContext(Dispatchers.IO){ downloadViewModel.getTerminalDownload(); } - YoutubeDL.getInstance().destroyProcessById(id.toString()) - WorkManager.getInstance(this@CustomCommandActivity).cancelUniqueWork(id.toString()) - notificationUtil.cancelDownloadNotification(id.toInt()) + compositeDisposable.dispose() + YoutubeDL.getInstance().destroyProcessById(downloadID.toString()) + notificationUtil.cancelDownloadNotification(downloadID) } } companion object { private const val TAG = "CustomCommandActivity" + private var downloadID = System.currentTimeMillis().toInt() + private val compositeDisposable = CompositeDisposable() + } } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt b/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt index 0a4abac1..50c52797 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/work/DownloadWorker.kt @@ -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 {