diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/skip/PlayerNextEpisodeRules.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/skip/PlayerNextEpisodeRules.kt index 3098446c0..a15b6b955 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/skip/PlayerNextEpisodeRules.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/skip/PlayerNextEpisodeRules.kt @@ -39,11 +39,32 @@ object PlayerNextEpisodeRules { val latestOutroEndMs = (outroSegments.maxOf { it.endTime } * 1_000.0).toLong() val postOutroGapMs = durationMs - latestOutroEndMs - return if (postOutroGapMs > POST_OUTRO_AUTOPLAY_GAP_MS) { - // Post-credits scene: hold prompt until video truly ends. - positionMs >= durationMs - END_OF_VIDEO_EPSILON_MS + // Calculate the user's configured threshold as milliseconds from end. + val userThresholdMs = when (thresholdMode) { + NextEpisodeThresholdMode.PERCENTAGE -> { + val clampedPercent = thresholdPercent.coerceIn(97f, 100f) + ((1.0 - clampedPercent / 100.0) * durationMs).toLong() + } + NextEpisodeThresholdMode.MINUTES_BEFORE_END -> { + val clampedMinutes = thresholdMinutesBeforeEnd.coerceIn(0f, 3.5f) + (clampedMinutes * 60_000f).toLong() + } + } + + return if (postOutroGapMs > userThresholdMs) { + when (thresholdMode) { + NextEpisodeThresholdMode.PERCENTAGE -> { + val clampedPercent = thresholdPercent.coerceIn(97f, 100f) + (positionMs.toDouble() / durationMs.toDouble()) >= (clampedPercent / 100.0) + } + NextEpisodeThresholdMode.MINUTES_BEFORE_END -> { + val clampedMinutes = thresholdMinutesBeforeEnd.coerceIn(0f, 3.5f) + val remainingMs = durationMs - positionMs + remainingMs <= (clampedMinutes * 60_000f).toLong() + } + } } else { - // No post-credits scene: fire as soon as the earliest outro starts. + // Outro ends close to the file end — fire at earliest outro start. positionMs / 1_000.0 >= outroSegments.minOf { it.startTime } } }