diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt index c7bf3e5c..d264a7ad 100644 --- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt +++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt @@ -478,7 +478,17 @@ class FutoVideoPlayer : FutoVideoPlayerBase { updateAutoplayButton() val progressUpdateListener = { position: Long, bufferedPosition: Long -> - val currentTime = position.formatDuration() + // For live streams that have been seeked behind, replace the running position with + // a -MM:SS "behind live" indicator (the videojs/HLS convention). At the live edge + // we keep showing the running position; this matches YouTube's web behaviour where + // the LIVE pill alone (red "caught up" / gray "behind") + a clear offset readout + // tell the whole story. + val behindMs = if (isLive) behindLiveMs else null + val currentTime = if (behindMs != null && behindMs > 0) { + "-" + behindMs.formatDuration() + } else { + position.formatDuration() + } val currentDuration = duration.formatDuration() _control_time.text = currentTime; _control_time_fullscreen.text = currentTime; diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt index af5ce802..bc24397e 100644 --- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt +++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt @@ -176,6 +176,18 @@ abstract class FutoVideoPlayerBase : RelativeLayout { } } + /** + * How far the player is behind the live edge from a user perspective, in ms. Subtracts the + * manifest's natural live offset (or the [LIVE_EDGE_FALLBACK_THRESHOLD_MS] when unknown) so + * the value reflects the user-perceptible delay rather than the inherent HLS/DASH latency. + * Returns null when not live or the offset is unknown; returns 0 when at the live edge. + */ + val behindLiveMs: Long? get() { + val offset = liveOffsetMs ?: return null + val baseline = targetLiveOffsetMs ?: LIVE_EDGE_FALLBACK_THRESHOLD_MS + return (offset - baseline).coerceAtLeast(0) + } + var isAudioMode: Boolean = false private set;