Update:Syncing playback time when media item is open in player

This commit is contained in:
advplyr 2023-06-19 12:37:44 -05:00
parent b4bf10d409
commit ff4f8324e7
25 changed files with 149 additions and 177 deletions

View file

@ -305,9 +305,9 @@ data class PodcastEpisode(
.setSubtitle(libraryItemDescription.title)
.setExtras(extras)
libraryItemDescription.iconBitmap?.let {
mediaDescriptionBuilder.setIconBitmap(it)
}
// libraryItemDescription.iconBitmap?.let {
// mediaDescriptionBuilder.setIconBitmap(it)
// }
return mediaDescriptionBuilder.build()
}

View file

@ -110,17 +110,17 @@ class LocalLibraryItem(
override fun getMediaDescription(progress:MediaProgressWrapper?, ctx:Context?): MediaDescriptionCompat {
val coverUri = getCoverUri()
var bitmap:Bitmap? = null
if (coverContentUrl != null) {
ctx?.let {
bitmap = if (Build.VERSION.SDK_INT < 28) {
MediaStore.Images.Media.getBitmap(it.contentResolver, coverUri)
} else {
val source: ImageDecoder.Source = ImageDecoder.createSource(it.contentResolver, coverUri)
ImageDecoder.decodeBitmap(source)
}
}
}
// var bitmap:Bitmap? = null
// if (coverContentUrl != null) {
// ctx?.let {
// bitmap = if (Build.VERSION.SDK_INT < 28) {
// MediaStore.Images.Media.getBitmap(it.contentResolver, coverUri)
// } else {
// val source: ImageDecoder.Source = ImageDecoder.createSource(it.contentResolver, coverUri)
// ImageDecoder.decodeBitmap(source)
// }
// }
// }
val extras = Bundle()
extras.putLong(
@ -156,9 +156,9 @@ class LocalLibraryItem(
.setSubtitle(authorName)
.setExtras(extras)
bitmap?.let {
mediaDescriptionBuilder.setIconBitmap(bitmap)
}
// bitmap?.let {
// mediaDescriptionBuilder.setIconBitmap(bitmap)
// }
return mediaDescriptionBuilder.build()
}

View file

@ -1,10 +1,7 @@
package com.audiobookshelf.app.data
import android.content.Context
import android.graphics.ImageDecoder
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.support.v4.media.MediaMetadataCompat
import com.audiobookshelf.app.BuildConfig
import com.audiobookshelf.app.R
@ -168,16 +165,16 @@ class PlaybackSession(
.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, getCoverUri().toString())
// Local covers get bitmap
if (localLibraryItem?.coverContentUrl != null) {
val bitmap = if (Build.VERSION.SDK_INT < 28) {
MediaStore.Images.Media.getBitmap(ctx.contentResolver, getCoverUri())
} else {
val source: ImageDecoder.Source = ImageDecoder.createSource(ctx.contentResolver, getCoverUri())
ImageDecoder.decodeBitmap(source)
}
metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, bitmap)
}
// if (localLibraryItem?.coverContentUrl != null) {
// val bitmap = if (Build.VERSION.SDK_INT < 28) {
// MediaStore.Images.Media.getBitmap(ctx.contentResolver, getCoverUri())
// } else {
// val source: ImageDecoder.Source = ImageDecoder.createSource(ctx.contentResolver, getCoverUri())
// ImageDecoder.decodeBitmap(source)
// }
// metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
// metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, bitmap)
// }
return metadataBuilder.build()
}

View file

@ -215,7 +215,6 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
val listeningTimeToAdd = diffSinceLastSync / 1000L
val syncData = MediaProgressSyncData(listeningTimeToAdd,currentPlaybackDuration,currentTime)
currentPlaybackSession?.syncData(syncData)
if (currentPlaybackSession?.progress?.isNaN() == true) {
@ -243,11 +242,6 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
// Send sync to server also if connected to this server and local item belongs to this server
if (hasNetworkConnection && shouldSyncServer && !it.libraryItemId.isNullOrEmpty() && it.serverConnectionConfigId != null && DeviceManager.serverConnectionConfig?.id == it.serverConnectionConfigId) {
apiHandler.sendLocalProgressSync(it) { syncSuccess, errorMsg ->
Log.d(
tag,
"Local progress sync data sent to server $currentDisplayTitle for time $currentTime"
)
if (syncSuccess) {
failedSyncs = 0
playerNotificationService.alertSyncSuccess()

View file

@ -4,9 +4,7 @@ import android.annotation.SuppressLint
import android.app.*
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.ImageDecoder
import android.hardware.Sensor
import android.hardware.SensorManager
import android.net.ConnectivityManager
@ -14,7 +12,6 @@ import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.*
import android.provider.MediaStore
import android.provider.Settings
import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaDescriptionCompat
@ -292,18 +289,18 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
return MediaDescriptionCompat.Builder().build()
}
val coverUri = currentPlaybackSession!!.getCoverUri()
var coverUri = currentPlaybackSession!!.getCoverUri()
var bitmap:Bitmap? = null
// var bitmap:Bitmap? = null
// Local covers get bitmap
if (currentPlaybackSession!!.localLibraryItem?.coverContentUrl != null) {
bitmap = if (Build.VERSION.SDK_INT < 28) {
MediaStore.Images.Media.getBitmap(ctx.contentResolver, coverUri)
} else {
val source: ImageDecoder.Source = ImageDecoder.createSource(ctx.contentResolver, coverUri)
ImageDecoder.decodeBitmap(source)
}
}
// if (currentPlaybackSession!!.localLibraryItem?.coverContentUrl != null) {
// bitmap = if (Build.VERSION.SDK_INT < 28) {
// MediaStore.Images.Media.getBitmap(ctx.contentResolver, coverUri)
// } else {
// val source: ImageDecoder.Source = ImageDecoder.createSource(ctx.contentResolver, coverUri)
// ImageDecoder.decodeBitmap(source)
// }
// }
// Fix for local images crashing on Android 11 for specific devices
// https://stackoverflow.com/questions/64186578/android-11-mediastyle-notification-crash/64232958#64232958
@ -325,9 +322,9 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
.setTitle(currentPlaybackSession!!.displayTitle)
.setIconUri(coverUri)
bitmap?.let {
mediaDescriptionBuilder.setIconBitmap(it)
}
// bitmap?.let {
// mediaDescriptionBuilder.setIconBitmap(it)
// }
return mediaDescriptionBuilder.build()
}

View file

@ -79,7 +79,7 @@ export default {
},
methods: {
castClick() {
if (this.$store.state.playerIsLocal) {
if (this.$store.getters['getIsCurrentSessionLocal']) {
this.$eventBus.$emit('cast-local-item')
return
}

View file

@ -574,8 +574,8 @@ export default {
AbsAudioPlayer.seek({ value: Math.floor(time) })
if (this.$refs.playedTrack) {
var perc = time / this.totalDuration
var ptWidth = Math.round(perc * this.trackWidth)
const perc = time / this.totalDuration
const ptWidth = Math.round(perc * this.trackWidth)
this.$refs.playedTrack.style.width = ptWidth + 'px'
this.$refs.playedTrack.classList.remove('bg-gray-200')
@ -721,7 +721,7 @@ export default {
AbsAudioPlayer.closePlayback()
},
endPlayback() {
this.$store.commit('setPlayerItem', null)
this.$store.commit('setPlaybackSession', null)
this.showFullscreen = false
this.isEnded = false
this.isLoading = false
@ -767,7 +767,7 @@ export default {
this.isEnded = false
this.isLoading = true
this.syncStatus = 0
this.$store.commit('setPlayerItem', this.playbackSession)
this.$store.commit('setPlaybackSession', this.playbackSession)
// Set track width
this.$nextTick(() => {

View file

@ -110,7 +110,7 @@ export default {
},
streamProgress(data) {
if (!data.numSegments) return
var chunks = data.chunks
const chunks = data.chunks
if (this.$refs.audioPlayer) {
this.$refs.audioPlayer.setChunksReady(chunks, data.numSegments)
}
@ -265,8 +265,7 @@ export default {
this.$store.commit('globals/updateLocalMediaProgress', localMediaProgress)
},
onMediaPlayerChanged(data) {
var mediaPlayer = data.value
this.$store.commit('setMediaPlayer', mediaPlayer)
this.$store.commit('setMediaPlayer', data.value)
},
onReady() {
// The UI is reporting elsewhere we are ready
@ -283,6 +282,9 @@ export default {
this.$store.commit('setIsFirstAudioLoad', false) // Only run this once on app launch
AbsAudioPlayer.onReady()
}
},
playbackTimeUpdate(currentTime) {
this.$refs.audioPlayer?.seek(currentTime)
}
},
mounted() {
@ -300,6 +302,7 @@ export default {
this.$eventBus.$on('close-stream', this.closeStreamOnly)
this.$eventBus.$on('cast-local-item', this.castLocalItem)
this.$eventBus.$on('user-settings', this.settingsUpdated)
this.$eventBus.$on('playback-time-update', this.playbackTimeUpdate)
},
beforeDestroy() {
if (this.onLocalMediaProgressUpdateListener) this.onLocalMediaProgressUpdateListener.remove()
@ -313,6 +316,7 @@ export default {
this.$eventBus.$off('close-stream', this.closeStreamOnly)
this.$eventBus.$off('cast-local-item', this.castLocalItem)
this.$eventBus.$off('user-settings', this.settingsUpdated)
this.$eventBus.$off('playback-time-update', this.playbackTimeUpdate)
}
}
</script>

View file

@ -213,7 +213,7 @@ export default {
return this.mediaMetadata.series
},
seriesSequence() {
return this.series ? this.series.sequence : null
return this.series?.sequence || null
},
recentEpisode() {
// Only added to item when getting currently listening podcasts
@ -232,14 +232,14 @@ export default {
},
booksInSeries() {
// Only added to item object when collapseSeries is enabled
return this.collapsedSeries ? this.collapsedSeries.numBooks : 0
return this.collapsedSeries?.numBooks || 0
},
seriesSequenceList() {
return this.collapsedSeries ? this.collapsedSeries.seriesSequenceList : null
return this.collapsedSeries?.seriesSequenceList || null
},
libraryItemIdsInSeries() {
// Only added to item object when collapseSeries is enabled
return this.collapsedSeries ? this.collapsedSeries.libraryItemIds || [] : []
return this.collapsedSeries?.libraryItemIds || []
},
displayTitle() {
if (this.recentEpisode) return this.recentEpisode.title
@ -291,20 +291,18 @@ export default {
showError() {
return this.numMissingParts || this.isMissing || this.isInvalid
},
playerIsLocal() {
return !!this.$store.state.playerIsLocal
},
localLibraryItemId() {
if (this.isLocal) return this.libraryItemId
return this.localLibraryItem ? this.localLibraryItem.id : null
return this.localLibraryItem?.id || null
},
localEpisode() {
if (!this.recentEpisode || !this.localLibraryItem) return null
// Current recentEpisode is only implemented server side so this will always be the serverEpisodeId
return this.localLibraryItem.media.episodes.find((ep) => ep.serverEpisodeId === this.recentEpisode.id)
},
isStreaming() {
if (this.isPodcast) {
if (this.playerIsLocal) {
// Check is streaming local version of this episode
return false // episode cards not implemented for local yet
}
return this.$store.getters['getIsEpisodeStreaming'](this.libraryItemId, this.recentEpisode.id)
return this.$store.getters['getIsMediaStreaming'](this.libraryItemId, this.recentEpisode.id)
} else {
return false // not yet necessary for books
}
@ -380,8 +378,7 @@ export default {
showHasLocalDownload() {
if (this.localLibraryItem || this.isLocal) {
if (this.recentEpisode && !this.isLocal) {
const localEpisode = this.localLibraryItem.media.episodes.find((ep) => ep.serverEpisodeId === this.recentEpisode.id)
return !!localEpisode
return !!this.localEpisode
} else {
return true
}
@ -436,18 +433,15 @@ export default {
return
}
if (this.localLibraryItem) {
const localEpisode = this.localLibraryItem.media.episodes.find((ep) => ep.serverEpisodeId === this.recentEpisode.id)
if (localEpisode) {
// Play episode locally
eventBus.$emit('play-item', {
libraryItemId: this.localLibraryItemId,
episodeId: localEpisode.id,
serverLibraryItemId: this.libraryItemId,
serverEpisodeId: this.recentEpisode.id
})
return
}
if (this.localEpisode) {
// Play episode locally
eventBus.$emit('play-item', {
libraryItemId: this.localLibraryItemId,
episodeId: this.localEpisode.id,
serverLibraryItemId: this.libraryItemId,
serverEpisodeId: this.recentEpisode.id
})
return
}
eventBus.$emit('play-item', { libraryItemId: this.libraryItemId, episodeId: this.recentEpisode.id })

View file

@ -23,7 +23,7 @@
</div>
</div>
<div class="fixed left-0 h-8 w-full bg-primary px-4 flex items-center text-white/80" :style="{ bottom: playerLibraryItemId ? '120px' : '0px' }">
<div class="fixed left-0 h-8 w-full bg-primary px-4 flex items-center text-white/80" :style="{ bottom: isPlayerOpen ? '120px' : '0px' }">
<div class="flex-grow" />
<p class="text-xs">{{ page }} / {{ numPages }}</p>
</div>
@ -148,8 +148,8 @@ export default {
}
})
},
playerLibraryItemId() {
return this.$store.state.playerLibraryItemId
isPlayerOpen() {
return this.$store.getters['getIsPlayerOpen']
}
},
methods: {

View file

@ -2,7 +2,7 @@
<div id="epub-frame" class="w-full">
<div id="viewer" class="h-full w-full"></div>
<div class="fixed left-0 h-8 w-full px-4 flex items-center" :class="isLightTheme ? 'bg-white text-black' : 'bg-primary text-white/80'" :style="{ bottom: playerLibraryItemId ? '120px' : '0px' }">
<div class="fixed left-0 h-8 w-full px-4 flex items-center" :class="isLightTheme ? 'bg-white text-black' : 'bg-primary text-white/80'" :style="{ bottom: isPlayerOpen ? '120px' : '0px' }">
<div class="flex-grow" />
<p class="text-xs">{{ progress }}%</p>
</div>
@ -37,7 +37,7 @@ export default {
}
},
watch: {
playerLibraryItemId() {
isPlayerOpen() {
this.updateHeight()
}
},
@ -65,11 +65,11 @@ export default {
}
return null
},
playerLibraryItemId() {
return this.$store.state.playerLibraryItemId
isPlayerOpen() {
return this.$store.getters['getIsPlayerOpen']
},
readerHeightOffset() {
return this.playerLibraryItemId ? 204 : 84
return this.isPlayerOpen ? 204 : 104
},
/** @returns {Array<ePub.NavItem>} */
chapters() {

View file

@ -23,9 +23,6 @@ export default {
return {}
},
computed: {
playerLibraryItemId() {
return this.$store.state.playerLibraryItemId
},
userToken() {
return this.$store.getters['user/getToken']
}

View file

@ -18,7 +18,7 @@
</div>
</div>
<div class="fixed left-0 h-8 w-full bg-primary px-4 flex items-center text-white/80" :style="{ bottom: playerLibraryItemId ? '120px' : '0px' }">
<div class="fixed left-0 h-8 w-full bg-primary px-4 flex items-center text-white/80" :style="{ bottom: isPlayerOpen ? '120px' : '0px' }">
<div class="flex-grow" />
<p class="text-xs">{{ page }} / {{ numPages }}</p>
</div>
@ -114,8 +114,8 @@ export default {
}
}
},
playerLibraryItemId() {
return this.$store.state.playerLibraryItemId
isPlayerOpen() {
return this.$store.getters['getIsPlayerOpen']
}
},
methods: {

View file

@ -1,5 +1,5 @@
<template>
<div v-if="show" :data-theme="ereaderTheme" class="group fixed top-0 left-0 right-0 layout-wrapper w-full z-40 pt-8 data-[theme=dark]:bg-primary data-[theme=dark]:text-white data-[theme=light]:bg-white data-[theme=light]:text-black" :class="{ 'reader-player-open': !!playerLibraryItemId }">
<div v-if="show" :data-theme="ereaderTheme" class="group fixed top-0 left-0 right-0 layout-wrapper w-full z-40 pt-8 data-[theme=dark]:bg-primary data-[theme=dark]:text-white data-[theme=light]:bg-white data-[theme=light]:text-black" :class="{ 'reader-player-open': isPlayerOpen }">
<!-- toolbar -->
<div class="h-32 pt-10 w-full px-2 fixed top-0 left-0 z-30 transition-transform bg-bg text-white" :class="showingToolbar ? 'translate-y-0' : '-translate-y-32'" @touchstart.stop @mousedown.stop @touchend.stop @mouseup.stop>
<div class="flex items-center mb-2">
@ -213,8 +213,8 @@ export default {
}
return `${serverAddress}/api/items/${this.selectedLibraryItem.id}/ebook`
},
playerLibraryItemId() {
return this.$store.state.playerLibraryItemId
isPlayerOpen() {
return this.$store.getters['getIsPlayerOpen']
},
keepProgress() {
return this.$store.state.ereaderKeepProgress

View file

@ -74,7 +74,7 @@ export default {
return !this.isMissing && !this.isInvalid && this.tracks.length
},
isStreaming() {
return this.$store.getters['getIsEpisodeStreaming'](this.libraryItemId)
return this.$store.getters['getIsMediaStreaming'](this.libraryItemId)
},
streamIsPlaying() {
return this.$store.state.playerIsPlaying && this.isStreaming

View file

@ -102,8 +102,8 @@ export default {
return !this.isMissing && !this.isInvalid && (this.tracks.length || this.episode)
},
isStreaming() {
if (this.localLibraryItem && this.$store.getters['getIsEpisodeStreaming'](this.localLibraryItem.id, this.localEpisode?.id)) return true
return this.$store.getters['getIsEpisodeStreaming'](this.libraryItem.id, this.episodeId)
if (this.localLibraryItem && this.localEpisode && this.$store.getters['getIsMediaStreaming'](this.localLibraryItem.id, this.localEpisode.id)) return true
return this.$store.getters['getIsMediaStreaming'](this.libraryItem.id, this.episodeId)
},
streamIsPlaying() {
return this.$store.state.playerIsPlaying && this.isStreaming

View file

@ -114,14 +114,7 @@ export default {
return this.$secondsToTimestamp(this.episode.duration)
},
isStreaming() {
if (this.playerIsLocal && this.localLibraryItemId && this.localEpisode) {
// Check is streaming local version of this episode
return this.$store.getters['getIsEpisodeStreaming'](this.localLibraryItemId, this.localEpisode.id)
}
return this.$store.getters['getIsEpisodeStreaming'](this.libraryItemId, this.episode.id)
},
playerIsLocal() {
return !!this.$store.state.playerIsLocal
return this.$store.getters['getIsMediaStreaming'](this.libraryItemId, this.episode.id)
},
streamIsPlaying() {
return this.$store.state.playerIsPlaying && this.isStreaming

View file

@ -117,14 +117,7 @@ export default {
return this.$secondsToTimestamp(this.episode.duration)
},
isStreaming() {
if (this.playerIsLocal && this.localLibraryItemId && this.localEpisode) {
// Check is streaming local version of this episode
return this.$store.getters['getIsEpisodeStreaming'](this.localLibraryItemId, this.localEpisode.id)
}
return this.$store.getters['getIsEpisodeStreaming'](this.libraryItemId, this.episode.id)
},
playerIsLocal() {
return !!this.$store.state.playerIsLocal
return this.$store.getters['getIsMediaStreaming'](this.libraryItemId, this.episode.id)
},
streamIsPlaying() {
return this.$store.state.playerIsPlaying && this.isStreaming

View file

@ -1,7 +1,7 @@
<template>
<div class="w-full layout-wrapper bg-bg text-white">
<app-appbar />
<div id="content" class="overflow-hidden relative" :class="playerIsOpen ? 'playerOpen' : ''">
<div id="content" class="overflow-hidden relative" :class="isPlayerOpen ? 'playerOpen' : ''">
<Nuxt />
<div v-if="attemptingConnection" class="absolute top-0 left-0 z-50 w-full h-full flex items-center justify-center">
@ -57,11 +57,8 @@ export default {
}
},
computed: {
playerIsOpen() {
return this.$store.state.playerLibraryItemId
},
readerIsOpen() {
return this.$store.state.showReader
isPlayerOpen() {
return this.$store.getters['getIsPlayerOpen']
},
routeName() {
return this.$route.name
@ -86,7 +83,7 @@ export default {
},
methods: {
initialStream(stream) {
if (this.$refs.streamContainer && this.$refs.streamContainer.audioPlayerReady) {
if (this.$refs.streamContainer?.audioPlayerReady) {
this.$refs.streamContainer.streamOpen(stream)
}
},
@ -234,8 +231,16 @@ export default {
this.$store.commit('user/setUser', user)
}
},
async userMediaProgressUpdated(prog) {
console.log(`[default] userMediaProgressUpdate checking for local media progress ${prog.id}`)
async userMediaProgressUpdated(payload) {
const prog = payload.data // MediaProgress
console.log(`[default] userMediaProgressUpdate checking for local media progress ${payload.id}`)
// Check if this media item is currently open in the player, paused, and this progress update is coming from a different session
const isMediaOpenInPlayer = this.$store.getters['getIsMediaStreaming'](prog.libraryItemId, prog.episodeId)
if (isMediaOpenInPlayer && this.$store.getters['getCurrentPlaybackSessionId'] !== payload.sessionId && !this.$store.state.playerIsPlaying) {
console.log('[default] userMediaProgressUpdated for current open media item', payload.data.currentTime)
this.$eventBus.$emit('playback-time-update', payload.data.currentTime)
}
// Update local media progress if exists
const localProg = await this.$db.getLocalMediaProgressForServerItem({ libraryItemId: prog.libraryItemId, episodeId: prog.episodeId })
@ -287,7 +292,7 @@ export default {
}
}
if (newLocalMediaProgress && newLocalMediaProgress.id) {
if (newLocalMediaProgress?.id) {
console.log(`[default] local media progress updated for ${newLocalMediaProgress.id}`)
this.$store.commit('globals/updateLocalMediaProgress', newLocalMediaProgress)
}

View file

@ -75,7 +75,7 @@ export default {
})
},
streaming() {
return !!this.playableBooks.find((b) => this.$store.getters['getIsItemStreaming'](b.id))
return !!this.playableBooks.find((b) => this.$store.getters['getIsMediaStreaming'](b.id))
},
showPlayButton() {
return this.playableBooks.length

View file

@ -209,14 +209,7 @@ export default {
return this.$store.getters['globals/getLibraryItemCoverSrcById'](this.libraryItemId)
},
isPlaying() {
if (this.playerIsLocal && this.localLibraryItemId && this.localEpisodeId) {
// Check is streaming local version of this episode
return this.$store.getters['getIsEpisodeStreaming'](this.localLibraryItemId, this.localEpisodeId)
}
return this.$store.getters['getIsEpisodeStreaming'](this.libraryItemId, this.episode.id)
},
playerIsLocal() {
return !!this.$store.state.playerIsLocal
return this.$store.getters['getIsMediaStreaming'](this.libraryItemId, this.episode.id)
},
playerIsPlaying() {
return this.$store.state.playerIsPlaying && this.isPlaying

View file

@ -326,11 +326,11 @@ export default {
return this.userItemProgress ? this.userItemProgress.finishedAt : 0
},
isStreaming() {
return this.isPlaying && !this.$store.state.playerIsLocal
return this.isPlaying && !this.$store.getters['getIsCurrentSessionLocal']
},
isPlaying() {
if (this.localLibraryItemId && this.$store.getters['getIsItemStreaming'](this.localLibraryItemId)) return true
return this.$store.getters['getIsItemStreaming'](this.libraryItemId)
if (this.localLibraryItemId && this.$store.getters['getIsMediaStreaming'](this.localLibraryItemId)) return true
return this.$store.getters['getIsMediaStreaming'](this.libraryItemId)
},
playerIsPlaying() {
return this.$store.state.playerIsPlaying && (this.isStreaming || this.isPlaying)

View file

@ -108,7 +108,7 @@
<p class="text-lg text-center px-8">{{ failed ? 'Failed to get local library item ' + localLibraryItemId : 'Loading..' }}</p>
</div>
<div v-if="orderChanged" class="fixed left-0 w-full py-4 px-4 bg-bg box-shadow-book flex items-center" :style="{ bottom: playerLibraryItemId ? '120px' : '0px' }">
<div v-if="orderChanged" class="fixed left-0 w-full py-4 px-4 bg-bg box-shadow-book flex items-center" :style="{ bottom: isPlayerOpen ? '120px' : '0px' }">
<div class="flex-grow" />
<ui-btn small color="success" @click="saveTrackOrder">Save Order</ui-btn>
</div>
@ -156,8 +156,8 @@ export default {
}
},
computed: {
playerLibraryItemId() {
return this.$store.state.playerLibraryItemId
isPlayerOpen() {
return this.$store.getters['getIsPlayerOpen']
},
isIos() {
return this.$platform === 'ios'

View file

@ -88,11 +88,10 @@ class ServerSocket extends EventEmitter {
this.emit('user_updated', data)
}
onUserItemProgressUpdated(data) {
console.log('[SOCKET] User Item Progress Updated', JSON.stringify(data))
var progress = data.data
this.$store.commit('user/updateUserMediaProgress', progress)
this.emit('user_media_progress_updated', progress)
onUserItemProgressUpdated(payload) {
console.log('[SOCKET] User Item Progress Updated', JSON.stringify(payload))
this.$store.commit('user/updateUserMediaProgress', payload.data)
this.emit('user_media_progress_updated', payload)
}
}

View file

@ -3,9 +3,7 @@ import { AbsAudioPlayer } from '@/plugins/capacitor'
export const state = () => ({
deviceData: null,
playerLibraryItemId: null,
playerEpisodeId: null,
playerIsLocal: false,
currentPlaybackSession: null,
playerIsPlaying: false,
playerIsFullscreen: false,
isCasting: false,
@ -30,16 +28,33 @@ export const state = () => ({
})
export const getters = {
getCurrentPlaybackSessionId: state => {
return state.currentPlaybackSession?.id || null
},
getIsPlayerOpen: state => {
return !!state.currentPlaybackSession
},
getIsCurrentSessionLocal: state => {
return state.currentPlaybackSession?.playMethod == this.$constants.PlayMethod.LOCAL
},
getIsMediaStreaming: state => (libraryItemId, episodeId) => {
if (!state.playerLibraryItemId) return null
if (!episodeId) return state.playerLibraryItemId == libraryItemId
return state.playerLibraryItemId == libraryItemId && state.playerEpisodeId == episodeId
},
getIsItemStreaming: state => libraryItemId => {
return state.playerLibraryItemId == libraryItemId
},
getIsEpisodeStreaming: state => (libraryItemId, episodeId) => {
return state.playerLibraryItemId == libraryItemId && state.playerEpisodeId == episodeId
if (!state.currentPlaybackSession || !libraryItemId) return false
// Check using local library item id and local episode id
const isLocalLibraryItemId = libraryItemId.startsWith('local_')
if (isLocalLibraryItemId) {
if (state.currentPlaybackSession.localLibraryItem?.id !== libraryItemId) {
return false
}
if (!episodeId) return true
return state.currentPlaybackSession.localEpisodeId === episodeId
}
if (state.currentPlaybackSession.libraryItemId !== libraryItemId) {
return false
}
if (!episodeId) return true
return state.currentPlaybackSession.episodeId === episodeId
},
getServerSetting: state => key => {
if (!state.serverSettings) return null
@ -96,19 +111,10 @@ export const mutations = {
setLastItemScrollData(state, data) {
state.lastItemScrollData = data
},
setPlayerItem(state, playbackSession) {
state.playerIsLocal = playbackSession ? playbackSession.playMethod == this.$constants.PlayMethod.LOCAL : false
setPlaybackSession(state, playbackSession) {
state.currentPlaybackSession = playbackSession
if (state.playerIsLocal) {
state.playerLibraryItemId = playbackSession ? playbackSession.localLibraryItem.id || null : null
state.playerEpisodeId = playbackSession ? playbackSession.localEpisodeId || null : null
} else {
state.playerLibraryItemId = playbackSession ? playbackSession.libraryItemId || null : null
state.playerEpisodeId = playbackSession ? playbackSession.episodeId || null : null
}
var mediaPlayer = playbackSession ? playbackSession.mediaPlayer : null
state.isCasting = mediaPlayer === "cast-player"
state.isCasting = playbackSession?.mediaPlayer === "cast-player"
},
setMediaPlayer(state, mediaPlayer) {
state.isCasting = mediaPlayer === 'cast-player'