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