diff --git a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt index 80a297d9..9eea3b26 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt @@ -1298,33 +1298,28 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel updateToStatus(id, DownloadRepository.Status.Paused) } - suspend fun pauseAllDownloads() { + fun pauseAllDownloads() = viewModelScope.launch { pausedAllDownloads.value = PausedAllDownloadsState.PROCESSING isPausingResuming = true WorkManager.getInstance(application).cancelAllWorkByTag("download") val activeDownloadsList = withContext(Dispatchers.IO){ getActiveDownloads() } - activeDownloadsList.forEach { cancelDownloadOnly(it.id) } - - withContext(Dispatchers.IO) { + delay(1000) + isPausingResuming = false + withContext(Dispatchers.IO){ repository.setDownloadStatusMultiple(activeDownloadsList.map { it.id }, DownloadRepository.Status.Paused) } - delay(1500) - isPausingResuming = false - - - withContext(Dispatchers.Main) { - pausedAllDownloads.value = PausedAllDownloadsState.RESUME - } + pausedAllDownloads.value = PausedAllDownloadsState.RESUME } - suspend fun resumeAllDownloads() { + fun resumeAllDownloads() = viewModelScope.launch { pausedAllDownloads.value = PausedAllDownloadsState.PROCESSING isPausingResuming = true + WorkManager.getInstance(application).cancelAllWorkByTag("download") val paused = withContext(Dispatchers.IO) { dao.getPausedDownloadsList() } @@ -1333,11 +1328,9 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel dbManager.downloadDao.resetPausedToQueued() repository.startDownloadWorker(paused, application) } - delay(1500) + delay(1000) isPausingResuming = false - withContext(Dispatchers.Main) { - pausedAllDownloads.value = PausedAllDownloadsState.PAUSE - } + pausedAllDownloads.value = PausedAllDownloadsState.PAUSE } fun deleteAll() = viewModelScope.launch { diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/GenerateYoutubePoTokensFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/GenerateYoutubePoTokensFragment.kt index bb0107b5..3e86715c 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/GenerateYoutubePoTokensFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/GenerateYoutubePoTokensFragment.kt @@ -1,8 +1,6 @@ package com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens import android.app.Activity -import android.app.ActivityManager -import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.os.Bundle @@ -32,9 +30,6 @@ class GenerateYoutubePoTokensFragment : Fragment() { private lateinit var preferences: SharedPreferences private lateinit var configuration : MutableList private lateinit var workManager : WorkManager - private lateinit var poTokenGenerator: PoTokenGenerator - - private val sampleURL = "https://www.youtube.com/watch?v=aqz-KE-bpKQ" // Big Buck Bunny override fun onCreateView( inflater: LayoutInflater, @@ -44,7 +39,6 @@ class GenerateYoutubePoTokensFragment : Fragment() { settingsActivity = activity as SettingsActivity settingsActivity.changeTopAppbarTitle(getString(R.string.generate_potokens)) preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) - poTokenGenerator = PoTokenGenerator() workManager = WorkManager.getInstance(requireContext()) return inflater.inflate(R.layout.fragment_generate_youtube_po_token, container, false) } diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenException.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenException.kt deleted file mode 100644 index d7d45ee2..00000000 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenException.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview - -class PoTokenException(message: String) : Exception(message) - -// to be thrown if the WebView provided by the system is broken -class BadWebViewException(message: String) : Exception(message) - -fun buildExceptionForJsError(error: String): Exception { - return if (error.contains("SyntaxError")) - BadWebViewException(error) - else - PoTokenException(error) -} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenWebViewLoginActivity.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenWebViewLoginActivity.kt index 53097ef0..2434f431 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenWebViewLoginActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenWebViewLoginActivity.kt @@ -5,6 +5,7 @@ import android.content.Intent import android.content.SharedPreferences import android.os.Build import android.os.Bundle +import android.view.MenuItem import android.webkit.CookieManager import android.webkit.WebView import android.widget.Toast @@ -23,7 +24,8 @@ import com.deniscerri.ytdl.R import com.deniscerri.ytdl.database.models.CookieItem import com.deniscerri.ytdl.database.viewmodel.CookieViewModel import com.deniscerri.ytdl.ui.BaseActivity -import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.PoTokenGenerator +import com.deniscerri.ytdl.util.UiUtil +import com.deniscerri.ytdl.util.extractors.newpipe.potoken.NewPipePoTokenGenerator import com.google.accompanist.web.AccompanistWebChromeClient import com.google.accompanist.web.AccompanistWebViewClient import com.google.accompanist.web.WebView @@ -57,7 +59,18 @@ class PoTokenWebViewLoginActivity : BaseActivity() { lifecycleScope.launch { val appbar = findViewById(R.id.webview_appbarlayout) toolbar = appbar.findViewById(R.id.webviewToolbar) - toolbar.menu.forEach { it.isVisible = false } + + toolbar.setOnMenuItemClickListener { m : MenuItem -> + when(m.itemId) { + R.id.get_data_sync_id -> { + webView.evaluateJavascript("ytcfg.get('DATASYNC_ID')") { id -> + UiUtil.copyToClipboard(id.replace("\"", ""), this@PoTokenWebViewLoginActivity) + } + } + else -> {} + } + true + } generateBtn = toolbar.findViewById(R.id.generate) webViewCompose = findViewById(R.id.webview_compose) @@ -82,7 +95,7 @@ class PoTokenWebViewLoginActivity : BaseActivity() { generateBtn.isEnabled = false lifecycleScope.launch { - val generator = PoTokenGenerator() + val generator = NewPipePoTokenGenerator() val res = withContext(Dispatchers.IO) { generator.getWebClientPoToken(sampleVideoID) } @@ -100,7 +113,7 @@ class PoTokenWebViewLoginActivity : BaseActivity() { //update cookies withContext(Dispatchers.IO) { - val url = "https://youtube.com" + val url = "Po Token Generated Cookies" cookiesViewModel.getCookiesFromDB(url).getOrNull()?.let { kotlin.runCatching { cookiesViewModel.insert( diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/updating/UpdateSettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/updating/UpdateSettingsFragment.kt index bc5ea643..37ca7f58 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/updating/UpdateSettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/updating/UpdateSettingsFragment.kt @@ -59,13 +59,18 @@ class UpdateSettingsFragment : BaseSettingsFragment() { } ytdlVersion?.apply { - summary = preferences.getString("ytdl-version", "") - if (summary?.isBlank() == true) { - setYTDLPVersion() - } - setOnPreferenceClickListener { - initYTDLUpdate() - true + lifecycleScope.launch { + summary = getString(R.string.loading) + summary = withContext(Dispatchers.IO){ + ytdlpViewModel.getVersion(preferences.getString("ytdlp_source", "stable")!!) + } + if (summary?.isBlank() == true) { + setYTDLPVersion() + } + setOnPreferenceClickListener { + initYTDLUpdate() + true + } } } diff --git a/app/src/main/java/com/deniscerri/ytdl/util/UpdateUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/UpdateUtil.kt index 65ac5fc3..89dcde14 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/UpdateUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/UpdateUtil.kt @@ -1,44 +1,18 @@ package com.deniscerri.ytdl.util import android.annotation.SuppressLint -import android.app.Activity -import android.app.DownloadManager -import android.content.BroadcastReceiver import android.content.Context -import android.content.DialogInterface -import android.content.Intent -import android.content.IntentFilter -import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.os.Environment -import android.os.Handler -import android.os.Looper -import android.text.method.LinkMovementMethod import android.util.Log -import android.widget.TextView -import android.widget.Toast -import androidx.core.content.ContextCompat.startActivity import androidx.preference.PreferenceManager -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.work.WorkManager.UpdateResult import com.deniscerri.ytdl.BuildConfig import com.deniscerri.ytdl.R import com.deniscerri.ytdl.database.models.GithubRelease -import com.deniscerri.ytdl.ui.adapter.ChangelogAdapter -import com.deniscerri.ytdl.util.Extensions.enableFastScroll -import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.yausername.youtubedl_android.YoutubeDL import com.yausername.youtubedl_android.YoutubeDLRequest -import io.noties.markwon.AbstractMarkwonPlugin -import io.noties.markwon.Markwon -import io.noties.markwon.MarkwonConfiguration import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import java.io.File import java.io.InputStreamReader import java.net.HttpURLConnection import java.net.URL @@ -96,36 +70,6 @@ class UpdateUtil(var context: Context) { } } - fun showChangeLog(activity: Activity){ - runCatching { - val releases = getGithubReleases() - - val view = activity.layoutInflater.inflate(R.layout.generic_list, null) - val adapter = ChangelogAdapter(activity) - val recycler = view.findViewById(R.id.download_recyclerview) - recycler.layoutManager = LinearLayoutManager(activity) - recycler.adapter = adapter - adapter.submitList(releases) - recycler.enableFastScroll() - - val changeLogDialog = MaterialAlertDialogBuilder(context) - .setTitle(activity.getString(R.string.changelog)) - .setView(view) - .setIcon(R.drawable.ic_chapters) - .setNegativeButton(context.resources.getString(R.string.dismiss)) { _: DialogInterface?, _: Int -> } - Handler(Looper.getMainLooper()).post { - changeLogDialog.show() - } - - }.onFailure { - if (it.message != null){ - Handler(Looper.getMainLooper()).post { - UiUtil.showErrorDialog(context, it.message!!) - } - } - } - } - fun getGithubReleases(): List { val url = "https://api.github.com/repos/deniscerri/ytdlnis/releases" val conn: HttpURLConnection @@ -158,8 +102,7 @@ class UpdateUtil(var context: Context) { suspend fun updateYoutubeDL(c: String? = null) : YTDLPUpdateResponse = withContext(Dispatchers.IO){ - val sharedPreferences = - PreferenceManager.getDefaultSharedPreferences(context) + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) if (updatingYTDL) { YTDLPUpdateResponse(YTDLPUpdateStatus.PROCESSING) } @@ -168,8 +111,6 @@ class UpdateUtil(var context: Context) { val channel = if (c.isNullOrBlank()) sharedPreferences.getString("ytdlp_source", "stable") else c - - when(channel) { "stable", "nightly", "master" -> { val res = YoutubeDL.updateYoutubeDL(context, channelMap[channel]!!) @@ -185,7 +126,7 @@ class UpdateUtil(var context: Context) { request.addOption("--update-to", "${channel}@latest") val res = YoutubeDL.getInstance().execute(request) - val out = res.out.split(System.getProperty("line.separator")).last { it.isNotBlank() } + val out = res.out.lines().last { it.isNotBlank() } if (out.contains("ERROR")) YTDLPUpdateResponse(YTDLPUpdateStatus.ERROR, out) if (out.contains("yt-dlp is up to date")) YTDLPUpdateResponse(YTDLPUpdateStatus.ALREADY_UP_TO_DATE, out) diff --git a/app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/NewPipeUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/NewPipeUtil.kt index 051835aa..5fc2c30f 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/NewPipeUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/NewPipeUtil.kt @@ -10,7 +10,7 @@ import com.deniscerri.ytdl.database.models.ResultItem import com.deniscerri.ytdl.database.viewmodel.ResultViewModel import com.deniscerri.ytdl.util.Extensions.getIDFromYoutubeURL import com.deniscerri.ytdl.util.Extensions.toStringDuration -import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.PoTokenGenerator +import com.deniscerri.ytdl.util.extractors.newpipe.potoken.NewPipePoTokenGenerator import com.google.gson.Gson import okhttp3.OkHttpClient import org.json.JSONException @@ -38,7 +38,7 @@ class NewPipeUtil(context: Context) { init { NewPipe.init(NewPipeDownloaderImpl(OkHttpClient.Builder()), Localization(language, countryCode)) - YoutubeStreamExtractor.setPoTokenProvider(PoTokenGenerator()) + YoutubeStreamExtractor.setPoTokenProvider(NewPipePoTokenGenerator()) } fun getVideoData(url : String) : Result> { diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/JavascriptUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/potoken/JavascriptUtil.kt similarity index 96% rename from app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/JavascriptUtil.kt rename to app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/potoken/JavascriptUtil.kt index d5814c96..81da6855 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/JavascriptUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/potoken/JavascriptUtil.kt @@ -1,4 +1,4 @@ -package com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview +package com.deniscerri.ytdl.util.extractors.newpipe.potoken import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonNull @@ -125,7 +125,7 @@ object JavascriptUtil { .replace('_', '/') .replace('.', '=') - return (base64Mod.decodeBase64() ?: throw PoTokenException("Cannot base64 decode")) + return (base64Mod.decodeBase64() ?: throw Exception("Cannot base64 decode")) .toByteArray() } } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/PoTokenGenerator.kt b/app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/potoken/NewPipePoTokenGenerator.kt similarity index 93% rename from app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/PoTokenGenerator.kt rename to app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/potoken/NewPipePoTokenGenerator.kt index 3b85ea7c..0cacc5be 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/PoTokenGenerator.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/potoken/NewPipePoTokenGenerator.kt @@ -1,4 +1,4 @@ -package com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens +package com.deniscerri.ytdl.util.extractors.newpipe.potoken import android.os.Handler import android.os.Looper @@ -6,7 +6,6 @@ import android.util.Log import android.webkit.CookieManager import com.deniscerri.ytdl.App import com.deniscerri.ytdl.BuildConfig -import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.PoTokenWebView import kotlinx.coroutines.runBlocking import org.schabi.newpipe.extractor.NewPipe import org.schabi.newpipe.extractor.services.youtube.InnertubeClientRequestInfo @@ -14,9 +13,8 @@ import org.schabi.newpipe.extractor.services.youtube.PoTokenProvider import org.schabi.newpipe.extractor.services.youtube.PoTokenResult import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper -//for newpipe -class PoTokenGenerator : PoTokenProvider { - val TAG = PoTokenGenerator::class.simpleName +class NewPipePoTokenGenerator : PoTokenProvider { + val TAG = NewPipePoTokenGenerator::class.simpleName private val supportsWebView by lazy { runCatching { CookieManager.getInstance() }.isSuccess } private object WebPoTokenGenLock @@ -39,7 +37,7 @@ class PoTokenGenerator : PoTokenProvider { /** * @param forceRecreate whether to force the recreation of [webPoTokenGenerator], to be used in * case the current [webPoTokenGenerator] threw an error last time - * [PoTokenGenerator.generatePoToken] was called + * [NewPipePoTokenGenerator.generatePoToken] was called */ private fun getWebClientPoToken(videoId: String, forceRecreate: Boolean): PoTokenResult { // just a helper class since Kotlin does not have builtin support for 4-tuples diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenWebView.kt b/app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/potoken/PoTokenWebView.kt similarity index 93% rename from app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenWebView.kt rename to app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/potoken/PoTokenWebView.kt index fa88a9c6..0cabfdf2 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenWebView.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/extractors/newpipe/potoken/PoTokenWebView.kt @@ -1,4 +1,4 @@ -package com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview +package com.deniscerri.ytdl.util.extractors.newpipe.potoken import android.content.Context import android.os.Build @@ -17,10 +17,10 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext import com.deniscerri.ytdl.BuildConfig -import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.JavascriptUtil.parseChallengeData -import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.JavascriptUtil.parseIntegrityTokenData -import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.JavascriptUtil.stringToU8 -import com.deniscerri.ytdl.ui.more.settings.advanced.generateyoutubepotokens.webview.JavascriptUtil.u8ToBase64 +import com.deniscerri.ytdl.util.extractors.newpipe.potoken.JavascriptUtil.parseChallengeData +import com.deniscerri.ytdl.util.extractors.newpipe.potoken.JavascriptUtil.parseIntegrityTokenData +import com.deniscerri.ytdl.util.extractors.newpipe.potoken.JavascriptUtil.stringToU8 +import com.deniscerri.ytdl.util.extractors.newpipe.potoken.JavascriptUtil.u8ToBase64 import okhttp3.Headers.Companion.toHeaders import okhttp3.OkHttpClient import okhttp3.RequestBody.Companion.toRequestBody @@ -67,7 +67,7 @@ class PoTokenWebView private constructor( // supports a really old version of JS. val fmt = "\"${m.message()}\", source: ${m.sourceId()} (${m.lineNumber()})" - val exception = BadWebViewException(fmt) + val exception = Exception(fmt) Log.e(TAG, "This WebView implementation is broken: $fmt") onInitializationErrorCloseAndCancel(exception) @@ -136,7 +136,7 @@ class PoTokenWebView private constructor( if (BuildConfig.DEBUG) { Log.e(TAG, "Initialization error from JavaScript: $error") } - onInitializationErrorCloseAndCancel(buildExceptionForJsError(error)) + onInitializationErrorCloseAndCancel(Exception(error)) } /** @@ -195,7 +195,7 @@ class PoTokenWebView private constructor( if (BuildConfig.DEBUG) { Log.e(TAG, "obtainPoToken error from JavaScript: $error") } - popPoTokenContinuation(identifier)?.resumeWithException(buildExceptionForJsError(error)) + popPoTokenContinuation(identifier)?.resumeWithException(Exception(error)) } /** @@ -280,10 +280,10 @@ class PoTokenWebView private constructor( } val httpCode = response.code if (httpCode != 200) { - onInitializationErrorCloseAndCancel(PoTokenException("Invalid response code: $httpCode")) + onInitializationErrorCloseAndCancel(Exception("Invalid response code: $httpCode")) } else { val body = withContext(Dispatchers.IO) { - response.body!!.string() + response.body.string() } handleResponseBody(body) } diff --git a/app/src/main/res/layout/fragment_generate_youtube_po_token.xml b/app/src/main/res/layout/fragment_generate_youtube_po_token.xml index 0b20f81e..fce64c66 100644 --- a/app/src/main/res/layout/fragment_generate_youtube_po_token.xml +++ b/app/src/main/res/layout/fragment_generate_youtube_po_token.xml @@ -6,241 +6,249 @@ android:layout_height="match_parent" tools:context="com.deniscerri.ytdl.ui.more.terminal.TerminalActivity"> - + android:layout_height="wrap_content"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -