mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 15:29:15 +01:00
persist and restore the playback position within the track
This commit is contained in:
@@ -65,4 +65,11 @@ val MIGRATION_5_6 =
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATIONS: Array<Migration> = arrayOf(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6)
|
||||
val MIGRATION_6_7 =
|
||||
object : Migration(6, 7) {
|
||||
override suspend fun migrate(connection: SQLiteConnection) {
|
||||
connection.execSQL("ALTER TABLE `playback_cursor` ADD COLUMN `positionMs` INTEGER NOT NULL DEFAULT 0")
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATIONS: Array<Migration> = arrayOf(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6, MIGRATION_6_7)
|
||||
|
||||
@@ -32,7 +32,7 @@ import com.subtracks.data.model.SubsonicSource
|
||||
ShuffleOrder::class,
|
||||
ArtworkSeed::class,
|
||||
],
|
||||
version = 6,
|
||||
version = 7,
|
||||
exportSchema = true,
|
||||
)
|
||||
@ColumnTypeConverters(QueueKindConverter::class)
|
||||
|
||||
@@ -211,6 +211,7 @@ data class PlaybackCursor(
|
||||
@ColumnInfo(defaultValue = "0") val shuffleEnabled: Boolean = false,
|
||||
@ColumnInfo(defaultValue = "0") val repeatMode: Int = 0,
|
||||
@ColumnInfo(defaultValue = "0") val shuffleSeed: Long = 0,
|
||||
@ColumnInfo(defaultValue = "0") val positionMs: Long = 0,
|
||||
)
|
||||
|
||||
@Entity(tableName = "shuffle_order")
|
||||
|
||||
@@ -270,6 +270,10 @@ class QueueRepository(
|
||||
|
||||
suspend fun cursor(): Long = dao.cursor()?.queuePosition ?: 0
|
||||
|
||||
suspend fun cursorPositionMs(): Long = dao.cursor()?.positionMs ?: 0
|
||||
|
||||
suspend fun setPosition(positionMs: Long) = dao.setCursor(cursorRow().copy(positionMs = positionMs.coerceAtLeast(0)))
|
||||
|
||||
suspend fun setCursor(position: Long) = dao.setCursor(cursorRow().copy(queuePosition = position))
|
||||
|
||||
private suspend fun cursorRow(): PlaybackCursor = dao.cursor() ?: PlaybackCursor(queuePosition = 0)
|
||||
|
||||
@@ -123,6 +123,7 @@ class PlaybackController(
|
||||
private var shuffleEnabled = false
|
||||
private var repeatMode = RepeatMode.Off
|
||||
private var endedHandled = false
|
||||
private var lastSavedPositionMs = 0L
|
||||
|
||||
init {
|
||||
scope.launch {
|
||||
@@ -463,7 +464,12 @@ class PlaybackController(
|
||||
return
|
||||
}
|
||||
player.ensurePrepared()
|
||||
if (player.playWhenReady) player.pause() else player.play()
|
||||
if (player.playWhenReady) {
|
||||
player.pause()
|
||||
savePosition()
|
||||
} else {
|
||||
player.play()
|
||||
}
|
||||
}
|
||||
|
||||
fun next() {
|
||||
@@ -550,6 +556,8 @@ class PlaybackController(
|
||||
|
||||
fun seekTo(positionMs: Long) {
|
||||
player?.seekTo(positionMs)
|
||||
lastSavedPositionMs = positionMs
|
||||
scope.launch { queueRepository.setPosition(positionMs) }
|
||||
}
|
||||
|
||||
fun coverArt(
|
||||
@@ -648,7 +656,8 @@ class PlaybackController(
|
||||
}
|
||||
this.queueSourceId = queueSourceId
|
||||
val position = queueRepository.cursor().coerceIn(0, snapshot.size - 1)
|
||||
loadWindow(position, autoplay = false)
|
||||
lastSavedPositionMs = queueRepository.cursorPositionMs().coerceAtLeast(0)
|
||||
loadWindow(position, autoplay = false, startPositionMs = lastSavedPositionMs)
|
||||
}
|
||||
|
||||
private suspend fun stop() = startLock.withLock { stopLocked() }
|
||||
@@ -723,6 +732,7 @@ class PlaybackController(
|
||||
val snapshot = snapshot ?: return
|
||||
if (snapshot.size == 0L) return
|
||||
val position = (windowStart + player.currentIndex).coerceIn(0, snapshot.size - 1)
|
||||
lastSavedPositionMs = 0
|
||||
queueRepository.setCursor(position)
|
||||
refresh(position)
|
||||
scheduleWindowShift(position)
|
||||
@@ -919,11 +929,23 @@ class PlaybackController(
|
||||
while (true) {
|
||||
delay(POSITION_TICK_MS)
|
||||
val player = player ?: break
|
||||
_state.value = _state.value.copy(positionMs = player.currentPositionMs)
|
||||
val positionMs = player.currentPositionMs
|
||||
_state.value = _state.value.copy(positionMs = positionMs)
|
||||
if (positionMs - lastSavedPositionMs >= POSITION_SAVE_INTERVAL_MS || positionMs < lastSavedPositionMs) {
|
||||
lastSavedPositionMs = positionMs
|
||||
queueRepository.setPosition(positionMs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun savePosition() {
|
||||
val player = player ?: return
|
||||
val positionMs = player.currentPositionMs
|
||||
lastSavedPositionMs = positionMs
|
||||
scope.launch { queueRepository.setPosition(positionMs) }
|
||||
}
|
||||
|
||||
private fun stopPositionTicker() {
|
||||
positionJob?.cancel()
|
||||
positionJob = null
|
||||
@@ -935,6 +957,7 @@ class PlaybackController(
|
||||
|
||||
private companion object {
|
||||
const val POSITION_TICK_MS = 500L
|
||||
const val POSITION_SAVE_INTERVAL_MS = 15_000L
|
||||
const val BUFFERING_INDICATOR_DELAY_MS = 1_000L
|
||||
const val QUEUE_WINDOW_RADIUS = 25L
|
||||
const val WINDOW_SHIFT_DELAY_MS = 400L
|
||||
|
||||
Reference in New Issue
Block a user