crash fix and headphones pause

This commit is contained in:
LagradOst 2022-01-13 22:09:05 +01:00
parent ca4d05bd34
commit 0f1229354a
9 changed files with 246 additions and 149 deletions

View File

@ -8,7 +8,6 @@
<option name="testRunner" value="GRADLE" /> <option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" /> <option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-11" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />

View File

@ -35,8 +35,8 @@ android {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 30 targetSdkVersion 30
versionCode 40 versionCode 41
versionName "2.4.8" versionName "2.5.8"
resValue "string", "app_version", resValue "string", "app_version",
"${defaultConfig.versionName}${versionNameSuffix ?: ""}" "${defaultConfig.versionName}${versionNameSuffix ?: ""}"

View File

@ -39,7 +39,6 @@ object APIHolder {
WcoProvider(), WcoProvider(),
// MeloMovieProvider(), // Captcha for links // MeloMovieProvider(), // Captcha for links
DubbedAnimeProvider(), DubbedAnimeProvider(),
HDMProvider(),
IHaveNoTvProvider(), // Documentaries provider IHaveNoTvProvider(), // Documentaries provider
//LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...) //LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...)
VMoveeProvider(), VMoveeProvider(),
@ -58,8 +57,6 @@ object APIHolder {
//TmdbProvider(), //TmdbProvider(),
FilmanProvider(), FilmanProvider(),
ZoroProvider(), ZoroProvider(),
@ -81,6 +78,7 @@ object APIHolder {
private val backwardsCompatibleProviders = arrayListOf( private val backwardsCompatibleProviders = arrayListOf(
KawaiifuProvider(), // removed due to cloudflare KawaiifuProvider(), // removed due to cloudflare
HDMProvider(),// removed due to cloudflare
) )
fun getApiFromName(apiName: String?): MainAPI { fun getApiFromName(apiName: String?): MainAPI {
@ -179,7 +177,8 @@ object APIHolder {
fun Context.filterProviderByPreferredMedia(): List<MainAPI> { fun Context.filterProviderByPreferredMedia(): List<MainAPI> {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
val currentPrefMedia = settingsManager.getInt(this.getString(R.string.prefer_media_type_key), 0) val currentPrefMedia =
settingsManager.getInt(this.getString(R.string.prefer_media_type_key), 0)
val langs = this.getApiProviderLangSettings() val langs = this.getApiProviderLangSettings()
val allApis = apis.filter { langs.contains(it.lang) }.filter { api -> api.hasMainPage } val allApis = apis.filter { langs.contains(it.lang) }.filter { api -> api.hasMainPage }
return if (currentPrefMedia < 1) { return if (currentPrefMedia < 1) {
@ -275,7 +274,7 @@ fun parseRating(ratingString: String?): Int? {
return (floatRating * 10).toInt() return (floatRating * 10).toInt()
} }
fun MainAPI.fixUrlNull(url : String?) : String? { fun MainAPI.fixUrlNull(url: String?): String? {
if (url.isNullOrEmpty()) { if (url.isNullOrEmpty()) {
return null return null
} }
@ -305,7 +304,7 @@ fun sortUrls(urls: Set<ExtractorLink>): List<ExtractorLink> {
return urls.sortedBy { t -> -t.quality } return urls.sortedBy { t -> -t.quality }
} }
fun sortSubs(subs : Set<SubtitleData>) : List<SubtitleData> { fun sortSubs(subs: Set<SubtitleData>): List<SubtitleData> {
return subs.sortedBy { it.name } return subs.sortedBy { it.name }
} }
@ -473,7 +472,7 @@ fun LoadResponse?.isAnimeBased(): Boolean {
return (this.type == TvType.Anime || this.type == TvType.ONA) // && (this is AnimeLoadResponse) return (this.type == TvType.Anime || this.type == TvType.ONA) // && (this is AnimeLoadResponse)
} }
fun TvType?.isEpisodeBased() : Boolean { fun TvType?.isEpisodeBased(): Boolean {
if (this == null) return false if (this == null) return false
return (this == TvType.TvSeries || this == TvType.Anime) return (this == TvType.TvSeries || this == TvType.Anime)
} }
@ -573,7 +572,13 @@ fun MainAPI.newMovieLoadResponse(
dataUrl: String, dataUrl: String,
initializer: MovieLoadResponse.() -> Unit = { } initializer: MovieLoadResponse.() -> Unit = { }
): MovieLoadResponse { ): MovieLoadResponse {
val builder = MovieLoadResponse(name = name, url = url, apiName = this.name, type = type, dataUrl = dataUrl) val builder = MovieLoadResponse(
name = name,
url = url,
apiName = this.name,
type = type,
dataUrl = dataUrl
)
builder.initializer() builder.initializer()
return builder return builder
} }
@ -634,7 +639,13 @@ fun MainAPI.newTvSeriesLoadResponse(
episodes: List<TvSeriesEpisode>, episodes: List<TvSeriesEpisode>,
initializer: TvSeriesLoadResponse.() -> Unit = { } initializer: TvSeriesLoadResponse.() -> Unit = { }
): TvSeriesLoadResponse { ): TvSeriesLoadResponse {
val builder = TvSeriesLoadResponse(name = name, url = url, apiName = this.name, type = type, episodes = episodes) val builder = TvSeriesLoadResponse(
name = name,
url = url,
apiName = this.name,
type = type,
episodes = episodes
)
builder.initializer() builder.initializer()
return builder return builder
} }

View File

@ -1,26 +1,27 @@
package com.lagradost.cloudstream3.ui.player package com.lagradost.cloudstream3.ui.player
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.BroadcastReceiver import android.content.*
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.drawable.AnimatedImageDrawable import android.graphics.drawable.AnimatedImageDrawable
import android.graphics.drawable.AnimatedVectorDrawable import android.graphics.drawable.AnimatedVectorDrawable
import android.media.metrics.PlaybackErrorEvent import android.media.metrics.PlaybackErrorEvent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.support.v4.media.session.MediaSessionCompat
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager
import android.widget.Toast import android.widget.Toast
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.media.session.MediaButtonReceiver
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.PlaybackException import com.google.android.exoplayer2.PlaybackException
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
import com.google.android.exoplayer2.ui.SubtitleView import com.google.android.exoplayer2.ui.SubtitleView
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
@ -81,9 +82,20 @@ abstract class AbstractPlayerFragment(
throw NotImplementedError() throw NotImplementedError()
} }
private fun keepScreenOn(on : Boolean) {
if(on) {
activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
private fun updateIsPlaying(playing: Pair<CSPlayerLoading, CSPlayerLoading>) { private fun updateIsPlaying(playing: Pair<CSPlayerLoading, CSPlayerLoading>) {
val (wasPlaying, isPlaying) = playing val (wasPlaying, isPlaying) = playing
val isPlayingRightNow = CSPlayerLoading.IsPlaying == isPlaying val isPlayingRightNow = CSPlayerLoading.IsPlaying == isPlaying
val isPausedRightNow = CSPlayerLoading.IsPaused == isPlaying
keepScreenOn(!isPausedRightNow)
isBuffering = CSPlayerLoading.IsBuffering == isPlaying isBuffering = CSPlayerLoading.IsBuffering == isPlaying
if (isBuffering) { if (isBuffering) {
@ -241,11 +253,48 @@ abstract class AbstractPlayerFragment(
private fun playerUpdated(player: Any?) { private fun playerUpdated(player: Any?) {
if (player is ExoPlayer) { if (player is ExoPlayer) {
context?.let { ctx ->
val mediaButtonReceiver = ComponentName(ctx, MediaButtonReceiver::class.java)
MediaSessionCompat(ctx, "Player", mediaButtonReceiver, null).let { media ->
//media.setCallback(mMediaSessionCallback)
//media.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
val mediaSessionConnector = MediaSessionConnector(media)
mediaSessionConnector.setPlayer(player)
media.isActive = true
mMediaSessionCompat = media
}
}
player_view?.player = player player_view?.player = player
player_view?.performClick() player_view?.performClick()
} }
} }
private var mediaSessionConnector: MediaSessionConnector? = null
private var mMediaSessionCompat: MediaSessionCompat? = null
// this can be used in the future for players other than exoplayer
//private val mMediaSessionCallback: MediaSessionCompat.Callback = object : MediaSessionCompat.Callback() {
// override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean {
// val keyEvent = mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) as KeyEvent?
// if (keyEvent != null) {
// if (keyEvent.action == KeyEvent.ACTION_DOWN) { // NO DOUBLE SKIP
// val consumed = when (keyEvent.keyCode) {
// KeyEvent.KEYCODE_MEDIA_PAUSE -> callOnPause()
// KeyEvent.KEYCODE_MEDIA_PLAY -> callOnPlay()
// KeyEvent.KEYCODE_MEDIA_STOP -> callOnStop()
// KeyEvent.KEYCODE_MEDIA_NEXT -> callOnNext()
// else -> false
// }
// if (consumed) return true
// }
// }
//
// return super.onMediaButtonEvent(mediaButtonEvent)
// }
//}
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
resizeMode = getKey(RESIZE_MODE_KEY) ?: 0 resizeMode = getKey(RESIZE_MODE_KEY) ?: 0
@ -295,6 +344,7 @@ abstract class AbstractPlayerFragment(
keyEventListener = null keyEventListener = null
SubtitlesFragment.applyStyleEvent -= ::onSubStyleChanged SubtitlesFragment.applyStyleEvent -= ::onSubStyleChanged
keepScreenOn(false)
super.onDestroy() super.onDestroy()
} }

View File

@ -130,7 +130,7 @@ open class FullScreenPlayer : AbstractPlayerFragment(R.layout.fragment_player) {
if (isShowing) { if (isShowing) {
updateUIVisibility() updateUIVisibility()
} else { } else {
player_holder.postDelayed({ updateUIVisibility() }, 200) player_holder?.postDelayed({ updateUIVisibility() }, 200)
} }
val titleMove = if (isShowing) 0f else -50.toPx.toFloat() val titleMove = if (isShowing) 0f else -50.toPx.toFloat()

View File

@ -17,6 +17,7 @@ import com.hippo.unifile.UniFile
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.mvvm.observe
import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType
@ -171,111 +172,115 @@ class GeneratorPlayer : FullScreenPlayer() {
var selectSourceDialog: AlertDialog? = null var selectSourceDialog: AlertDialog? = null
override fun showMirrorsDialogue() { override fun showMirrorsDialogue() {
currentSelectedSubtitles = player.getCurrentPreferredSubtitle() try {
context?.let { ctx -> currentSelectedSubtitles = player.getCurrentPreferredSubtitle()
val isPlaying = player.getIsPlaying() context?.let { ctx ->
player.handleEvent(CSPlayerEvent.Pause) val isPlaying = player.getIsPlaying()
val currentSubtitles = sortSubs(currentSubs) player.handleEvent(CSPlayerEvent.Pause)
val currentSubtitles = sortSubs(currentSubs)
val sourceBuilder = AlertDialog.Builder(ctx, R.style.AlertDialogCustomBlack) val sourceBuilder = AlertDialog.Builder(ctx, R.style.AlertDialogCustomBlack)
.setView(R.layout.player_select_source_and_subs) .setView(R.layout.player_select_source_and_subs)
val sourceDialog = sourceBuilder.create() val sourceDialog = sourceBuilder.create()
selectSourceDialog = sourceDialog selectSourceDialog = sourceDialog
sourceDialog.show() sourceDialog.show()
val providerList = val providerList =
sourceDialog.findViewById<ListView>(R.id.sort_providers)!! sourceDialog.findViewById<ListView>(R.id.sort_providers)!!
val subtitleList = val subtitleList =
sourceDialog.findViewById<ListView>(R.id.sort_subtitles)!! sourceDialog.findViewById<ListView>(R.id.sort_subtitles)!!
val applyButton = val applyButton =
sourceDialog.findViewById<MaterialButton>(R.id.apply_btt)!! sourceDialog.findViewById<MaterialButton>(R.id.apply_btt)!!
val cancelButton = val cancelButton =
sourceDialog.findViewById<MaterialButton>(R.id.cancel_btt)!! sourceDialog.findViewById<MaterialButton>(R.id.cancel_btt)!!
val footer: TextView = val footer: TextView =
layoutInflater.inflate(R.layout.sort_bottom_footer_add_choice, null) as TextView layoutInflater.inflate(R.layout.sort_bottom_footer_add_choice, null) as TextView
footer.text = ctx.getString(R.string.player_load_subtitles) footer.text = ctx.getString(R.string.player_load_subtitles)
footer.setOnClickListener { footer.setOnClickListener {
openSubPicker() openSubPicker()
}
subtitleList.addFooterView(footer)
var sourceIndex = 0
var startSource = 0
val sortedUrls = sortLinks(useQualitySettings = false)
if (sortedUrls.isNullOrEmpty()) {
sourceDialog.findViewById<LinearLayout>(R.id.sort_sources_holder)?.isGone = true
} else {
startSource = sortedUrls.indexOf(currentSelectedLink)
sourceIndex = startSource
val sourcesArrayAdapter =
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
sourcesArrayAdapter.addAll(sortedUrls.map {
it.first?.name ?: it.second?.name ?: "NULL"
})
providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE
providerList.adapter = sourcesArrayAdapter
providerList.setSelection(sourceIndex)
providerList.setItemChecked(sourceIndex, true)
providerList.setOnItemClickListener { _, _, which, _ ->
sourceIndex = which
providerList.setItemChecked(which, true)
} }
} subtitleList.addFooterView(footer)
sourceDialog.setOnDismissListener { var sourceIndex = 0
if (isPlaying) { var startSource = 0
player.handleEvent(CSPlayerEvent.Play)
}
activity?.hideSystemUI()
selectSourceDialog = null
}
val subtitleIndexStart = currentSubtitles.indexOf(currentSelectedSubtitles) + 1 val sortedUrls = sortLinks(useQualitySettings = false)
var subtitleIndex = subtitleIndexStart if (sortedUrls.isNullOrEmpty()) {
sourceDialog.findViewById<LinearLayout>(R.id.sort_sources_holder)?.isGone = true
} else {
startSource = sortedUrls.indexOf(currentSelectedLink)
sourceIndex = startSource
val subsArrayAdapter = val sourcesArrayAdapter =
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice) ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
subsArrayAdapter.add(getString(R.string.no_subtitles))
subsArrayAdapter.addAll(currentSubtitles.map { it.name })
subtitleList.adapter = subsArrayAdapter sourcesArrayAdapter.addAll(sortedUrls.map {
subtitleList.choiceMode = AbsListView.CHOICE_MODE_SINGLE it.first?.name ?: it.second?.name ?: "NULL"
})
subtitleList.setSelection(subtitleIndex) providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE
subtitleList.setItemChecked(subtitleIndex, true) providerList.adapter = sourcesArrayAdapter
providerList.setSelection(sourceIndex)
providerList.setItemChecked(sourceIndex, true)
subtitleList.setOnItemClickListener { _, _, which, _ -> providerList.setOnItemClickListener { _, _, which, _ ->
subtitleIndex = which sourceIndex = which
subtitleList.setItemChecked(which, true) providerList.setItemChecked(which, true)
}
cancelButton.setOnClickListener {
sourceDialog.dismissSafe(activity)
}
applyButton.setOnClickListener {
var init = false
if (sourceIndex != startSource) {
init = true
}
if (subtitleIndex != subtitleIndexStart) {
init = init || if (subtitleIndex <= 0) {
noSubtitles()
} else {
setSubtitles(currentSubtitles[subtitleIndex - 1])
} }
} }
if (init) {
loadLink(sortedUrls[sourceIndex], true) sourceDialog.setOnDismissListener {
if (isPlaying) {
player.handleEvent(CSPlayerEvent.Play)
}
activity?.hideSystemUI()
selectSourceDialog = null
}
val subtitleIndexStart = currentSubtitles.indexOf(currentSelectedSubtitles) + 1
var subtitleIndex = subtitleIndexStart
val subsArrayAdapter =
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
subsArrayAdapter.add(getString(R.string.no_subtitles))
subsArrayAdapter.addAll(currentSubtitles.map { it.name })
subtitleList.adapter = subsArrayAdapter
subtitleList.choiceMode = AbsListView.CHOICE_MODE_SINGLE
subtitleList.setSelection(subtitleIndex)
subtitleList.setItemChecked(subtitleIndex, true)
subtitleList.setOnItemClickListener { _, _, which, _ ->
subtitleIndex = which
subtitleList.setItemChecked(which, true)
}
cancelButton.setOnClickListener {
sourceDialog.dismissSafe(activity)
}
applyButton.setOnClickListener {
var init = false
if (sourceIndex != startSource) {
init = true
}
if (subtitleIndex != subtitleIndexStart) {
init = init || if (subtitleIndex <= 0) {
noSubtitles()
} else {
setSubtitles(currentSubtitles[subtitleIndex - 1])
}
}
if (init) {
loadLink(sortedUrls[sourceIndex], true)
}
sourceDialog.dismissSafe(activity)
} }
sourceDialog.dismissSafe(activity)
} }
} catch (e : Exception) {
logError(e)
} }
} }

View File

@ -755,9 +755,13 @@ class ResultFragment : Fragment() {
ACTION_PLAY_EPISODE_IN_BROWSER -> { ACTION_PLAY_EPISODE_IN_BROWSER -> {
acquireSingeExtractorLink(getString(R.string.episode_action_play_in_browser)) { link -> acquireSingeExtractorLink(getString(R.string.episode_action_play_in_browser)) { link ->
val i = Intent(ACTION_VIEW) try {
i.data = Uri.parse(link.url) val i = Intent(ACTION_VIEW)
startActivity(i) i.data = Uri.parse(link.url)
startActivity(i)
} catch (e : Exception) {
logError(e)
}
} }
} }
@ -1125,11 +1129,15 @@ class ResultFragment : Fragment() {
} }
result_share?.setOnClickListener { result_share?.setOnClickListener {
val i = Intent(ACTION_SEND) try {
i.type = "text/plain" val i = Intent(ACTION_SEND)
i.putExtra(EXTRA_SUBJECT, d.name) i.type = "text/plain"
i.putExtra(EXTRA_TEXT, d.url) i.putExtra(EXTRA_SUBJECT, d.name)
startActivity(createChooser(i, d.name)) i.putExtra(EXTRA_TEXT, d.url)
startActivity(createChooser(i, d.name))
} catch (e: Exception) {
logError(e)
}
} }
updateSync(d.getId()) updateSync(d.getId())

View File

@ -32,6 +32,7 @@ import com.lagradost.cloudstream3.DubStatus
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.syncproviders.AccountManager import com.lagradost.cloudstream3.syncproviders.AccountManager
import com.lagradost.cloudstream3.syncproviders.OAuth2API import com.lagradost.cloudstream3.syncproviders.OAuth2API
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.aniListApi import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.aniListApi
@ -301,22 +302,24 @@ class SettingsFragment : PreferenceFragmentCompat() {
} }
fun getDownloadDirs(): List<String> { fun getDownloadDirs(): List<String> {
val defaultDir = getDownloadDir()?.filePath return normalSafeApiCall {
val defaultDir = getDownloadDir()?.filePath
// app_name_download_path = Cloudstream and does not change depending on release. // app_name_download_path = Cloudstream and does not change depending on release.
// DOES NOT WORK ON SCOPED STORAGE. // DOES NOT WORK ON SCOPED STORAGE.
val secondaryDir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) null else Environment.getExternalStorageDirectory().absolutePath + val secondaryDir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) null else Environment.getExternalStorageDirectory().absolutePath +
File.separator + resources.getString(R.string.app_name_download_path) File.separator + resources.getString(R.string.app_name_download_path)
val first = listOf(defaultDir, secondaryDir) val first = listOf(defaultDir, secondaryDir)
return (try { (try {
val currentDir = context?.getBasePath()?.let { it.first?.filePath ?: it.second } val currentDir = context?.getBasePath()?.let { it.first?.filePath ?: it.second }
(first + (first +
requireContext().getExternalFilesDirs("").mapNotNull { it.path } + requireContext().getExternalFilesDirs("").mapNotNull { it.path } +
currentDir) currentDir)
} catch (e: Exception) { } catch (e: Exception) {
first first
}).filterNotNull().distinct() }).filterNotNull().distinct()
} ?: emptyList()
} }
downloadPathPreference.setOnPreferenceClickListener { downloadPathPreference.setOnPreferenceClickListener {

View File

@ -126,7 +126,12 @@ class InAppUpdater {
} }
)!! < 0 else false )!! < 0 else false
return if (foundVersion != null) { return if (foundVersion != null) {
Update(shouldUpdate, foundAsset.browser_download_url, foundVersion.groupValues[2], found.body) Update(
shouldUpdate,
foundAsset.browser_download_url,
foundVersion.groupValues[2],
found.body
)
} else { } else {
Update(false, null, null, null) Update(false, null, null, null)
} }
@ -135,7 +140,8 @@ class InAppUpdater {
} }
private fun Activity.getPreReleaseUpdate(): Update { private fun Activity.getPreReleaseUpdate(): Update {
val tagUrl = "https://api.github.com/repos/LagradOst/CloudStream-3/git/ref/tags/pre-release" val tagUrl =
"https://api.github.com/repos/LagradOst/CloudStream-3/git/ref/tags/pre-release"
val releaseUrl = "https://api.github.com/repos/LagradOst/CloudStream-3/releases" val releaseUrl = "https://api.github.com/repos/LagradOst/CloudStream-3/releases"
val headers = mapOf("Accept" to "application/vnd.github.v3+json") val headers = mapOf("Accept" to "application/vnd.github.v3+json")
val response = val response =
@ -150,10 +156,16 @@ class InAppUpdater {
val tagResponse = val tagResponse =
mapper.readValue<GithubTag>(app.get(tagUrl, headers = headers).text) mapper.readValue<GithubTag>(app.get(tagUrl, headers = headers).text)
val shouldUpdate = (getString(R.string.prerelease_commit_hash) != tagResponse.github_object.sha) val shouldUpdate =
(getString(R.string.prerelease_commit_hash) != tagResponse.github_object.sha)
return if (foundAsset != null) { return if (foundAsset != null) {
Update(shouldUpdate, foundAsset.browser_download_url, tagResponse.github_object.sha, found.body) Update(
shouldUpdate,
foundAsset.browser_download_url,
tagResponse.github_object.sha,
found.body
)
} else { } else {
Update(false, null, null, null) Update(false, null, null, null)
} }
@ -217,26 +229,33 @@ class InAppUpdater {
} }
fun openApk(context: Context, uri: Uri) { fun openApk(context: Context, uri: Uri) {
uri.path?.let { try {
val contentUri = FileProvider.getUriForFile( uri.path?.let {
context, val contentUri = FileProvider.getUriForFile(
BuildConfig.APPLICATION_ID + ".provider", context,
File(it) BuildConfig.APPLICATION_ID + ".provider",
) File(it)
val installIntent = Intent(Intent.ACTION_VIEW).apply { )
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) val installIntent = Intent(Intent.ACTION_VIEW).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
data = contentUri putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
data = contentUri
}
context.startActivity(installIntent)
} }
context.startActivity(installIntent) } catch (e: Exception) {
logError(e)
} }
} }
fun Activity.runAutoUpdate(checkAutoUpdate: Boolean = true): Boolean { fun Activity.runAutoUpdate(checkAutoUpdate: Boolean = true): Boolean {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
if (!checkAutoUpdate || settingsManager.getBoolean(getString(R.string.auto_update_key), true) if (!checkAutoUpdate || settingsManager.getBoolean(
getString(R.string.auto_update_key),
true
)
) { ) {
val update = getAppUpdate() val update = getAppUpdate()
if (update.shouldUpdate && update.updateURL != null) { if (update.shouldUpdate && update.updateURL != null) {
@ -264,7 +283,8 @@ class InAppUpdater {
showToast(context, R.string.download_started, Toast.LENGTH_LONG) showToast(context, R.string.download_started, Toast.LENGTH_LONG)
thread { thread {
val downloadStatus = val downloadStatus =
normalSafeApiCall { context.downloadUpdate(update.updateURL) } ?: false normalSafeApiCall { context.downloadUpdate(update.updateURL) }
?: false
if (!downloadStatus) { if (!downloadStatus) {
runOnUiThread { runOnUiThread {
showToast( showToast(
@ -281,7 +301,8 @@ class InAppUpdater {
if (checkAutoUpdate) { if (checkAutoUpdate) {
setNeutralButton(R.string.dont_show_again) { _, _ -> setNeutralButton(R.string.dont_show_again) { _, _ ->
settingsManager.edit().putBoolean("auto_update", false).apply() settingsManager.edit().putBoolean("auto_update", false)
.apply()
} }
} }
} }