Implemented automatic fallback for sources.

This commit is contained in:
2026-10-28 10:20:00 -04:00
parent bd7d443f21
commit 3d59612d6e
3 changed files with 34 additions and 3 deletions

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@ android/.gradle/
www/
android/app/src/main/assets/
release/
android/app/src/main/res/raw/*.crt

View File

@@ -79,6 +79,7 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withTimeoutOrNull
import tv.vyla.app.ui.components.VideoTintSampler
import tv.vyla.app.ui.components.videoTint
import android.util.Log
enum class ActivePlayerMenu {
NONE, QUALITY, SUBTITLES, VOLUME, SETTINGS, MORE
@@ -223,6 +224,33 @@ fun PlayerScreen(
exoPlayer.prepare()
exoPlayer.play()
resetHideTimer()
}
DisposableEffect(exoPlayer) {
val errorListener = object : Player.Listener { // source auto-fallback
override fun onPlayerError(error: androidx.media3.common.PlaybackException) {
val currentIdx = resolvedStreams.indexOf(activeStream)
if (currentIdx != -1 && currentIdx + 1 < resolvedStreams.size) {
// android.widget.Toast.makeText(context, "Source failed. Trying next...", android.widget.Toast.LENGTH_SHORT).show()
Log.e("vyla", "Source failed. Trying next...")
coroutineScope.launch {
delay(1500) // follow rate limits
val nextStream = resolvedStreams[currentIdx + 1]
activeStream = nextStream
playStream(nextStream.primaryUrl, nextStream.headers)
}
} else {
isBuffering = false
Log.e("vyla", "All Sources Failed")
android.widget.Toast.makeText(context, "All available sources failed. Please disable any VPN or try again later", android.widget.Toast.LENGTH_LONG).show()
}
}
}
exoPlayer.addListener(errorListener)
onDispose {
exoPlayer.removeListener(errorListener)
}
}
suspend fun focusEpisodeCard() {
var tries = 0
@@ -300,7 +328,9 @@ fun PlayerScreen(
onFirstPlayable = { stream ->
coroutineScope.launch {
activeStream = stream
if (!resolvedStreams.any { it.provider == stream.provider }) {
resolvedStreams.add(stream)
}
playStream(stream.primaryUrl, stream.headers)
}
},
@@ -938,7 +968,7 @@ fun PlayerScreen(
items(resolvedStreams) { stream ->
MenuItemRow(
label = stream.label,
isSelected = activeStream?.provider == stream.provider,
isSelected = ((activeStream?.provider == stream.provider) && (activeStream?.primaryUrl == stream.primaryUrl)),
onClick = {
activeStream = stream
playStream(stream.primaryUrl, stream.headers)

0
android/gradlew vendored Normal file → Executable file
View File