mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-07-13 07:24:55 +02:00
Add keep local media progress and playback sessions, update data models to support syncing local progress and support for podcast episodes
This commit is contained in:
parent
526fca98b9
commit
d9e4469089
23 changed files with 295 additions and 118 deletions
|
@ -76,10 +76,9 @@ class DbManager {
|
|||
|
||||
fun getAllLocalFolders():List<LocalFolder> {
|
||||
var localFolders:MutableList<LocalFolder> = mutableListOf()
|
||||
Paper.book("localFolders").allKeys.forEach {
|
||||
var localFolder:LocalFolder? = Paper.book("localFolders").read(it)
|
||||
if (localFolder != null) {
|
||||
localFolders.add(localFolder)
|
||||
Paper.book("localFolders").allKeys.forEach { localFolderId ->
|
||||
Paper.book("localFolders").read<LocalFolder>(localFolderId)?.let {
|
||||
localFolders.add(it)
|
||||
}
|
||||
}
|
||||
return localFolders
|
||||
|
@ -103,15 +102,41 @@ class DbManager {
|
|||
|
||||
fun getDownloadItems():List<AbsDownloader.DownloadItem> {
|
||||
var downloadItems:MutableList<AbsDownloader.DownloadItem> = mutableListOf()
|
||||
Paper.book("downloadItems").allKeys.forEach {
|
||||
var downloadItem:AbsDownloader.DownloadItem? = Paper.book("downloadItems").read(it)
|
||||
if (downloadItem != null) {
|
||||
downloadItems.add(downloadItem)
|
||||
Paper.book("downloadItems").allKeys.forEach { downloadItemId ->
|
||||
Paper.book("downloadItems").read<AbsDownloader.DownloadItem>(downloadItemId)?.let {
|
||||
downloadItems.add(it)
|
||||
}
|
||||
}
|
||||
return downloadItems
|
||||
}
|
||||
|
||||
fun saveLocalMediaProgress(mediaProgress:LocalMediaProgress) {
|
||||
Paper.book("localMediaProgress").write(mediaProgress.id,mediaProgress)
|
||||
}
|
||||
// For books this will just be the localLibraryItemId for podcast episodes this will be "{localLibraryItemId}-{episodeId}"
|
||||
fun getLocalMediaProgress(localMediaProgressId:String):LocalMediaProgress? {
|
||||
return Paper.book("localMediaProgress").read(localMediaProgressId)
|
||||
}
|
||||
fun getAllLocalMediaProgress():List<LocalMediaProgress> {
|
||||
var mediaProgress:MutableList<LocalMediaProgress> = mutableListOf()
|
||||
Paper.book("localMediaProgress").allKeys.forEach { localMediaProgressId ->
|
||||
Paper.book("localMediaProgress").read<LocalMediaProgress>(localMediaProgressId)?.let {
|
||||
mediaProgress.add(it)
|
||||
}
|
||||
}
|
||||
return mediaProgress
|
||||
}
|
||||
fun removeLocalMediaProgress(localMediaProgressId:String) {
|
||||
Paper.book("localMediaProgress").delete(localMediaProgressId)
|
||||
}
|
||||
|
||||
fun saveLocalPlaybackSession(playbackSession:PlaybackSession) {
|
||||
Paper.book("localPlaybackSession").write(playbackSession.id,playbackSession)
|
||||
}
|
||||
fun getLocalPlaybackSession(playbackSessionId:String):PlaybackSession? {
|
||||
return Paper.book("localPlaybackSession").read(playbackSessionId)
|
||||
}
|
||||
|
||||
fun saveObject(db:String, key:String, value:JSONObject) {
|
||||
Log.d(tag, "Saving Object $key ${value.toString()}")
|
||||
Paper.book(db).write(key, value)
|
||||
|
|
|
@ -9,6 +9,7 @@ data class ServerConnectionConfig(
|
|||
var index:Int,
|
||||
var name:String,
|
||||
var address:String,
|
||||
var userId:String,
|
||||
var username:String,
|
||||
var token:String
|
||||
)
|
||||
|
@ -16,7 +17,7 @@ data class ServerConnectionConfig(
|
|||
data class DeviceData(
|
||||
var serverConnectionConfigs:MutableList<ServerConnectionConfig>,
|
||||
var lastServerConnectionConfigId:String?,
|
||||
var localLibraryItemIdPlaying:String?
|
||||
var currentLocalPlaybackSession:PlaybackSession? // Stored to open up where left off for local media
|
||||
)
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.audiobookshelf.app.data
|
||||
|
||||
import com.audiobookshelf.app.device.DeviceManager
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import java.util.*
|
||||
|
@ -7,8 +8,6 @@ import java.util.*
|
|||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class LocalLibraryItem(
|
||||
var id:String,
|
||||
var serverAddress:String?,
|
||||
var libraryItemId:String?,
|
||||
var folderId:String,
|
||||
var basePath:String,
|
||||
var absolutePath:String,
|
||||
|
@ -19,8 +18,14 @@ data class LocalLibraryItem(
|
|||
var localFiles:MutableList<LocalFile>,
|
||||
var coverContentUrl:String?,
|
||||
var coverAbsolutePath:String?,
|
||||
var isLocal:Boolean
|
||||
) {
|
||||
var isLocal:Boolean,
|
||||
// If local library item is linked to a server item
|
||||
var serverConnectionConfigId:String?,
|
||||
var serverAddress:String?,
|
||||
var serverUserId:String?,
|
||||
var libraryItemId:String?
|
||||
) {
|
||||
|
||||
@JsonIgnore
|
||||
fun getDuration():Double {
|
||||
var total = 0.0
|
||||
|
@ -45,9 +50,14 @@ data class LocalLibraryItem(
|
|||
}
|
||||
|
||||
@JsonIgnore
|
||||
fun getPlaybackSession():PlaybackSession {
|
||||
fun getPlaybackSession(episodeId:String):PlaybackSession {
|
||||
var sessionId = "play-${UUID.randomUUID()}"
|
||||
|
||||
val mediaProgressId = if (episodeId.isNullOrEmpty()) id else "$id-$episodeId"
|
||||
var mediaProgress = DeviceManager.dbManager.getLocalMediaProgress(mediaProgressId)
|
||||
var currentTime = mediaProgress?.currentTime ?: 0.0
|
||||
|
||||
// TODO: Clean up add mediaType methods for displayTitle and displayAuthor
|
||||
var mediaMetadata = media.metadata
|
||||
var chapters = if (mediaType == "book") (media as Book).chapters else mutableListOf()
|
||||
var authorName = "Unknown"
|
||||
|
@ -55,7 +65,10 @@ data class LocalLibraryItem(
|
|||
var bookMetadata = mediaMetadata as BookMetadata
|
||||
authorName = bookMetadata?.authorName ?: "Unknown"
|
||||
}
|
||||
return PlaybackSession(sessionId,null,null,null, mediaType, mediaMetadata, chapters, mediaMetadata.title, authorName,null,getDuration(),PLAYMETHOD_LOCAL, media.getAudioTracks() as MutableList<AudioTrack>,0.0,null,this,null,null)
|
||||
|
||||
var episodeIdNullable = if (episodeId.isNullOrEmpty()) null else episodeId
|
||||
var dateNow = System.currentTimeMillis()
|
||||
return PlaybackSession(sessionId,serverUserId,libraryItemId,episodeIdNullable, mediaType, mediaMetadata, chapters, mediaMetadata.title, authorName,null,getDuration(),PLAYMETHOD_LOCAL,dateNow,0L,0L, media.getAudioTracks() as MutableList<AudioTrack>,currentTime,null,this,serverConnectionConfigId, serverAddress)
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
|
|
|
@ -10,7 +10,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
|||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class LocalMediaItem(
|
||||
var id:String,
|
||||
var serverAddress:String?,
|
||||
var name: String,
|
||||
var mediaType:String,
|
||||
var folderId:String,
|
||||
|
@ -63,10 +62,10 @@ data class LocalMediaItem(
|
|||
if (mediaType == "book") {
|
||||
var chapters = getAudiobookChapters()
|
||||
var book = Book(mediaMetadata as BookMetadata, coverAbsolutePath, mutableListOf(), mutableListOf(), chapters,audioTracks,getTotalSize(),getDuration())
|
||||
return LocalLibraryItem(id,serverAddress, null, folderId, basePath,absolutePath, contentUrl, false,mediaType, book, localFiles, coverContentUrl, coverAbsolutePath,true)
|
||||
return LocalLibraryItem(id, folderId, basePath,absolutePath, contentUrl, false,mediaType, book, localFiles, coverContentUrl, coverAbsolutePath,true,null,null,null,null)
|
||||
} else {
|
||||
var podcast = Podcast(mediaMetadata as PodcastMetadata, coverAbsolutePath, mutableListOf(), mutableListOf(), false)
|
||||
return LocalLibraryItem(id,serverAddress, null, folderId, basePath,absolutePath, contentUrl, false, mediaType, podcast,localFiles,coverContentUrl, coverAbsolutePath, true)
|
||||
return LocalLibraryItem(id, folderId, basePath,absolutePath, contentUrl, false, mediaType, podcast,localFiles,coverContentUrl, coverAbsolutePath, true, null,null,null,null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package com.audiobookshelf.app.data
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class LocalMediaProgress(
|
||||
var id:String,
|
||||
var localLibraryItemId:String,
|
||||
var episodeId:String?,
|
||||
var duration:Double,
|
||||
var progress:Double, // 0 to 1
|
||||
var currentTime:Double,
|
||||
var isFinished:Boolean,
|
||||
var lastUpdate:Long,
|
||||
var startedAt:Long,
|
||||
var finishedAt:Long?,
|
||||
// For local lib items from server to support server sync
|
||||
var serverConnectionConfigId:String?,
|
||||
var serverAddress:String?,
|
||||
var serverUserId:String?,
|
||||
var libraryItemId:String?
|
||||
)
|
|
@ -1,18 +0,0 @@
|
|||
package com.audiobookshelf.app.data
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class MediaProgress(
|
||||
val id:String,
|
||||
val libraryItemId:String,
|
||||
val episodeId:String,
|
||||
val duration:Double,
|
||||
val progress:Double, // 0 to 1
|
||||
val currentTime:Int,
|
||||
val isFinished:Boolean,
|
||||
val lastUpdate:Long,
|
||||
val startedAt:Long,
|
||||
val finishedAt:Long,
|
||||
val isLocal:Boolean?
|
||||
)
|
|
@ -2,8 +2,9 @@ package com.audiobookshelf.app.data
|
|||
|
||||
import android.net.Uri
|
||||
import android.support.v4.media.MediaMetadataCompat
|
||||
import android.util.Log
|
||||
import com.audiobookshelf.app.R
|
||||
import com.audiobookshelf.app.device.DeviceManager
|
||||
import com.audiobookshelf.app.player.MediaProgressSyncData
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import com.google.android.exoplayer2.MediaItem
|
||||
|
@ -29,17 +30,29 @@ class PlaybackSession(
|
|||
var coverPath:String?,
|
||||
var duration:Double,
|
||||
var playMethod:Int,
|
||||
var startedAt:Long,
|
||||
var updatedAt:Long,
|
||||
var timeListening:Long,
|
||||
var audioTracks:MutableList<AudioTrack>,
|
||||
var currentTime:Double,
|
||||
var libraryItem:LibraryItem?,
|
||||
var localLibraryItem:LocalLibraryItem?,
|
||||
var serverUrl:String?,
|
||||
var token:String?
|
||||
var serverConnectionConfigId:String?,
|
||||
var serverAddress:String?
|
||||
) {
|
||||
|
||||
@get:JsonIgnore
|
||||
val isHLS get() = playMethod == PLAYMETHOD_TRANSCODE
|
||||
@get:JsonIgnore
|
||||
val isLocal get() = playMethod == PLAYMETHOD_LOCAL
|
||||
@get:JsonIgnore
|
||||
val currentTimeMs get() = (currentTime * 1000L).toLong()
|
||||
@get:JsonIgnore
|
||||
val localLibraryItemId get() = localLibraryItem?.id ?: ""
|
||||
@get:JsonIgnore
|
||||
val localMediaProgressId get() = if (episodeId.isNullOrEmpty()) localLibraryItemId else "$localLibraryItemId-$episodeId"
|
||||
@get:JsonIgnore
|
||||
val progress get() = currentTime / getTotalDuration()
|
||||
|
||||
@JsonIgnore
|
||||
fun getCurrentTrackIndex():Int {
|
||||
|
@ -77,13 +90,13 @@ class PlaybackSession(
|
|||
if (localLibraryItem?.coverContentUrl != null) return Uri.parse(localLibraryItem?.coverContentUrl) ?: Uri.parse("android.resource://com.audiobookshelf.app/" + R.drawable.icon)
|
||||
|
||||
if (coverPath == null) return Uri.parse("android.resource://com.audiobookshelf.app/" + R.drawable.icon)
|
||||
return Uri.parse("$serverUrl/api/items/$libraryItemId/cover?token=$token")
|
||||
return Uri.parse("$serverAddress/api/items/$libraryItemId/cover?token=${DeviceManager.token}")
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
fun getContentUri(audioTrack:AudioTrack): Uri {
|
||||
if (isLocal) return Uri.parse(audioTrack.contentUrl) // Local content url
|
||||
return Uri.parse("$serverUrl${audioTrack.contentUrl}?token=$token")
|
||||
return Uri.parse("$serverAddress${audioTrack.contentUrl}?token=${DeviceManager.token}")
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
|
@ -130,6 +143,19 @@ class PlaybackSession(
|
|||
|
||||
@JsonIgnore
|
||||
fun clone():PlaybackSession {
|
||||
return PlaybackSession(id,userId,libraryItemId,episodeId,mediaType,mediaMetadata,chapters,displayTitle,displayAuthor,coverPath,duration,playMethod,audioTracks,currentTime,libraryItem,localLibraryItem,serverUrl,token)
|
||||
return PlaybackSession(id,userId,libraryItemId,episodeId,mediaType,mediaMetadata,chapters,displayTitle,displayAuthor,coverPath,duration,playMethod,startedAt,updatedAt,timeListening,audioTracks,currentTime,libraryItem,localLibraryItem,serverConnectionConfigId,serverAddress)
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
fun syncData(syncData:MediaProgressSyncData) {
|
||||
timeListening += syncData.timeListened
|
||||
updatedAt = System.currentTimeMillis()
|
||||
currentTime = syncData.currentTime
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
fun getNewLocalMediaProgress():LocalMediaProgress {
|
||||
var dateNow = System.currentTimeMillis()
|
||||
return LocalMediaProgress(localMediaProgressId,localLibraryItemId,episodeId,getTotalDuration(),progress,currentTime,false,dateNow,dateNow,null,serverConnectionConfigId,serverAddress,userId,libraryItemId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ object DeviceManager {
|
|||
var serverConnectionConfig: ServerConnectionConfig? = null
|
||||
|
||||
val serverAddress get() = serverConnectionConfig?.address ?: ""
|
||||
val serverUserId get() = serverConnectionConfig?.userId ?: ""
|
||||
val token get() = serverConnectionConfig?.token ?: ""
|
||||
|
||||
init {
|
||||
|
|
|
@ -186,7 +186,7 @@ class FolderScanner(var ctx: Context) {
|
|||
Log.d(tag, "Found local media item named $itemFolderName with ${audioTracks.size} tracks and ${localFiles.size} local files")
|
||||
mediaItemsAdded++
|
||||
|
||||
var localMediaItem = LocalMediaItem(itemId,null, itemFolderName, localFolder.mediaType, localFolder.id, itemFolder.uri.toString(), itemFolder.getSimplePath(ctx), itemFolder.getBasePath(ctx), itemFolder.getAbsolutePath(ctx),audioTracks,localFiles,coverContentUrl,coverAbsolutePath)
|
||||
var localMediaItem = LocalMediaItem(itemId, itemFolderName, localFolder.mediaType, localFolder.id, itemFolder.uri.toString(), itemFolder.getSimplePath(ctx), itemFolder.getBasePath(ctx), itemFolder.getAbsolutePath(ctx),audioTracks,localFiles,coverContentUrl,coverAbsolutePath)
|
||||
var localLibraryItem = localMediaItem.getLocalLibraryItem()
|
||||
localLibraryItems.add(localLibraryItem)
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ class FolderScanner(var ctx: Context) {
|
|||
var filesFound = df.search(false, DocumentFileType.FILE, arrayOf("audio/*", "image/*"))
|
||||
Log.d(tag, "scanDownloadItem ${filesFound.size} files found in ${downloadItem.itemFolderPath}")
|
||||
|
||||
var localLibraryItem = LocalLibraryItem("local_${downloadItem.id}", downloadItem.serverAddress, downloadItem.id, downloadItem.localFolder.id, itemFolderBasePath, itemFolderAbsolutePath, itemFolderUrl, false, downloadItem.mediaType, downloadItem.media, mutableListOf(), null, null, true)
|
||||
var localLibraryItem = LocalLibraryItem("local_${downloadItem.id}", downloadItem.localFolder.id, itemFolderBasePath, itemFolderAbsolutePath, itemFolderUrl, false, downloadItem.mediaType, downloadItem.media, mutableListOf(), null, null, true,downloadItem.serverConnectionConfigId,downloadItem.serverAddress,downloadItem.serverUserId,downloadItem.id)
|
||||
|
||||
var localFiles:MutableList<LocalFile> = mutableListOf()
|
||||
var audioTracks:MutableList<AudioTrack> = mutableListOf()
|
||||
|
|
|
@ -3,11 +3,13 @@ package com.audiobookshelf.app.player
|
|||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import com.audiobookshelf.app.data.MediaProgress
|
||||
import com.audiobookshelf.app.data.LocalMediaProgress
|
||||
import com.audiobookshelf.app.data.PlaybackSession
|
||||
import com.audiobookshelf.app.device.DeviceManager
|
||||
import com.audiobookshelf.app.server.ApiHandler
|
||||
import java.util.*
|
||||
import kotlin.concurrent.schedule
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
data class MediaProgressSyncData(
|
||||
var timeListened:Long, // seconds
|
||||
|
@ -26,7 +28,7 @@ class MediaProgressSyncer(playerNotificationService:PlayerNotificationService, a
|
|||
private var lastSyncTime:Long = 0
|
||||
|
||||
var currentPlaybackSession: PlaybackSession? = null // copy of pb session currently syncing
|
||||
// var currentMediaProgress: MediaProgress? = null
|
||||
var currentLocalMediaProgress: LocalMediaProgress? = null
|
||||
|
||||
val currentDisplayTitle get() = currentPlaybackSession?.displayTitle ?: "Unset"
|
||||
val currentIsLocal get() = currentPlaybackSession?.isLocal == true
|
||||
|
@ -77,8 +79,13 @@ class MediaProgressSyncer(playerNotificationService:PlayerNotificationService, a
|
|||
|
||||
var syncData = MediaProgressSyncData(listeningTimeToAdd,currentPlaybackDuration,currentTime)
|
||||
|
||||
currentPlaybackSession?.syncData(syncData)
|
||||
if (currentIsLocal) {
|
||||
// TODO: Save local progress sync
|
||||
// Save local progress sync
|
||||
currentPlaybackSession?.let {
|
||||
DeviceManager.dbManager.saveLocalPlaybackSession(it)
|
||||
saveLocalProgress(it)
|
||||
}
|
||||
} else {
|
||||
apiHandler.sendProgressSync(currentSessionId,syncData) {
|
||||
Log.d(tag, "Progress sync data sent to server $currentDisplayTitle for time $currentTime")
|
||||
|
@ -86,6 +93,26 @@ class MediaProgressSyncer(playerNotificationService:PlayerNotificationService, a
|
|||
}
|
||||
}
|
||||
|
||||
private fun saveLocalProgress(playbackSession:PlaybackSession) {
|
||||
if (currentLocalMediaProgress == null) {
|
||||
var mediaProgress = DeviceManager.dbManager.getLocalMediaProgress(playbackSession.localMediaProgressId)
|
||||
if (mediaProgress == null) {
|
||||
currentLocalMediaProgress = playbackSession.getNewLocalMediaProgress()
|
||||
} else {
|
||||
currentLocalMediaProgress = mediaProgress
|
||||
}
|
||||
} else {
|
||||
currentLocalMediaProgress?.currentTime = playbackSession.currentTime
|
||||
currentLocalMediaProgress?.lastUpdate = System.currentTimeMillis()
|
||||
currentLocalMediaProgress?.progress = playbackSession.progress
|
||||
}
|
||||
currentLocalMediaProgress?.let {
|
||||
DeviceManager.dbManager.saveLocalMediaProgress(it)
|
||||
playerNotificationService.clientEventEmitter?.onLocalMediaProgressUpdate(it)
|
||||
Log.d(tag, "Saved Local Progress Current Time: ${it.currentTime} | Duration ${it.duration} | Progress ${(it.progress * 100).roundToInt()}%")
|
||||
}
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
listeningTimerTask?.cancel()
|
||||
listeningTimerTask = null
|
||||
|
|
|
@ -23,7 +23,9 @@ import androidx.media.MediaBrowserServiceCompat
|
|||
import androidx.media.utils.MediaConstants
|
||||
import com.audiobookshelf.app.Audiobook
|
||||
import com.audiobookshelf.app.AudiobookManager
|
||||
import com.audiobookshelf.app.data.LocalMediaProgress
|
||||
import com.audiobookshelf.app.data.PlaybackSession
|
||||
import com.audiobookshelf.app.device.DeviceManager
|
||||
import com.audiobookshelf.app.server.ApiHandler
|
||||
import com.getcapacitor.Bridge
|
||||
import com.getcapacitor.JSObject
|
||||
|
@ -57,6 +59,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
|||
fun onPrepare(audiobookId: String, playWhenReady: Boolean)
|
||||
fun onSleepTimerEnded(currentPosition: Long)
|
||||
fun onSleepTimerSet(sleepTimeRemaining: Int)
|
||||
fun onLocalMediaProgressUpdate(localMediaProgress: LocalMediaProgress)
|
||||
}
|
||||
|
||||
private val tag = "PlayerService"
|
||||
|
@ -648,7 +651,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
|||
Log.d(tag, "Playing HLS Item")
|
||||
var dataSourceFactory = DefaultHttpDataSource.Factory()
|
||||
dataSourceFactory.setUserAgent(channelId)
|
||||
dataSourceFactory.setDefaultRequestProperties(hashMapOf("Authorization" to "Bearer ${playbackSession.token}"))
|
||||
dataSourceFactory.setDefaultRequestProperties(hashMapOf("Authorization" to "Bearer ${DeviceManager.token}"))
|
||||
mediaSource = HlsMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItems[0])
|
||||
}
|
||||
mPlayer.setMediaSource(mediaSource)
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.os.Looper
|
|||
import android.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.audiobookshelf.app.MainActivity
|
||||
import com.audiobookshelf.app.data.LocalMediaProgress
|
||||
import com.audiobookshelf.app.data.PlaybackSession
|
||||
import com.audiobookshelf.app.device.DeviceManager
|
||||
import com.audiobookshelf.app.player.CastManager
|
||||
|
@ -64,6 +65,10 @@ class AbsAudioPlayer : Plugin() {
|
|||
override fun onSleepTimerSet(sleepTimeRemaining: Int) {
|
||||
emit("onSleepTimerSet", sleepTimeRemaining)
|
||||
}
|
||||
|
||||
override fun onLocalMediaProgressUpdate(localMediaProgress: LocalMediaProgress) {
|
||||
notifyListeners("onLocalMediaProgressUpdate", JSObject(jacksonObjectMapper().writeValueAsString(localMediaProgress)))
|
||||
}
|
||||
})
|
||||
}
|
||||
mainActivity.pluginCallback = foregroundServiceReady
|
||||
|
@ -86,6 +91,7 @@ class AbsAudioPlayer : Plugin() {
|
|||
}
|
||||
|
||||
var libraryItemId = call.getString("libraryItemId", "").toString()
|
||||
var episodeId = call.getString("episodeId", "").toString()
|
||||
var playWhenReady = call.getBoolean("playWhenReady") == true
|
||||
|
||||
if (libraryItemId.isEmpty()) {
|
||||
|
@ -97,13 +103,13 @@ class AbsAudioPlayer : Plugin() {
|
|||
DeviceManager.dbManager.getLocalLibraryItem(libraryItemId)?.let {
|
||||
Handler(Looper.getMainLooper()).post() {
|
||||
Log.d(tag, "Preparing Local Media item ${jacksonObjectMapper().writeValueAsString(it)}")
|
||||
var playbackSession = it.getPlaybackSession()
|
||||
var playbackSession = it.getPlaybackSession(episodeId)
|
||||
playerNotificationService.preparePlayer(playbackSession, playWhenReady)
|
||||
}
|
||||
return call.resolve(JSObject())
|
||||
}
|
||||
} else { // Play library item from server
|
||||
apiHandler.playLibraryItem(libraryItemId, false) {
|
||||
apiHandler.playLibraryItem(libraryItemId, episodeId, false) {
|
||||
|
||||
Handler(Looper.getMainLooper()).post() {
|
||||
Log.d(tag, "Preparing Player TEST ${jacksonObjectMapper().writeValueAsString(it)}")
|
||||
|
|
|
@ -17,6 +17,10 @@ import org.json.JSONObject
|
|||
class AbsDatabase : Plugin() {
|
||||
val tag = "AbsDatabase"
|
||||
|
||||
data class LocalMediaProgressPayload(val value:List<LocalMediaProgress>)
|
||||
data class LocalLibraryItemsPayload(val value:List<LocalLibraryItem>)
|
||||
data class LocalFoldersPayload(val value:List<LocalFolder>)
|
||||
|
||||
@PluginMethod
|
||||
fun getDeviceData(call:PluginCall) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
|
@ -29,10 +33,7 @@ class AbsDatabase : Plugin() {
|
|||
fun getLocalFolders(call:PluginCall) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
var folders = DeviceManager.dbManager.getAllLocalFolders()
|
||||
var folderObjArray = jacksonObjectMapper().writeValueAsString(folders)
|
||||
var jsobj = JSObject()
|
||||
jsobj.put("folders", folderObjArray)
|
||||
call.resolve(jsobj)
|
||||
call.resolve(JSObject(jacksonObjectMapper().writeValueAsString(LocalFoldersPayload(folders))))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,9 +81,7 @@ class AbsDatabase : Plugin() {
|
|||
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
var localLibraryItems = DeviceManager.dbManager.getLocalLibraryItems(mediaType)
|
||||
var jsobj = JSObject()
|
||||
jsobj.put("localLibraryItems", jacksonObjectMapper().writeValueAsString(localLibraryItems))
|
||||
call.resolve(jsobj)
|
||||
call.resolve(JSObject(jacksonObjectMapper().writeValueAsString(LocalLibraryItemsPayload(localLibraryItems))))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,11 +89,8 @@ class AbsDatabase : Plugin() {
|
|||
fun getLocalLibraryItemsInFolder(call:PluginCall) {
|
||||
var folderId = call.getString("folderId", "").toString()
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
var localMediaItems = DeviceManager.dbManager.getLocalLibraryItemsInFolder(folderId)
|
||||
var mediaItemsArray = jacksonObjectMapper().writeValueAsString(localMediaItems)
|
||||
var jsobj = JSObject()
|
||||
jsobj.put("localLibraryItems", mediaItemsArray)
|
||||
call.resolve(jsobj)
|
||||
var localLibraryItems = DeviceManager.dbManager.getLocalLibraryItemsInFolder(folderId)
|
||||
call.resolve(JSObject(jacksonObjectMapper().writeValueAsString(LocalLibraryItemsPayload(localLibraryItems))))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,6 +99,7 @@ class AbsDatabase : Plugin() {
|
|||
var serverConnectionConfigId = call.getString("id", "").toString()
|
||||
var serverConnectionConfig = DeviceManager.deviceData.serverConnectionConfigs.find { it.id == serverConnectionConfigId }
|
||||
|
||||
var userId = call.getString("userId", "").toString()
|
||||
var username = call.getString("username", "").toString()
|
||||
var token = call.getString("token", "").toString()
|
||||
|
||||
|
@ -113,7 +110,7 @@ class AbsDatabase : Plugin() {
|
|||
// Create new server connection config
|
||||
var sscId = DeviceManager.getBase64Id("$serverAddress@$username")
|
||||
var sscIndex = DeviceManager.deviceData.serverConnectionConfigs.size
|
||||
serverConnectionConfig = ServerConnectionConfig(sscId, sscIndex, "$serverAddress ($username)", serverAddress, username, token)
|
||||
serverConnectionConfig = ServerConnectionConfig(sscId, sscIndex, "$serverAddress ($username)", serverAddress, userId, username, token)
|
||||
|
||||
// Add and save
|
||||
DeviceManager.deviceData.serverConnectionConfigs.add(serverConnectionConfig!!)
|
||||
|
@ -122,6 +119,7 @@ class AbsDatabase : Plugin() {
|
|||
} else {
|
||||
var shouldSave = false
|
||||
if (serverConnectionConfig?.username != username || serverConnectionConfig?.token != token) {
|
||||
serverConnectionConfig?.userId = userId
|
||||
serverConnectionConfig?.username = username
|
||||
serverConnectionConfig?.name = "${serverConnectionConfig?.address} (${serverConnectionConfig?.username})"
|
||||
serverConnectionConfig?.token = token
|
||||
|
@ -168,6 +166,22 @@ class AbsDatabase : Plugin() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@PluginMethod
|
||||
fun getAllLocalMediaProgress(call:PluginCall) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
var localMediaProgress = DeviceManager.dbManager.getAllLocalMediaProgress()
|
||||
call.resolve(JSObject(jacksonObjectMapper().writeValueAsString(LocalMediaProgressPayload(localMediaProgress))))
|
||||
}
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun removeLocalMediaProgress(call:PluginCall) {
|
||||
var localMediaProgressId = call.getString("localMediaProgressId", "").toString()
|
||||
DeviceManager.dbManager.removeLocalMediaProgress(localMediaProgressId)
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
//
|
||||
// Generic Webview calls to db
|
||||
//
|
||||
|
|
|
@ -62,7 +62,9 @@ class AbsDownloader : Plugin() {
|
|||
|
||||
data class DownloadItem(
|
||||
val id: String,
|
||||
val serverConnectionConfigId:String,
|
||||
val serverAddress:String,
|
||||
val serverUserId:String,
|
||||
val mediaType: String,
|
||||
val itemFolderPath:String,
|
||||
val localFolder: LocalFolder,
|
||||
|
@ -143,7 +145,7 @@ class AbsDownloader : Plugin() {
|
|||
var tracks = libraryItem.media.getAudioTracks()
|
||||
Log.d(tag, "Starting library item download with ${tracks.size} tracks")
|
||||
var itemFolderPath = localFolder.absolutePath + "/" + bookTitle
|
||||
var downloadItem = DownloadItem(libraryItem.id, DeviceManager.serverAddress, libraryItem.mediaType, itemFolderPath, localFolder, bookTitle, libraryItem.media, mutableListOf())
|
||||
var downloadItem = DownloadItem(libraryItem.id, DeviceManager.serverConnectionConfig?.id ?: "", DeviceManager.serverAddress, DeviceManager.serverUserId, libraryItem.mediaType, itemFolderPath, localFolder, bookTitle, libraryItem.media, mutableListOf())
|
||||
|
||||
// Create download item part for each audio track
|
||||
tracks.forEach { audioTrack ->
|
||||
|
|
|
@ -104,18 +104,20 @@ class ApiHandler {
|
|||
}
|
||||
}
|
||||
|
||||
fun playLibraryItem(libraryItemId:String, forceTranscode:Boolean, cb: (PlaybackSession) -> Unit) {
|
||||
fun playLibraryItem(libraryItemId:String, episodeId:String, forceTranscode:Boolean, cb: (PlaybackSession) -> Unit) {
|
||||
val mapper = jacksonObjectMapper()
|
||||
var payload = JSObject()
|
||||
payload.put("mediaPlayer", "exo-player")
|
||||
|
||||
// Only if direct play fails do we force transcode
|
||||
// TODO: Fallback to transcode
|
||||
if (!forceTranscode) payload.put("forceDirectPlay", true)
|
||||
else payload.put("forceTranscode", true)
|
||||
|
||||
postRequest("/api/items/$libraryItemId/play", payload) {
|
||||
it.put("serverUrl", DeviceManager.serverAddress)
|
||||
it.put("token", DeviceManager.token)
|
||||
val endpoint = if (episodeId.isNullOrEmpty()) "/api/items/$libraryItemId/play" else "/api/items/$libraryItemId/play/$episodeId"
|
||||
postRequest(endpoint, payload) {
|
||||
it.put("serverConnectionConfigId", DeviceManager.serverConnectionConfig?.id)
|
||||
it.put("serverAddress", DeviceManager.serverAddress)
|
||||
val playbackSession = mapper.readValue<PlaybackSession>(it.toString())
|
||||
cb(playbackSession)
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ export default {
|
|||
isSleepTimerRunning: false,
|
||||
sleepTimerEndTime: 0,
|
||||
sleepTimeRemaining: 0,
|
||||
onLocalMediaProgressUpdateListener: null,
|
||||
onSleepTimerEndedListener: null,
|
||||
onSleepTimerSetListener: null,
|
||||
sleepInterval: null,
|
||||
|
@ -174,9 +175,14 @@ export default {
|
|||
.catch((error) => {
|
||||
console.error('Failed', error)
|
||||
})
|
||||
},
|
||||
onLocalMediaProgressUpdate(localMediaProgress) {
|
||||
console.log('Got local media progress update', localMediaProgress.progress, JSON.stringify(localMediaProgress))
|
||||
this.$store.commit('globals/updateLocalMediaProgress', localMediaProgress)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.onLocalMediaProgressUpdateListener = AbsAudioPlayer.addListener('onLocalMediaProgressUpdate', this.onLocalMediaProgressUpdate)
|
||||
this.onSleepTimerEndedListener = AbsAudioPlayer.addListener('onSleepTimerEnded', this.onSleepTimerEnded)
|
||||
this.onSleepTimerSetListener = AbsAudioPlayer.addListener('onSleepTimerSet', this.onSleepTimerSet)
|
||||
|
||||
|
@ -189,6 +195,7 @@ export default {
|
|||
this.$store.commit('user/addSettingsListener', { id: 'streamContainer', meth: this.settingsUpdated })
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.onLocalMediaProgressUpdateListener) this.onLocalMediaProgressUpdateListener.remove()
|
||||
if (this.onSleepTimerEndedListener) this.onSleepTimerEndedListener.remove()
|
||||
if (this.onSleepTimerSetListener) this.onSleepTimerSetListener.remove()
|
||||
|
||||
|
|
|
@ -207,6 +207,7 @@ export default {
|
|||
return null
|
||||
},
|
||||
userProgress() {
|
||||
if (this.isLocal) return this.store.getters['globals/getLocalMediaProgressById'](this.libraryItemId)
|
||||
return this.store.getters['user/getUserMediaProgress'](this.libraryItemId)
|
||||
},
|
||||
userProgressPercent() {
|
||||
|
|
|
@ -123,6 +123,7 @@ export default {
|
|||
this.error = null
|
||||
this.serverConfig = {
|
||||
address: null,
|
||||
userId: null,
|
||||
username: null
|
||||
}
|
||||
},
|
||||
|
@ -160,6 +161,7 @@ export default {
|
|||
this.deviceData.serverConnectionConfigs = this.deviceData.serverConnectionConfigs.filter((scc) => scc.id != this.serverConfig.id)
|
||||
this.serverConfig = {
|
||||
address: null,
|
||||
userId: null,
|
||||
username: null
|
||||
}
|
||||
this.password = null
|
||||
|
@ -266,6 +268,7 @@ export default {
|
|||
this.$store.commit('libraries/setCurrentLibrary', userDefaultLibraryId)
|
||||
}
|
||||
|
||||
this.serverConfig.userId = user.id
|
||||
this.serverConfig.token = user.token
|
||||
|
||||
var serverConnectionConfig = await this.$db.setServerConnectionConfig(this.serverConfig)
|
||||
|
|
|
@ -144,15 +144,6 @@ export default {
|
|||
// }
|
||||
// })
|
||||
// },
|
||||
async initMediaStore() {
|
||||
// Request and setup listeners for media files on native
|
||||
// AbsDownloader.addListener('onItemDownloadUpdate', (data) => {
|
||||
// this.onItemDownloadUpdate(data)
|
||||
// })
|
||||
// AbsDownloader.addListener('onItemDownloadComplete', (data) => {
|
||||
// this.onItemDownloadComplete(data)
|
||||
// })
|
||||
},
|
||||
async loadSavedSettings() {
|
||||
var userSavedServerSettings = await this.$localStore.getServerSettings()
|
||||
if (userSavedServerSettings) {
|
||||
|
@ -266,9 +257,9 @@ export default {
|
|||
await this.attemptConnection()
|
||||
}
|
||||
|
||||
this.$store.dispatch('globals/loadLocalMediaProgress')
|
||||
this.checkForUpdate()
|
||||
this.loadSavedSettings()
|
||||
this.initMediaStore()
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
|
|
@ -164,6 +164,7 @@ export default {
|
|||
return this.$store.getters['user/getToken']
|
||||
},
|
||||
userItemProgress() {
|
||||
if (this.isLocal) return this.$store.getters['globals/getLocalMediaProgressById'](this.libraryItemId)
|
||||
return this.$store.getters['user/getUserMediaProgress'](this.libraryItemId)
|
||||
},
|
||||
userIsFinished() {
|
||||
|
@ -238,18 +239,23 @@ export default {
|
|||
})
|
||||
if (value) {
|
||||
this.resettingProgress = true
|
||||
this.$axios
|
||||
if (this.isLocal) {
|
||||
await this.$db.removeLocalMediaProgress(this.libraryItemId)
|
||||
this.$store.commit('globals/removeLocalMediaProgress', this.libraryItemId)
|
||||
} else {
|
||||
await this.$axios
|
||||
.$delete(`/api/me/progress/${this.libraryItemId}`)
|
||||
.then(() => {
|
||||
console.log('Progress reset complete')
|
||||
this.$toast.success(`Your progress was reset`)
|
||||
this.resettingProgress = false
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Progress reset failed', error)
|
||||
this.resettingProgress = false
|
||||
})
|
||||
}
|
||||
|
||||
this.resettingProgress = false
|
||||
}
|
||||
},
|
||||
itemUpdated(libraryItem) {
|
||||
if (libraryItem.id === this.libraryItemId) {
|
||||
|
|
|
@ -13,7 +13,7 @@ class AbsDatabaseWeb extends WebPlugin {
|
|||
const deviceData = {
|
||||
serverConnectionConfigs: [],
|
||||
lastServerConnectionConfigId: null,
|
||||
localLibraryItemIdPlaying: null
|
||||
currentLocalPlaybackSession: null
|
||||
}
|
||||
return deviceData
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ class AbsDatabaseWeb extends WebPlugin {
|
|||
deviceData.lastServerConnectionConfigId = ssc.id
|
||||
ssc.name = `${ssc.address} (${serverConnectionConfig.username})`
|
||||
ssc.token = serverConnectionConfig.token
|
||||
ssc.userId = serverConnectionConfig.userId
|
||||
ssc.username = serverConnectionConfig.username
|
||||
localStorage.setItem('device', JSON.stringify(deviceData))
|
||||
} else {
|
||||
|
@ -33,6 +34,7 @@ class AbsDatabaseWeb extends WebPlugin {
|
|||
id: encodeURIComponent(Buffer.from(`${serverConnectionConfig.address}@${serverConnectionConfig.username}`).toString('base64')),
|
||||
index: deviceData.serverConnectionConfigs.length,
|
||||
name: `${serverConnectionConfig.address} (${serverConnectionConfig.username})`,
|
||||
userId: serverConnectionConfig.userId,
|
||||
username: serverConnectionConfig.username,
|
||||
address: serverConnectionConfig.address,
|
||||
token: serverConnectionConfig.token
|
||||
|
@ -62,7 +64,7 @@ class AbsDatabaseWeb extends WebPlugin {
|
|||
//
|
||||
async getLocalFolders() {
|
||||
return {
|
||||
folders: [
|
||||
value: [
|
||||
{
|
||||
id: 'test1',
|
||||
name: 'Audiobooks',
|
||||
|
@ -76,11 +78,11 @@ class AbsDatabaseWeb extends WebPlugin {
|
|||
}
|
||||
}
|
||||
async getLocalFolder({ folderId }) {
|
||||
return this.getLocalFolders().then((data) => data.folders[0])
|
||||
return this.getLocalFolders().then((data) => data.value[0])
|
||||
}
|
||||
async getLocalLibraryItems(payload) {
|
||||
return {
|
||||
localLibraryItems: [{
|
||||
value: [{
|
||||
id: 'local_test',
|
||||
libraryItemId: 'test34',
|
||||
folderId: 'test1',
|
||||
|
@ -133,10 +135,36 @@ class AbsDatabaseWeb extends WebPlugin {
|
|||
return this.getLocalLibraryItems()
|
||||
}
|
||||
async getLocalLibraryItem({ id }) {
|
||||
return this.getLocalLibraryItems().then((data) => data.localLibraryItems[0])
|
||||
return this.getLocalLibraryItems().then((data) => data.value[0])
|
||||
}
|
||||
async getLocalLibraryItemByLLId({ libraryItemId }) {
|
||||
return this.getLocalLibraryItems().then((data) => data.localLibraryItems.find(lli => lli.libraryItemId == libraryItemId))
|
||||
return this.getLocalLibraryItems().then((data) => data.value.find(lli => lli.libraryItemId == libraryItemId))
|
||||
}
|
||||
async getAllLocalMediaProgress() {
|
||||
return {
|
||||
value: [
|
||||
{
|
||||
id: 'local_test',
|
||||
localLibraryItemId: 'local_test',
|
||||
episodeId: null,
|
||||
duration: 100,
|
||||
progress: 0.5,
|
||||
currentTime: 50,
|
||||
isFinished: false,
|
||||
lastUpdate: 394089090,
|
||||
startedAt: 239048209,
|
||||
finishedAt: null,
|
||||
// For local lib items from server to support server sync
|
||||
// var serverConnectionConfigId:String?,
|
||||
// var serverAddress:String?,
|
||||
// var serverUserId:String?,
|
||||
// var libraryItemId:String?
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
async removeLocalMediaProgress({ localMediaProgressId }) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,13 +52,7 @@ class DbService {
|
|||
}
|
||||
|
||||
getLocalFolders() {
|
||||
return AbsDatabase.getLocalFolders().then((data) => {
|
||||
console.log('Loaded local folders', JSON.stringify(data))
|
||||
if (data.folders && typeof data.folders == 'string') {
|
||||
return JSON.parse(data.folders)
|
||||
}
|
||||
return data.folders
|
||||
}).catch((error) => {
|
||||
return AbsDatabase.getLocalFolders().then((data) => data.value).catch((error) => {
|
||||
console.error('Failed to load', error)
|
||||
return null
|
||||
})
|
||||
|
@ -72,23 +66,11 @@ class DbService {
|
|||
}
|
||||
|
||||
getLocalLibraryItemsInFolder(folderId) {
|
||||
return AbsDatabase.getLocalLibraryItemsInFolder({ folderId }).then((data) => {
|
||||
console.log('Loaded local library items in folder', JSON.stringify(data))
|
||||
if (data.localLibraryItems && typeof data.localLibraryItems == 'string') {
|
||||
return JSON.parse(data.localLibraryItems)
|
||||
}
|
||||
return data.localLibraryItems
|
||||
})
|
||||
return AbsDatabase.getLocalLibraryItemsInFolder({ folderId }).then((data) => data.value)
|
||||
}
|
||||
|
||||
getLocalLibraryItems(mediaType = null) {
|
||||
return AbsDatabase.getLocalLibraryItems({ mediaType }).then((data) => {
|
||||
console.log('Loaded all local media items', JSON.stringify(data))
|
||||
if (data.localLibraryItems && typeof data.localLibraryItems == 'string') {
|
||||
return JSON.parse(data.localLibraryItems)
|
||||
}
|
||||
return data.localLibraryItems
|
||||
})
|
||||
return AbsDatabase.getLocalLibraryItems({ mediaType }).then((data) => data.value)
|
||||
}
|
||||
|
||||
getLocalLibraryItem(id) {
|
||||
|
@ -98,6 +80,14 @@ class DbService {
|
|||
getLocalLibraryItemByLLId(libraryItemId) {
|
||||
return AbsDatabase.getLocalLibraryItemByLLId({ libraryItemId })
|
||||
}
|
||||
|
||||
getAllLocalMediaProgress() {
|
||||
return AbsDatabase.getAllLocalMediaProgress().then((data) => data.value)
|
||||
}
|
||||
|
||||
removeLocalMediaProgress(localMediaProgressId) {
|
||||
return AbsDatabase.removeLocalMediaProgress({ localMediaProgressId })
|
||||
}
|
||||
}
|
||||
|
||||
export default ({ app, store }, inject) => {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
export const state = () => ({
|
||||
itemDownloads: [],
|
||||
bookshelfListView: false,
|
||||
series: null
|
||||
series: null,
|
||||
localMediaProgress: []
|
||||
})
|
||||
|
||||
export const getters = {
|
||||
|
@ -25,11 +26,21 @@ export const getters = {
|
|||
|
||||
var url = new URL(`/api/items/${libraryItem.id}/cover`, rootGetters['user/getServerAddress'])
|
||||
return `${url}?token=${userToken}&ts=${lastUpdate}`
|
||||
},
|
||||
getLocalMediaProgressById: (state) => (localLibraryItemId, episodeId = null) => {
|
||||
return state.localMediaProgress.find(lmp => {
|
||||
if (episodeId != null && lmp.episodeId != episodeId) return false
|
||||
return lmp.localLibraryItemId == localLibraryItemId
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
|
||||
async loadLocalMediaProgress({ state, commit }) {
|
||||
var mediaProgress = await this.$db.getAllLocalMediaProgress()
|
||||
console.log('Got all local media progress', JSON.stringify(mediaProgress))
|
||||
commit('setLocalMediaProgress', mediaProgress)
|
||||
}
|
||||
}
|
||||
|
||||
export const mutations = {
|
||||
|
@ -49,5 +60,22 @@ export const mutations = {
|
|||
},
|
||||
setSeries(state, val) {
|
||||
state.series = val
|
||||
},
|
||||
setLocalMediaProgress(state, val) {
|
||||
state.localMediaProgress = val
|
||||
},
|
||||
updateLocalMediaProgress(state, prog) {
|
||||
if (!prog || !prog.id) {
|
||||
return
|
||||
}
|
||||
var index = state.localMediaProgress.findIndex(lmp => lmp.id == prog.id)
|
||||
if (index >= 0) {
|
||||
state.localMediaProgress.splice(index, 1, prog)
|
||||
} else {
|
||||
state.localMediaProgress.push(prog)
|
||||
}
|
||||
},
|
||||
removeLocalMediaProgress(state, id) {
|
||||
state.localMediaProgress = state.localMediaProgress.filter(lmp => lmp.id != id)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue