diff --git a/app/src/main/java/com/lagradost/cloudstream3/DownloaderTestImpl.kt b/app/src/main/java/com/lagradost/cloudstream3/DownloaderTestImpl.kt index e562ee17..379a91e4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/DownloaderTestImpl.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/DownloaderTestImpl.kt @@ -40,10 +40,7 @@ class DownloaderTestImpl private constructor(builder: OkHttpClient.Builder) : Do throw ReCaptchaException("reCaptcha Challenge requested", url) } val body = response.body - var responseBodyToReturn: String? = null - if (body != null) { - responseBodyToReturn = body.string() - } + val responseBodyToReturn: String = body.string() val latestUrl = response.request.url.toString() return Response( response.code, response.message, response.headers.toMultimap(), diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index efeac1a1..ed0e3c99 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -88,7 +88,8 @@ object APIHolder { } private fun getLoadResponseIdFromUrl(url: String, apiName: String): Int { - return url.replace(getApiFromNameNull(apiName)?.mainUrl ?: "", "").replace("/", "").hashCode() + return url.replace(getApiFromNameNull(apiName)?.mainUrl ?: "", "").replace("/", "") + .hashCode() } fun LoadResponse.getId(): Int { @@ -109,39 +110,43 @@ object APIHolder { // Try document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]").attr("src").substringAfter("render=") // To get the key suspend fun getCaptchaToken(url: String, key: String, referer: String? = null): String? { - val uri = Uri.parse(url) - val domain = encodeToString( - (uri.scheme + "://" + uri.host + ":443").encodeToByteArray(), - 0 - ).replace("\n", "").replace("=", ".") + try { + val uri = Uri.parse(url) + val domain = encodeToString( + (uri.scheme + "://" + uri.host + ":443").encodeToByteArray(), + 0 + ).replace("\n", "").replace("=", ".") - val vToken = - app.get( - "https://www.google.com/recaptcha/api.js?render=$key", - referer = referer, - cacheTime = 0 - ) - .text - .substringAfter("releases/") - .substringBefore("/") - val recapToken = - app.get("https://www.google.com/recaptcha/api2/anchor?ar=1&hl=en&size=invisible&cb=cs3&k=$key&co=$domain&v=$vToken") - .document - .selectFirst("#recaptcha-token")?.attr("value") - if (recapToken != null) { - return app.post( - "https://www.google.com/recaptcha/api2/reload?k=$key", - data = mapOf( - "v" to vToken, - "k" to key, - "c" to recapToken, - "co" to domain, - "sa" to "", - "reason" to "q" - ), cacheTime = 0 - ).text - .substringAfter("rresp\",\"") - .substringBefore("\"") + val vToken = + app.get( + "https://www.google.com/recaptcha/api.js?render=$key", + referer = referer, + cacheTime = 0 + ) + .text + .substringAfter("releases/") + .substringBefore("/") + val recapToken = + app.get("https://www.google.com/recaptcha/api2/anchor?ar=1&hl=en&size=invisible&cb=cs3&k=$key&co=$domain&v=$vToken") + .document + .selectFirst("#recaptcha-token")?.attr("value") + if (recapToken != null) { + return app.post( + "https://www.google.com/recaptcha/api2/reload?k=$key", + data = mapOf( + "v" to vToken, + "k" to key, + "c" to recapToken, + "co" to domain, + "sa" to "", + "reason" to "q" + ), cacheTime = 0 + ).text + .substringAfter("rresp\",\"") + .substringBefore("\"") + } + } catch (e: Exception) { + logError(e) } return null } diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index be1b0e82..240fa3ae 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -10,10 +10,6 @@ import android.view.KeyEvent import android.view.Menu import android.view.MenuItem import android.view.WindowManager -import android.widget.Toast -import androidx.activity.result.ActivityResult -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.IdRes import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible @@ -36,7 +32,6 @@ import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings import com.lagradost.cloudstream3.APIHolder.initAll import com.lagradost.cloudstream3.APIHolder.updateHasTrailers -import com.lagradost.cloudstream3.CommonActivity.currentToast import com.lagradost.cloudstream3.CommonActivity.loadThemes import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent @@ -45,10 +40,12 @@ import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.updateLocale import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.network.initClient +import com.lagradost.cloudstream3.plugins.PluginManager import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.OAuth2Apis import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.accountManagers import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appString +import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStringRepo import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.inAppAuths import com.lagradost.cloudstream3.ui.APIRepository import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO @@ -58,8 +55,10 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmula import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings import com.lagradost.cloudstream3.ui.settings.SettingsGeneral import com.lagradost.cloudstream3.ui.setup.HAS_DONE_SETUP_KEY +import com.lagradost.cloudstream3.ui.setup.SetupFragmentExtensions import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable import com.lagradost.cloudstream3.utils.AppUtils.loadCache +import com.lagradost.cloudstream3.utils.AppUtils.loadRepository import com.lagradost.cloudstream3.utils.AppUtils.loadResult import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup import com.lagradost.cloudstream3.utils.Coroutines.ioSafe @@ -68,6 +67,7 @@ import com.lagradost.cloudstream3.utils.DataStore.removeKey import com.lagradost.cloudstream3.utils.DataStore.setKey import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos +import com.lagradost.cloudstream3.utils.Event import com.lagradost.cloudstream3.utils.IOnBackPressed import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate import com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState @@ -83,17 +83,8 @@ import com.lagradost.nicehttp.ResponseParser import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.fragment_result_swipe.* import java.io.File -import kotlin.concurrent.thread -import kotlin.reflect.KClass -import com.lagradost.cloudstream3.plugins.PluginManager -import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStringRepo -import com.lagradost.cloudstream3.ui.setup.SetupFragmentExtensions -import com.lagradost.cloudstream3.utils.AppUtils.loadRepository -import com.lagradost.cloudstream3.utils.Coroutines.main -import com.lagradost.cloudstream3.utils.Event -import kotlinx.coroutines.delay -import java.lang.ref.WeakReference import java.net.URI +import kotlin.reflect.KClass const val VLC_PACKAGE = "org.videolan.vlc" @@ -659,7 +650,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { handleAppIntent(intent) - thread { + ioSafe { runAutoUpdate() } diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt index 0f6e0368..c7e0ff86 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt @@ -5,11 +5,10 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.apmap -import com.lagradost.cloudstream3.apmapIndexed import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall import com.lagradost.cloudstream3.plugins.PluginManager.getPluginSanitizedFileName -import com.lagradost.cloudstream3.plugins.PluginManager.getPluginsLocal import com.lagradost.cloudstream3.ui.settings.extensions.REPOSITORIES_KEY import com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson @@ -80,10 +79,15 @@ object RepositoryManager { private suspend fun parsePlugins(pluginUrls: String): List { // Take manifestVersion and such into account later - val response = app.get(pluginUrls) - // Normal parsed function not working? -// return response.parsedSafe() - return tryParseJson>(response.text)?.toList() ?: emptyList() + return try { + val response = app.get(pluginUrls) + // Normal parsed function not working? + // return response.parsedSafe() + tryParseJson>(response.text)?.toList() ?: emptyList() + } catch (e : Exception) { + logError(e) + emptyList() + } } /** diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/SelectAdaptor.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/SelectAdaptor.kt index eb4aafa1..74647ada 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/SelectAdaptor.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/SelectAdaptor.kt @@ -3,22 +3,11 @@ package com.lagradost.cloudstream3.ui.result import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView -import androidx.core.view.isVisible import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.google.android.material.button.MaterialButton -import com.lagradost.cloudstream3.ActorData -import com.lagradost.cloudstream3.ActorRole import com.lagradost.cloudstream3.R -import com.lagradost.cloudstream3.ui.download.DownloadButtonViewHolder -import com.lagradost.cloudstream3.ui.home.ParentItemAdapter -import com.lagradost.cloudstream3.ui.settings.AccountAdapter import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings -import com.lagradost.cloudstream3.utils.UIHelper.setImage -import kotlinx.android.synthetic.main.cast_item.view.* -import org.schabi.newpipe.extractor.timeago.patterns.it typealias SelectData = Pair diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt index 03257ebf..ee974502 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt @@ -16,6 +16,7 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar import com.lagradost.cloudstream3.utils.BackupUtils.backup import com.lagradost.cloudstream3.utils.BackupUtils.restorePrompt +import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard @@ -25,7 +26,6 @@ import okhttp3.internal.closeQuietly import java.io.BufferedReader import java.io.InputStreamReader import java.io.OutputStream -import kotlin.concurrent.thread class SettingsUpdates : PreferenceFragmentCompat() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -116,8 +116,8 @@ class SettingsUpdates : PreferenceFragmentCompat() { } getPref(R.string.manual_check_update_key)?.setOnPreferenceClickListener { - thread { - if (!requireActivity().runAutoUpdate(false)) { + ioSafe { + if (activity?.runAutoUpdate(false) == false) { activity?.runOnUiThread { CommonActivity.showToast( activity, diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentProviderLanguage.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentProviderLanguage.kt index 157a7ac2..3e24cc4d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentProviderLanguage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentProviderLanguage.kt @@ -41,7 +41,7 @@ class SetupFragmentProviderLanguage : Fragment() { val langs = APIHolder.apis.map { it.lang }.toSet() .sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) } - val currentList = current.map { langs.indexOf(it) } + val currentList = current.map { langs.indexOf(it) }.filter { it != -1 } // TODO LOOK INTO val languageNames = langs.map { val emoji = SubtitleHelper.getFlagFromIso(it) val name = SubtitleHelper.fromTwoLettersToLanguage(it) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt index 32fa04af..42d200d0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt @@ -15,15 +15,14 @@ import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.mvvm.logError -import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.Coroutines.ioSafe -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import okio.* +import okio.BufferedSink +import okio.buffer +import okio.sink import java.io.File -import kotlin.concurrent.thread class InAppUpdater { @@ -68,10 +67,14 @@ class InAppUpdater { @JsonProperty("updateNodeId") val updateNodeId: String? ) - private fun Activity.getAppUpdate(): Update { + private suspend fun Activity.getAppUpdate(): Update { return try { val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) - if (settingsManager.getBoolean(getString(R.string.prerelease_update_key), resources.getBoolean(R.bool.is_prerelease))) { + if (settingsManager.getBoolean( + getString(R.string.prerelease_update_key), + resources.getBoolean(R.bool.is_prerelease) + ) + ) { getPreReleaseUpdate() } else { getReleaseUpdate() @@ -82,16 +85,16 @@ class InAppUpdater { } } - private fun Activity.getReleaseUpdate(): Update { + private suspend fun Activity.getReleaseUpdate(): Update { val url = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/releases" val headers = mapOf("Accept" to "application/vnd.github.v3+json") val response = - parseJson>(runBlocking { + parseJson>( app.get( url, headers = headers ).text - }) + ) val versionRegex = Regex("""(.*?((\d+)\.(\d+)\.(\d+))\.apk)""") val versionRegexLocal = Regex("""(.*?((\d+)\.(\d+)\.(\d+)).*)""") @@ -148,7 +151,7 @@ class InAppUpdater { return Update(false, null, null, null, null) } - private fun Activity.getPreReleaseUpdate(): Update = runBlocking { + private suspend fun Activity.getPreReleaseUpdate(): Update { val tagUrl = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/git/ref/tags/pre-release" val releaseUrl = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/releases" @@ -171,14 +174,14 @@ class InAppUpdater { val shouldUpdate = (getString(R.string.commit_hash) - .trim {c->c.isWhitespace()} - .take(7) - != - tagResponse.github_object.sha - .trim {c->c.isWhitespace()} - .take(7)) + .trim { c -> c.isWhitespace() } + .take(7) + != + tagResponse.github_object.sha + .trim { c -> c.isWhitespace() } + .take(7)) - return@runBlocking if (foundAsset != null) { + return if (foundAsset != null) { Update( shouldUpdate, foundAsset.browser_download_url, @@ -194,25 +197,24 @@ class InAppUpdater { private val updateLock = Mutex() - private fun Activity.downloadUpdate(url: String): Boolean { + private suspend fun Activity.downloadUpdate(url: String): Boolean { + try { + Log.d(LOG_TAG, "Downloading update: $url") - Log.d(LOG_TAG, "Downloading update: $url") + val localContext = this - val localContext = this + val downloadedFile = File.createTempFile("CloudStream", ".apk") + val sink: BufferedSink = downloadedFile.sink().buffer() - val downloadedFile = File.createTempFile("CloudStream",".apk") - val sink: BufferedSink = downloadedFile.sink().buffer() - - - ioSafe { updateLock.withLock { - sink.writeAll(app.get(url).body.source() ) + sink.writeAll(app.get(url).body.source()) sink.close() openApk(localContext, Uri.fromFile(downloadedFile)) } + return true + } catch (e: Exception) { + return false } - - return true } private fun openApk(context: Context, uri: Uri) { @@ -236,7 +238,7 @@ class InAppUpdater { } } - fun Activity.runAutoUpdate(checkAutoUpdate: Boolean = true): Boolean { + suspend fun Activity.runAutoUpdate(checkAutoUpdate: Boolean = true): Boolean { val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) if (!checkAutoUpdate || settingsManager.getBoolean( @@ -247,7 +249,8 @@ class InAppUpdater { val update = getAppUpdate() if (update.shouldUpdate && update.updateURL != null) { //Check if update should be skipped - val updateNodeId = settingsManager.getString(getString(R.string.skip_update_key), "") + val updateNodeId = + settingsManager.getString(getString(R.string.skip_update_key), "") if (update.updateNodeId.equals(updateNodeId)) { return false } @@ -273,11 +276,8 @@ class InAppUpdater { builder.apply { setPositiveButton(R.string.update) { _, _ -> showToast(context, R.string.download_started, Toast.LENGTH_LONG) - thread { - val downloadStatus = - normalSafeApiCall { context.downloadUpdate(update.updateURL) } - ?: false - if (!downloadStatus) { + ioSafe { + if (!downloadUpdate(update.updateURL)) runOnUiThread { showToast( context, @@ -285,7 +285,6 @@ class InAppUpdater { Toast.LENGTH_LONG ) } - } } } @@ -293,7 +292,10 @@ class InAppUpdater { if (checkAutoUpdate) { setNeutralButton(R.string.skip_update) { _, _ -> - settingsManager.edit().putString(getString(R.string.skip_update_key), update.updateNodeId ?: "") + settingsManager.edit().putString( + getString(R.string.skip_update_key), + update.updateNodeId ?: "" + ) .apply() } }