From a714e2dea922d63fcf41dbcee5d8791f320515d9 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Fri, 17 Apr 2026 19:06:06 -0600 Subject: [PATCH 1/3] Fix player notification and STATE_IDLE issues --- .../cloudstream3/ui/player/CS3IPlayer.kt | 15 +++++++++++++++ .../cloudstream3/ui/player/GeneratorPlayer.kt | 10 ++++++++++ 2 files changed, 25 insertions(+) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt index 8a643cc69b8..6ca83e33003 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt @@ -961,6 +961,21 @@ class CS3IPlayer : IPlayer { when (event) { CSPlayerEvent.Play -> { event(PlayEvent(source)) + // If the player was stopped (e.g. notification dismissed) it lands in + // STATE_IDLE. A bare play() call is a no-op in that state, re-prepare and + // then resume to the saved position once we are in STATE_READY again. + if (playbackState == Player.STATE_IDLE) { + prepare() + exoPlayer?.addListener(object : Player.Listener { + private var seekApplied = false + override fun onPlaybackStateChanged(playbackState: Int) { + if (seekApplied || playbackState != Player.STATE_READY) return + seekApplied = true + exoPlayer?.seekTo(currentWindow, playbackPosition) + exoPlayer?.removeListener(this) + } + }) + } play() } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt index 16b03e4f61c..17f07d9db2e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt @@ -393,6 +393,16 @@ class GeneratorPlayer : FullScreenPlayer() { } } }) + .setNotificationListener(object : PlayerNotificationManager.NotificationListener { + override fun onNotificationCancelled(notificationId: Int, dismissedByUser: Boolean) { + if (dismissedByUser) { + // User explicitly swiped the notification away, detach cleanly so it + // doesn't reappear and to avoid any further interactions with the player. + cachedPlayerNotificationManager?.setPlayer(null) + cachedPlayerNotificationManager = null + } + } + }) .setPlayActionIconResourceId(R.drawable.ic_baseline_play_arrow_24) .setPauseActionIconResourceId(R.drawable.netflix_pause) .setSmallIconResourceId(R.drawable.baseline_headphones_24) From 4e78b9eb2ff59b91cf289c32f9feaa233d64498f Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 18 Apr 2026 13:14:56 -0600 Subject: [PATCH 2/3] Fix --- .../com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt | 7 ++++--- .../cloudstream3/ui/player/GeneratorPlayer.kt | 10 ---------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt index 6ca83e33003..0ff31f10843 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt @@ -963,18 +963,19 @@ class CS3IPlayer : IPlayer { event(PlayEvent(source)) // If the player was stopped (e.g. notification dismissed) it lands in // STATE_IDLE. A bare play() call is a no-op in that state, re-prepare and - // then resume to the saved position once we are in STATE_READY again. + // then resume to the current position once we are in STATE_READY again. if (playbackState == Player.STATE_IDLE) { - prepare() + val mediaPosition = currentPosition exoPlayer?.addListener(object : Player.Listener { private var seekApplied = false override fun onPlaybackStateChanged(playbackState: Int) { if (seekApplied || playbackState != Player.STATE_READY) return seekApplied = true - exoPlayer?.seekTo(currentWindow, playbackPosition) + exoPlayer?.seekTo(currentWindow, mediaPosition) exoPlayer?.removeListener(this) } }) + prepare() } play() } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt index 17f07d9db2e..16b03e4f61c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt @@ -393,16 +393,6 @@ class GeneratorPlayer : FullScreenPlayer() { } } }) - .setNotificationListener(object : PlayerNotificationManager.NotificationListener { - override fun onNotificationCancelled(notificationId: Int, dismissedByUser: Boolean) { - if (dismissedByUser) { - // User explicitly swiped the notification away, detach cleanly so it - // doesn't reappear and to avoid any further interactions with the player. - cachedPlayerNotificationManager?.setPlayer(null) - cachedPlayerNotificationManager = null - } - } - }) .setPlayActionIconResourceId(R.drawable.ic_baseline_play_arrow_24) .setPauseActionIconResourceId(R.drawable.netflix_pause) .setSmallIconResourceId(R.drawable.baseline_headphones_24) From 08bb81583a37afabe763e09c42b3c9a7f89340e5 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 18 Apr 2026 21:30:45 -0600 Subject: [PATCH 3/3] Better variable name --- .../java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt index 0ff31f10843..81bbcc59f3f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt @@ -965,13 +965,13 @@ class CS3IPlayer : IPlayer { // STATE_IDLE. A bare play() call is a no-op in that state, re-prepare and // then resume to the current position once we are in STATE_READY again. if (playbackState == Player.STATE_IDLE) { - val mediaPosition = currentPosition + val seekPosition = currentPosition exoPlayer?.addListener(object : Player.Listener { private var seekApplied = false override fun onPlaybackStateChanged(playbackState: Int) { if (seekApplied || playbackState != Player.STATE_READY) return seekApplied = true - exoPlayer?.seekTo(currentWindow, mediaPosition) + exoPlayer?.seekTo(currentWindow, seekPosition) exoPlayer?.removeListener(this) } })