diff --git a/app/src/main/java/com/nuvio/tv/data/local/PlayerSettingsDataStore.kt b/app/src/main/java/com/nuvio/tv/data/local/PlayerSettingsDataStore.kt
index b562623e..952a74d7 100644
--- a/app/src/main/java/com/nuvio/tv/data/local/PlayerSettingsDataStore.kt
+++ b/app/src/main/java/com/nuvio/tv/data/local/PlayerSettingsDataStore.kt
@@ -184,6 +184,7 @@ data class PlayerSettings(
val streamAutoPlayRegex: String = "",
val streamAutoPlayNextEpisodeEnabled: Boolean = false,
val streamAutoPlayPreferBingeGroupForNextEpisode: Boolean = true,
+ val streamAutoPlayTimeoutSeconds: Int = 3,
val nextEpisodeThresholdMode: NextEpisodeThresholdMode = NextEpisodeThresholdMode.PERCENTAGE,
val nextEpisodeThresholdPercent: Float = 99f,
val nextEpisodeThresholdMinutesBeforeEnd: Float = 2f,
@@ -289,6 +290,7 @@ class PlayerSettingsDataStore @Inject constructor(
private val streamAutoPlayRegexKey = stringPreferencesKey("stream_auto_play_regex")
private val streamAutoPlayNextEpisodeEnabledKey = booleanPreferencesKey("stream_auto_play_next_episode_enabled")
private val streamAutoPlayPreferBingeGroupForNextEpisodeKey = booleanPreferencesKey("stream_auto_play_prefer_bingegroup_next_episode")
+ private val streamAutoPlayTimeoutSecondsKey = intPreferencesKey("stream_auto_play_timeout_seconds")
private val nextEpisodeThresholdModeKey = stringPreferencesKey("next_episode_threshold_mode")
private val nextEpisodeThresholdPercentLegacyKey = intPreferencesKey("next_episode_threshold_percent")
private val nextEpisodeThresholdMinutesBeforeEndLegacyKey = intPreferencesKey("next_episode_threshold_minutes_before_end")
@@ -437,6 +439,7 @@ class PlayerSettingsDataStore @Inject constructor(
streamAutoPlayNextEpisodeEnabled = prefs[streamAutoPlayNextEpisodeEnabledKey] ?: false,
streamAutoPlayPreferBingeGroupForNextEpisode =
prefs[streamAutoPlayPreferBingeGroupForNextEpisodeKey] ?: true,
+ streamAutoPlayTimeoutSeconds = (prefs[streamAutoPlayTimeoutSecondsKey] ?: 3).coerceIn(0, 10),
nextEpisodeThresholdMode = prefs[nextEpisodeThresholdModeKey]?.let {
runCatching { NextEpisodeThresholdMode.valueOf(it) }.getOrDefault(NextEpisodeThresholdMode.PERCENTAGE)
} ?: NextEpisodeThresholdMode.PERCENTAGE,
@@ -641,6 +644,12 @@ class PlayerSettingsDataStore @Inject constructor(
}
}
+ suspend fun setStreamAutoPlayTimeoutSeconds(seconds: Int) {
+ store().edit { prefs ->
+ prefs[streamAutoPlayTimeoutSecondsKey] = seconds.coerceIn(0, 10)
+ }
+ }
+
suspend fun setNextEpisodeThresholdMode(mode: NextEpisodeThresholdMode) {
store().edit { prefs ->
prefs[nextEpisodeThresholdModeKey] = mode.name
diff --git a/app/src/main/java/com/nuvio/tv/ui/screens/player/PlayerRuntimeControllerStreams.kt b/app/src/main/java/com/nuvio/tv/ui/screens/player/PlayerRuntimeControllerStreams.kt
index e0a6faea..5e2b4144 100644
--- a/app/src/main/java/com/nuvio/tv/ui/screens/player/PlayerRuntimeControllerStreams.kt
+++ b/app/src/main/java/com/nuvio/tv/ui/screens/player/PlayerRuntimeControllerStreams.kt
@@ -822,7 +822,10 @@ internal fun PlayerRuntimeController.playNextEpisode() {
}
}
- delay(5_000L)
+ val timeoutMs = playerSettings.streamAutoPlayTimeoutSeconds * 1_000L
+ if (timeoutMs > 0L) {
+ delay(timeoutMs)
+ }
timeoutElapsed = true
if (!autoSelectTriggered && lastSuccessData != null) {
autoSelectTriggered = true
diff --git a/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackAutoPlaySettings.kt b/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackAutoPlaySettings.kt
index 4233ac5c..bd845fa1 100644
--- a/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackAutoPlaySettings.kt
+++ b/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackAutoPlaySettings.kt
@@ -28,6 +28,7 @@ import androidx.compose.material.icons.filled.Extension
import androidx.compose.material.icons.filled.Language
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.SkipNext
+import androidx.compose.material.icons.filled.Timer
import androidx.compose.material.icons.filled.History
import androidx.compose.material.icons.filled.Tune
import androidx.compose.runtime.Composable
@@ -81,6 +82,7 @@ internal fun LazyListScope.autoPlaySettingsItems(
onSetStreamAutoPlayPreferBingeGroupForNextEpisode: (Boolean) -> Unit,
onSetNextEpisodeThresholdPercent: (Float) -> Unit,
onSetNextEpisodeThresholdMinutesBeforeEnd: (Float) -> Unit,
+ onSetStreamAutoPlayTimeoutSeconds: (Int) -> Unit,
onSetReuseLastLinkEnabled: (Boolean) -> Unit,
onItemFocused: () -> Unit = {}
) {
@@ -122,6 +124,29 @@ internal fun LazyListScope.autoPlaySettingsItems(
)
}
+ if (playerSettings.streamAutoPlayMode != StreamAutoPlayMode.MANUAL) {
+ item(key = "autoplay_stream_timeout") {
+ val timeoutSec = playerSettings.streamAutoPlayTimeoutSeconds
+ val valueText = if (timeoutSec == 0) {
+ stringResource(R.string.autoplay_timeout_instant)
+ } else {
+ "${timeoutSec}s"
+ }
+ SliderSettingsItem(
+ icon = Icons.Default.Timer,
+ title = stringResource(R.string.autoplay_timeout_title),
+ subtitle = stringResource(R.string.autoplay_timeout_sub),
+ value = timeoutSec,
+ valueText = valueText,
+ minValue = 0,
+ maxValue = 10,
+ step = 1,
+ onValueChange = { onSetStreamAutoPlayTimeoutSeconds(it) },
+ onFocused = onItemFocused
+ )
+ }
+ }
+
item(key = "autoplay_next_episode") {
ToggleSettingsItem(
icon = Icons.Default.SkipNext,
diff --git a/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsScreen.kt b/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsScreen.kt
index 2bb6150d..ceb153fa 100644
--- a/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsScreen.kt
+++ b/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsScreen.kt
@@ -231,6 +231,9 @@ fun PlaybackSettingsContent(
onSetNextEpisodeThresholdMinutesBeforeEnd = { minutes ->
coroutineScope.launch { viewModel.setNextEpisodeThresholdMinutesBeforeEnd(minutes) }
},
+ onSetStreamAutoPlayTimeoutSeconds = { seconds ->
+ coroutineScope.launch { viewModel.setStreamAutoPlayTimeoutSeconds(seconds) }
+ },
onSetReuseLastLinkEnabled = { enabled -> coroutineScope.launch { viewModel.setStreamReuseLastLinkEnabled(enabled) } },
onSetLoadingOverlayEnabled = { enabled -> coroutineScope.launch { viewModel.setLoadingOverlayEnabled(enabled) } },
onSetPauseOverlayEnabled = { enabled -> coroutineScope.launch { viewModel.setPauseOverlayEnabled(enabled) } },
diff --git a/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsSections.kt b/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsSections.kt
index 884b495b..42df8014 100644
--- a/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsSections.kt
+++ b/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsSections.kt
@@ -112,6 +112,7 @@ internal fun PlaybackSettingsSections(
onSetStreamAutoPlayPreferBingeGroupForNextEpisode: (Boolean) -> Unit,
onSetNextEpisodeThresholdPercent: (Float) -> Unit,
onSetNextEpisodeThresholdMinutesBeforeEnd: (Float) -> Unit,
+ onSetStreamAutoPlayTimeoutSeconds: (Int) -> Unit,
onSetReuseLastLinkEnabled: (Boolean) -> Unit,
onSetLoadingOverlayEnabled: (Boolean) -> Unit,
onSetPauseOverlayEnabled: (Boolean) -> Unit,
@@ -315,6 +316,7 @@ internal fun PlaybackSettingsSections(
onSetStreamAutoPlayPreferBingeGroupForNextEpisode = onSetStreamAutoPlayPreferBingeGroupForNextEpisode,
onSetNextEpisodeThresholdPercent = onSetNextEpisodeThresholdPercent,
onSetNextEpisodeThresholdMinutesBeforeEnd = onSetNextEpisodeThresholdMinutesBeforeEnd,
+ onSetStreamAutoPlayTimeoutSeconds = onSetStreamAutoPlayTimeoutSeconds,
onSetReuseLastLinkEnabled = onSetReuseLastLinkEnabled,
onItemFocused = { focusedSection = PlaybackSection.STREAM_SELECTION }
)
diff --git a/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsViewModel.kt b/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsViewModel.kt
index fd3be0ed..b4e94b23 100644
--- a/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsViewModel.kt
+++ b/app/src/main/java/com/nuvio/tv/ui/screens/settings/PlaybackSettingsViewModel.kt
@@ -237,6 +237,10 @@ class PlaybackSettingsViewModel @Inject constructor(
playerSettingsDataStore.setStreamAutoPlayPreferBingeGroupForNextEpisode(enabled)
}
+ suspend fun setStreamAutoPlayTimeoutSeconds(seconds: Int) {
+ playerSettingsDataStore.setStreamAutoPlayTimeoutSeconds(seconds)
+ }
+
suspend fun setNextEpisodeThresholdMode(mode: NextEpisodeThresholdMode) {
playerSettingsDataStore.setNextEpisodeThresholdMode(mode)
}
diff --git a/app/src/main/java/com/nuvio/tv/ui/screens/stream/StreamScreenViewModel.kt b/app/src/main/java/com/nuvio/tv/ui/screens/stream/StreamScreenViewModel.kt
index 35afaf2f..ac8e9af2 100644
--- a/app/src/main/java/com/nuvio/tv/ui/screens/stream/StreamScreenViewModel.kt
+++ b/app/src/main/java/com/nuvio/tv/ui/screens/stream/StreamScreenViewModel.kt
@@ -399,8 +399,11 @@ class StreamScreenViewModel @Inject constructor(
}
}
- // After 5s: if streams arrived, auto-select now; if not, wait for first result from inner job
- delay(5_000L)
+ // After timeout: if streams arrived, auto-select now; if not, wait for first result from inner job
+ val timeoutMs = playerSettings.streamAutoPlayTimeoutSeconds * 1_000L
+ if (timeoutMs > 0L) {
+ delay(timeoutMs)
+ }
timeoutElapsed = true
if (!autoSelectTriggered && lastSuccessData != null) {
autoSelectTriggered = true
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index ff9a9699..921474aa 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -282,6 +282,9 @@
Tylko zainstalowane dodatki
Tylko włączone wtyczki
Zakres źródeł auto-play
+ Limit czasu wyboru strumienia
+ Czas oczekiwania na dodatki przed wyborem. 0 = pierwszy wynik wygrywa.
+ Natychmiast
Dozwolone dodatki
Wszystkie zainstalowane dodatki
Dozwolone wtyczki
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 077059f2..6db33005 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -351,6 +351,9 @@
Installed addons only
Enabled plugins only
Auto-play Source Scope
+ Stream Selection Timeout
+ Wait time for addons before selecting. 0 = first result wins.
+ Instant
Allowed Addons
All installed addons
Allowed Plugins