Update:Handle multiple sessions open, sync when paused, show alert of multiple sessions open when both are playing #1660

This commit is contained in:
advplyr 2023-05-27 17:21:43 -05:00
parent 9712bdf5f0
commit 53c96b2540
5 changed files with 44 additions and 10 deletions

View File

@ -268,6 +268,10 @@ export default {
seek(time) {
this.playerHandler.seek(time)
},
playbackTimeUpdate(time) {
// When updating progress from another session
this.playerHandler.seek(time, false)
},
setCurrentTime(time) {
this.currentTime = time
if (this.$refs.audioPlayer) {
@ -477,12 +481,14 @@ export default {
mounted() {
this.$eventBus.$on('cast-session-active', this.castSessionActive)
this.$eventBus.$on('playback-seek', this.seek)
this.$eventBus.$on('playback-time-update', this.playbackTimeUpdate)
this.$eventBus.$on('play-item', this.playLibraryItem)
this.$eventBus.$on('pause-item', this.pauseItem)
},
beforeDestroy() {
this.$eventBus.$off('cast-session-active', this.castSessionActive)
this.$eventBus.$off('playback-seek', this.seek)
this.$eventBus.$off('playback-time-update', this.playbackTimeUpdate)
this.$eventBus.$off('play-item', this.playLibraryItem)
this.$eventBus.$off('pause-item', this.pauseItem)
}

View File

@ -35,7 +35,9 @@ export default {
isSocketConnected: false,
isFirstSocketConnection: true,
socketConnectionToastId: null,
currentLang: null
currentLang: null,
multiSessionOtherSessionId: null, // Used for multiple sessions open warning toast
multiSessionCurrentSessionId: null // Used for multiple sessions open warning toast
}
},
watch: {
@ -300,14 +302,27 @@ export default {
this.$store.commit('users/updateUserOnline', user)
},
userSessionClosed(sessionId) {
// If this session or other session is closed then dismiss multiple sessions warning toast
if (sessionId === this.multiSessionOtherSessionId || this.multiSessionCurrentSessionId === sessionId) {
this.multiSessionOtherSessionId = null
this.multiSessionCurrentSessionId = null
this.$toast.dismiss('multiple-sessions')
}
if (this.$refs.streamContainer) this.$refs.streamContainer.sessionClosedEvent(sessionId)
},
userMediaProgressUpdate(payload) {
this.$store.commit('user/updateMediaProgress', payload)
if (payload.data) {
if (this.$store.getters['getIsMediaStreaming'](payload.data.libraryItemId, payload.data.episodeId)) {
// TODO: Update currently open session if being played from another device
if (this.$store.getters['getIsMediaStreaming'](payload.data.libraryItemId, payload.data.episodeId) && this.$store.state.playbackSessionId !== payload.sessionId) {
this.multiSessionOtherSessionId = payload.sessionId
this.multiSessionCurrentSessionId = this.$store.state.playbackSessionId
console.log(`Media progress was updated from another session (${this.multiSessionOtherSessionId}) for currently open media. Device description=${payload.deviceDescription}. Current session id=${this.multiSessionCurrentSessionId}`)
if (this.$store.state.streamIsPlaying) {
this.$toast.update('multiple-sessions', { content: `Another session is open for this item on device ${payload.deviceDescription}`, options: { timeout: 20000, type: 'warning', pauseOnFocusLoss: false } }, true)
} else {
this.$eventBus.$emit('playback-time-update', payload.data.currentTime)
}
}
}
},

View File

@ -52,6 +52,11 @@ export default class PlayerHandler {
return this.libraryItem.media.episodes.find(ep => ep.id === this.episodeId)
}
setSessionId(sessionId) {
this.currentSessionId = sessionId
this.ctx.$store.commit('setPlaybackSessionId', sessionId)
}
load(libraryItem, episodeId, playWhenReady, playbackRate, startTimeOverride = undefined) {
this.libraryItem = libraryItem
this.isVideo = libraryItem.mediaType === 'video'
@ -182,7 +187,7 @@ export default class PlayerHandler {
}
async prepare(forceTranscode = false) {
this.currentSessionId = null // Reset session
this.setSessionId(null) // Reset session
const payload = {
deviceInfo: {
@ -218,7 +223,7 @@ export default class PlayerHandler {
prepareSession(session) {
this.failedProgressSyncs = 0
this.startTime = this.startTimeOverride !== undefined ? this.startTimeOverride : session.currentTime
this.currentSessionId = session.id
this.setSessionId(session.id)
this.displayTitle = session.displayTitle
this.displayAuthor = session.displayAuthor
@ -263,7 +268,7 @@ export default class PlayerHandler {
this.player = null
this.playerState = 'IDLE'
this.libraryItem = null
this.currentSessionId = null
this.setSessionId(null)
this.startTime = 0
this.stopPlayInterval()
}
@ -300,7 +305,7 @@ export default class PlayerHandler {
if (this.player) {
const listeningTimeToAdd = Math.max(0, Math.floor(this.listeningTimeSinceSync))
// When opening player and quickly closing dont save progress
if (listeningTimeToAdd > 20 || this.lastSyncTime > 0) {
if (listeningTimeToAdd > 20) {
syncData = {
timeListened: listeningTimeToAdd,
duration: this.getDuration(),
@ -390,13 +395,13 @@ export default class PlayerHandler {
this.player.setPlaybackRate(playbackRate)
}
seek(time) {
seek(time, shouldSync = true) {
if (!this.player) return
this.player.seek(time, this.playerPlaying)
this.ctx.setCurrentTime(time)
// Update progress if paused
if (!this.playerPlaying) {
if (!this.playerPlaying && shouldSync) {
this.sendProgressSync(time)
}
}

View File

@ -6,6 +6,7 @@ export const state = () => ({
Source: null,
versionData: null,
serverSettings: null,
playbackSessionId: null,
streamLibraryItem: null,
streamEpisodeId: null,
streamIsPlaying: false,
@ -150,6 +151,9 @@ export const mutations = {
if (!settings) return
state.serverSettings = settings
},
setPlaybackSessionId(state, playbackSessionId) {
state.playbackSessionId = playbackSessionId
},
setMediaPlaying(state, payload) {
if (!payload) {
state.streamLibraryItem = null

View File

@ -130,6 +130,8 @@ class PlaybackSessionManager {
const itemProgress = user.getMediaProgress(session.libraryItemId, session.episodeId)
SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
id: itemProgress.id,
sessionId: session.id,
deviceDescription: session.deviceDescription,
data: itemProgress.toJSON()
})
}
@ -239,6 +241,8 @@ class PlaybackSessionManager {
const itemProgress = user.getMediaProgress(session.libraryItemId, session.episodeId)
SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
id: itemProgress.id,
sessionId: session.id,
deviceDescription: session.deviceDescription,
data: itemProgress.toJSON()
})
}
@ -306,7 +310,7 @@ class PlaybackSessionManager {
// See https://github.com/advplyr/audiobookshelf/issues/868
// Remove playback sessions with listening time too high
async removeInvalidSessions() {
const selectFunc = (session) => isNaN(session.timeListening) || Number(session.timeListening) > 3600000000
const selectFunc = (session) => isNaN(session.timeListening) || Number(session.timeListening) > 36000000
const numSessionsRemoved = await this.db.removeEntities('session', selectFunc, true)
if (numSessionsRemoved) {
Logger.info(`[PlaybackSessionManager] Removed ${numSessionsRemoved} invalid playback sessions`)