ultrasonic-app-subsonic-and.../ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/DownloadQueueSerializer.kt

113 lines
3.3 KiB
Kotlin

/*
* DownloadQueueSerializer.kt
* Copyright (C) 2009-2021 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.service
import android.content.Context
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.MediaSessionHandler
import timber.log.Timber
/**
* This class is responsible for the serialization / deserialization
* of the DownloadQueue (playlist) to the filesystem.
* It also serializes the player state e.g. current playing number and play position.
*/
class DownloadQueueSerializer : KoinComponent {
private val context by inject<Context>()
private val mediaSessionHandler by inject<MediaSessionHandler>()
val lock: Lock = ReentrantLock()
val setup = AtomicBoolean(false)
private val appScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
fun serializeDownloadQueue(
songs: Iterable<DownloadFile>,
currentPlayingIndex: Int,
currentPlayingPosition: Int
) {
if (!setup.get()) return
appScope.launch {
if (lock.tryLock()) {
try {
serializeDownloadQueueNow(songs, currentPlayingIndex, currentPlayingPosition)
} finally {
lock.unlock()
}
}
}
}
fun serializeDownloadQueueNow(
songs: Iterable<DownloadFile>,
currentPlayingIndex: Int,
currentPlayingPosition: Int
) {
val state = State()
for (downloadFile in songs) {
state.songs.add(downloadFile.song)
}
state.currentPlayingIndex = currentPlayingIndex
state.currentPlayingPosition = currentPlayingPosition
Timber.i(
"Serialized currentPlayingIndex: %d, currentPlayingPosition: %d",
state.currentPlayingIndex,
state.currentPlayingPosition
)
FileUtil.serialize(context, state, Constants.FILENAME_DOWNLOADS_SER)
// This is called here because the queue is usually serialized after a change
mediaSessionHandler.updateMediaSessionQueue(state.songs)
}
fun deserializeDownloadQueue(afterDeserialized: Consumer<State?>) {
appScope.launch {
try {
lock.lock()
deserializeDownloadQueueNow(afterDeserialized)
setup.set(true)
} finally {
lock.unlock()
}
}
}
private fun deserializeDownloadQueueNow(afterDeserialized: Consumer<State?>) {
val state = FileUtil.deserialize<State>(
context, Constants.FILENAME_DOWNLOADS_SER
) ?: return
Timber.i(
"Deserialized currentPlayingIndex: %d, currentPlayingPosition: %d ",
state.currentPlayingIndex,
state.currentPlayingPosition
)
mediaSessionHandler.updateMediaSessionQueue(state.songs)
afterDeserialized.accept(state)
}
}