From 484cc553854a3930122145d3144ea6e9b339ef31 Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:33:04 +0000 Subject: [PATCH] playback: prepare the restored queue so the session starts on launch Restoring the saved queue left the player idle, so the media session had no notification and Bluetooth or Automate saw no active player until playback began. Prepare the restored window without autoplaying, which surfaces the paused session when the app opens. A queue from another source stays stopped, and an offline queue without downloads has no window to prepare. Closes austinried/subtracks#202 --- .../subtracks/playback/PlaybackController.kt | 1 + .../playback/PlaybackControllerTest.kt | 44 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt b/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt index c11673f1..667fe2dc 100644 --- a/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt +++ b/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt @@ -1070,6 +1070,7 @@ class PlaybackController( } lastSavedPositionMs = savedPositionMs loadWindow(anchor.position, autoplay = false, startPositionMs = savedPositionMs) + if ((player?.itemCount ?: 0) > 0) player?.ensurePrepared() } private suspend fun stop() = startLock.withLock { stopLocked() } diff --git a/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt b/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt index a572cc93..acfbf07d 100644 --- a/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt +++ b/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt @@ -343,7 +343,46 @@ class PlaybackControllerTest { } @Test - fun togglingPlayOnARestoredQueuePreparesBeforePlaying() { + fun restoringAPreviousQueuePreparesTheSessionWithoutPlaying() { + seedAlbum(3, sourceId = 1) + runBlocking { queues.replace(listOf(queues.albumEntry(1, "al1"))) } + + controller.connect() + await { handle.items.isNotEmpty() } + + assertTrue(handle.operations.contains("prepare")) + assertFalse(handle.operations.contains("play")) + assertFalse(handle.isIdle) + assertFalse(handle.playWhenReady) + assertFalse(controller.state.value.isPlaying) + } + + @Test + fun restoringAnEmptyQueueDoesNotPrepare() { + seedAlbum(3, sourceId = 1) + + controller.connect() + await { controller.ready.value } + + assertTrue(handle.items.isEmpty()) + assertFalse(handle.operations.contains("prepare")) + } + + @Test + fun restoringAnOfflineQueueWithoutDownloadsDoesNotPrepare() { + seedAlbum(3, sourceId = 1) + runBlocking { queues.replace(listOf(queues.albumEntry(1, "al1"))) } + setOffline() + + controller.connect() + await { controller.ready.value } + + assertTrue(handle.items.isEmpty()) + assertFalse(handle.operations.contains("prepare")) + } + + @Test + fun togglingPlayOnARestoredQueuePlaysThePreparedWindow() { seedAlbum(5, sourceId = 1) runBlocking { queues.replace(listOf(queues.albumEntry(1, "al1"))) } @@ -354,7 +393,8 @@ class PlaybackControllerTest { controller.togglePlayPause() await { handle.operations.contains("play") } - assertEquals(listOf("prepare", "play"), handle.operations) + assertEquals(listOf("play"), handle.operations) + assertTrue(handle.playWhenReady) } @Test