forked from recloudstream/cloudstream
crash fix and headphones pause
This commit is contained in:
parent
ca4d05bd34
commit
0f1229354a
9 changed files with 246 additions and 149 deletions
|
@ -8,7 +8,6 @@
|
|||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="jbr-11" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
|
|
|
@ -35,8 +35,8 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
|
||||
versionCode 40
|
||||
versionName "2.4.8"
|
||||
versionCode 41
|
||||
versionName "2.5.8"
|
||||
|
||||
resValue "string", "app_version",
|
||||
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
|
||||
|
|
|
@ -39,7 +39,6 @@ object APIHolder {
|
|||
WcoProvider(),
|
||||
// MeloMovieProvider(), // Captcha for links
|
||||
DubbedAnimeProvider(),
|
||||
HDMProvider(),
|
||||
IHaveNoTvProvider(), // Documentaries provider
|
||||
//LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...)
|
||||
VMoveeProvider(),
|
||||
|
@ -58,8 +57,6 @@ object APIHolder {
|
|||
|
||||
//TmdbProvider(),
|
||||
|
||||
|
||||
|
||||
FilmanProvider(),
|
||||
|
||||
ZoroProvider(),
|
||||
|
@ -81,6 +78,7 @@ object APIHolder {
|
|||
|
||||
private val backwardsCompatibleProviders = arrayListOf(
|
||||
KawaiifuProvider(), // removed due to cloudflare
|
||||
HDMProvider(),// removed due to cloudflare
|
||||
)
|
||||
|
||||
fun getApiFromName(apiName: String?): MainAPI {
|
||||
|
@ -179,7 +177,8 @@ object APIHolder {
|
|||
|
||||
fun Context.filterProviderByPreferredMedia(): List<MainAPI> {
|
||||
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 allApis = apis.filter { langs.contains(it.lang) }.filter { api -> api.hasMainPage }
|
||||
return if (currentPrefMedia < 1) {
|
||||
|
@ -275,7 +274,7 @@ fun parseRating(ratingString: String?): Int? {
|
|||
return (floatRating * 10).toInt()
|
||||
}
|
||||
|
||||
fun MainAPI.fixUrlNull(url : String?) : String? {
|
||||
fun MainAPI.fixUrlNull(url: String?): String? {
|
||||
if (url.isNullOrEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
@ -305,7 +304,7 @@ fun sortUrls(urls: Set<ExtractorLink>): List<ExtractorLink> {
|
|||
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 }
|
||||
}
|
||||
|
||||
|
@ -473,7 +472,7 @@ fun LoadResponse?.isAnimeBased(): Boolean {
|
|||
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
|
||||
return (this == TvType.TvSeries || this == TvType.Anime)
|
||||
}
|
||||
|
@ -573,7 +572,13 @@ fun MainAPI.newMovieLoadResponse(
|
|||
dataUrl: String,
|
||||
initializer: MovieLoadResponse.() -> Unit = { }
|
||||
): 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()
|
||||
return builder
|
||||
}
|
||||
|
@ -634,7 +639,13 @@ fun MainAPI.newTvSeriesLoadResponse(
|
|||
episodes: List<TvSeriesEpisode>,
|
||||
initializer: TvSeriesLoadResponse.() -> Unit = { }
|
||||
): 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()
|
||||
return builder
|
||||
}
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.*
|
||||
import android.graphics.drawable.AnimatedImageDrawable
|
||||
import android.graphics.drawable.AnimatedVectorDrawable
|
||||
import android.media.metrics.PlaybackErrorEvent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.v4.media.session.MediaSessionCompat
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.media.session.MediaButtonReceiver
|
||||
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
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.SubtitleView
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||
|
@ -81,9 +82,20 @@ abstract class AbstractPlayerFragment(
|
|||
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>) {
|
||||
val (wasPlaying, isPlaying) = playing
|
||||
val isPlayingRightNow = CSPlayerLoading.IsPlaying == isPlaying
|
||||
val isPausedRightNow = CSPlayerLoading.IsPaused == isPlaying
|
||||
|
||||
keepScreenOn(!isPausedRightNow)
|
||||
|
||||
isBuffering = CSPlayerLoading.IsBuffering == isPlaying
|
||||
if (isBuffering) {
|
||||
|
@ -241,11 +253,48 @@ abstract class AbstractPlayerFragment(
|
|||
|
||||
private fun playerUpdated(player: Any?) {
|
||||
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?.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")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
resizeMode = getKey(RESIZE_MODE_KEY) ?: 0
|
||||
|
@ -295,6 +344,7 @@ abstract class AbstractPlayerFragment(
|
|||
keyEventListener = null
|
||||
SubtitlesFragment.applyStyleEvent -= ::onSubStyleChanged
|
||||
|
||||
keepScreenOn(false)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ open class FullScreenPlayer : AbstractPlayerFragment(R.layout.fragment_player) {
|
|||
if (isShowing) {
|
||||
updateUIVisibility()
|
||||
} else {
|
||||
player_holder.postDelayed({ updateUIVisibility() }, 200)
|
||||
player_holder?.postDelayed({ updateUIVisibility() }, 200)
|
||||
}
|
||||
|
||||
val titleMove = if (isShowing) 0f else -50.toPx.toFloat()
|
||||
|
|
|
@ -17,6 +17,7 @@ import com.hippo.unifile.UniFile
|
|||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType
|
||||
|
@ -171,6 +172,7 @@ class GeneratorPlayer : FullScreenPlayer() {
|
|||
|
||||
var selectSourceDialog: AlertDialog? = null
|
||||
override fun showMirrorsDialogue() {
|
||||
try {
|
||||
currentSelectedSubtitles = player.getCurrentPreferredSubtitle()
|
||||
context?.let { ctx ->
|
||||
val isPlaying = player.getIsPlaying()
|
||||
|
@ -277,6 +279,9 @@ class GeneratorPlayer : FullScreenPlayer() {
|
|||
sourceDialog.dismissSafe(activity)
|
||||
}
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun noLinksFound() {
|
||||
|
|
|
@ -755,9 +755,13 @@ class ResultFragment : Fragment() {
|
|||
|
||||
ACTION_PLAY_EPISODE_IN_BROWSER -> {
|
||||
acquireSingeExtractorLink(getString(R.string.episode_action_play_in_browser)) { link ->
|
||||
try {
|
||||
val i = Intent(ACTION_VIEW)
|
||||
i.data = Uri.parse(link.url)
|
||||
startActivity(i)
|
||||
} catch (e : Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1125,11 +1129,15 @@ class ResultFragment : Fragment() {
|
|||
}
|
||||
|
||||
result_share?.setOnClickListener {
|
||||
try {
|
||||
val i = Intent(ACTION_SEND)
|
||||
i.type = "text/plain"
|
||||
i.putExtra(EXTRA_SUBJECT, d.name)
|
||||
i.putExtra(EXTRA_TEXT, d.url)
|
||||
startActivity(createChooser(i, d.name))
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
updateSync(d.getId())
|
||||
|
|
|
@ -32,6 +32,7 @@ import com.lagradost.cloudstream3.DubStatus
|
|||
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.syncproviders.AccountManager
|
||||
import com.lagradost.cloudstream3.syncproviders.OAuth2API
|
||||
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.aniListApi
|
||||
|
@ -301,6 +302,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
|
||||
fun getDownloadDirs(): List<String> {
|
||||
return normalSafeApiCall {
|
||||
val defaultDir = getDownloadDir()?.filePath
|
||||
|
||||
// app_name_download_path = Cloudstream and does not change depending on release.
|
||||
|
@ -308,7 +310,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
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)
|
||||
val first = listOf(defaultDir, secondaryDir)
|
||||
return (try {
|
||||
(try {
|
||||
val currentDir = context?.getBasePath()?.let { it.first?.filePath ?: it.second }
|
||||
|
||||
(first +
|
||||
|
@ -317,6 +319,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
} catch (e: Exception) {
|
||||
first
|
||||
}).filterNotNull().distinct()
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
downloadPathPreference.setOnPreferenceClickListener {
|
||||
|
|
|
@ -126,7 +126,12 @@ class InAppUpdater {
|
|||
}
|
||||
)!! < 0 else false
|
||||
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 {
|
||||
Update(false, null, null, null)
|
||||
}
|
||||
|
@ -135,7 +140,8 @@ class InAppUpdater {
|
|||
}
|
||||
|
||||
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 headers = mapOf("Accept" to "application/vnd.github.v3+json")
|
||||
val response =
|
||||
|
@ -150,10 +156,16 @@ class InAppUpdater {
|
|||
val tagResponse =
|
||||
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) {
|
||||
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 {
|
||||
Update(false, null, null, null)
|
||||
}
|
||||
|
@ -217,6 +229,7 @@ class InAppUpdater {
|
|||
}
|
||||
|
||||
fun openApk(context: Context, uri: Uri) {
|
||||
try {
|
||||
uri.path?.let {
|
||||
val contentUri = FileProvider.getUriForFile(
|
||||
context,
|
||||
|
@ -231,12 +244,18 @@ class InAppUpdater {
|
|||
}
|
||||
context.startActivity(installIntent)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun Activity.runAutoUpdate(checkAutoUpdate: Boolean = true): Boolean {
|
||||
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()
|
||||
if (update.shouldUpdate && update.updateURL != null) {
|
||||
|
@ -264,7 +283,8 @@ class InAppUpdater {
|
|||
showToast(context, R.string.download_started, Toast.LENGTH_LONG)
|
||||
thread {
|
||||
val downloadStatus =
|
||||
normalSafeApiCall { context.downloadUpdate(update.updateURL) } ?: false
|
||||
normalSafeApiCall { context.downloadUpdate(update.updateURL) }
|
||||
?: false
|
||||
if (!downloadStatus) {
|
||||
runOnUiThread {
|
||||
showToast(
|
||||
|
@ -281,7 +301,8 @@ class InAppUpdater {
|
|||
|
||||
if (checkAutoUpdate) {
|
||||
setNeutralButton(R.string.dont_show_again) { _, _ ->
|
||||
settingsManager.edit().putBoolean("auto_update", false).apply()
|
||||
settingsManager.edit().putBoolean("auto_update", false)
|
||||
.apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue