mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-04-02 01:16:54 +02:00
Update:Handle multiple sessions open, sync when paused, show alert of multiple sessions open when both are playing #1660
This commit is contained in:
parent
9712bdf5f0
commit
53c96b2540
@ -268,6 +268,10 @@ export default {
|
|||||||
seek(time) {
|
seek(time) {
|
||||||
this.playerHandler.seek(time)
|
this.playerHandler.seek(time)
|
||||||
},
|
},
|
||||||
|
playbackTimeUpdate(time) {
|
||||||
|
// When updating progress from another session
|
||||||
|
this.playerHandler.seek(time, false)
|
||||||
|
},
|
||||||
setCurrentTime(time) {
|
setCurrentTime(time) {
|
||||||
this.currentTime = time
|
this.currentTime = time
|
||||||
if (this.$refs.audioPlayer) {
|
if (this.$refs.audioPlayer) {
|
||||||
@ -477,12 +481,14 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.$eventBus.$on('cast-session-active', this.castSessionActive)
|
this.$eventBus.$on('cast-session-active', this.castSessionActive)
|
||||||
this.$eventBus.$on('playback-seek', this.seek)
|
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('play-item', this.playLibraryItem)
|
||||||
this.$eventBus.$on('pause-item', this.pauseItem)
|
this.$eventBus.$on('pause-item', this.pauseItem)
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.$eventBus.$off('cast-session-active', this.castSessionActive)
|
this.$eventBus.$off('cast-session-active', this.castSessionActive)
|
||||||
this.$eventBus.$off('playback-seek', this.seek)
|
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('play-item', this.playLibraryItem)
|
||||||
this.$eventBus.$off('pause-item', this.pauseItem)
|
this.$eventBus.$off('pause-item', this.pauseItem)
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,9 @@ export default {
|
|||||||
isSocketConnected: false,
|
isSocketConnected: false,
|
||||||
isFirstSocketConnection: true,
|
isFirstSocketConnection: true,
|
||||||
socketConnectionToastId: null,
|
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: {
|
watch: {
|
||||||
@ -300,14 +302,27 @@ export default {
|
|||||||
this.$store.commit('users/updateUserOnline', user)
|
this.$store.commit('users/updateUserOnline', user)
|
||||||
},
|
},
|
||||||
userSessionClosed(sessionId) {
|
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)
|
if (this.$refs.streamContainer) this.$refs.streamContainer.sessionClosedEvent(sessionId)
|
||||||
},
|
},
|
||||||
userMediaProgressUpdate(payload) {
|
userMediaProgressUpdate(payload) {
|
||||||
this.$store.commit('user/updateMediaProgress', payload)
|
this.$store.commit('user/updateMediaProgress', payload)
|
||||||
|
|
||||||
if (payload.data) {
|
if (payload.data) {
|
||||||
if (this.$store.getters['getIsMediaStreaming'](payload.data.libraryItemId, payload.data.episodeId)) {
|
if (this.$store.getters['getIsMediaStreaming'](payload.data.libraryItemId, payload.data.episodeId) && this.$store.state.playbackSessionId !== payload.sessionId) {
|
||||||
// TODO: Update currently open session if being played from another device
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -52,6 +52,11 @@ export default class PlayerHandler {
|
|||||||
return this.libraryItem.media.episodes.find(ep => ep.id === this.episodeId)
|
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) {
|
load(libraryItem, episodeId, playWhenReady, playbackRate, startTimeOverride = undefined) {
|
||||||
this.libraryItem = libraryItem
|
this.libraryItem = libraryItem
|
||||||
this.isVideo = libraryItem.mediaType === 'video'
|
this.isVideo = libraryItem.mediaType === 'video'
|
||||||
@ -182,7 +187,7 @@ export default class PlayerHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async prepare(forceTranscode = false) {
|
async prepare(forceTranscode = false) {
|
||||||
this.currentSessionId = null // Reset session
|
this.setSessionId(null) // Reset session
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
deviceInfo: {
|
deviceInfo: {
|
||||||
@ -218,7 +223,7 @@ export default class PlayerHandler {
|
|||||||
prepareSession(session) {
|
prepareSession(session) {
|
||||||
this.failedProgressSyncs = 0
|
this.failedProgressSyncs = 0
|
||||||
this.startTime = this.startTimeOverride !== undefined ? this.startTimeOverride : session.currentTime
|
this.startTime = this.startTimeOverride !== undefined ? this.startTimeOverride : session.currentTime
|
||||||
this.currentSessionId = session.id
|
this.setSessionId(session.id)
|
||||||
this.displayTitle = session.displayTitle
|
this.displayTitle = session.displayTitle
|
||||||
this.displayAuthor = session.displayAuthor
|
this.displayAuthor = session.displayAuthor
|
||||||
|
|
||||||
@ -263,7 +268,7 @@ export default class PlayerHandler {
|
|||||||
this.player = null
|
this.player = null
|
||||||
this.playerState = 'IDLE'
|
this.playerState = 'IDLE'
|
||||||
this.libraryItem = null
|
this.libraryItem = null
|
||||||
this.currentSessionId = null
|
this.setSessionId(null)
|
||||||
this.startTime = 0
|
this.startTime = 0
|
||||||
this.stopPlayInterval()
|
this.stopPlayInterval()
|
||||||
}
|
}
|
||||||
@ -300,7 +305,7 @@ export default class PlayerHandler {
|
|||||||
if (this.player) {
|
if (this.player) {
|
||||||
const listeningTimeToAdd = Math.max(0, Math.floor(this.listeningTimeSinceSync))
|
const listeningTimeToAdd = Math.max(0, Math.floor(this.listeningTimeSinceSync))
|
||||||
// When opening player and quickly closing dont save progress
|
// When opening player and quickly closing dont save progress
|
||||||
if (listeningTimeToAdd > 20 || this.lastSyncTime > 0) {
|
if (listeningTimeToAdd > 20) {
|
||||||
syncData = {
|
syncData = {
|
||||||
timeListened: listeningTimeToAdd,
|
timeListened: listeningTimeToAdd,
|
||||||
duration: this.getDuration(),
|
duration: this.getDuration(),
|
||||||
@ -390,13 +395,13 @@ export default class PlayerHandler {
|
|||||||
this.player.setPlaybackRate(playbackRate)
|
this.player.setPlaybackRate(playbackRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
seek(time) {
|
seek(time, shouldSync = true) {
|
||||||
if (!this.player) return
|
if (!this.player) return
|
||||||
this.player.seek(time, this.playerPlaying)
|
this.player.seek(time, this.playerPlaying)
|
||||||
this.ctx.setCurrentTime(time)
|
this.ctx.setCurrentTime(time)
|
||||||
|
|
||||||
// Update progress if paused
|
// Update progress if paused
|
||||||
if (!this.playerPlaying) {
|
if (!this.playerPlaying && shouldSync) {
|
||||||
this.sendProgressSync(time)
|
this.sendProgressSync(time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ export const state = () => ({
|
|||||||
Source: null,
|
Source: null,
|
||||||
versionData: null,
|
versionData: null,
|
||||||
serverSettings: null,
|
serverSettings: null,
|
||||||
|
playbackSessionId: null,
|
||||||
streamLibraryItem: null,
|
streamLibraryItem: null,
|
||||||
streamEpisodeId: null,
|
streamEpisodeId: null,
|
||||||
streamIsPlaying: false,
|
streamIsPlaying: false,
|
||||||
@ -150,6 +151,9 @@ export const mutations = {
|
|||||||
if (!settings) return
|
if (!settings) return
|
||||||
state.serverSettings = settings
|
state.serverSettings = settings
|
||||||
},
|
},
|
||||||
|
setPlaybackSessionId(state, playbackSessionId) {
|
||||||
|
state.playbackSessionId = playbackSessionId
|
||||||
|
},
|
||||||
setMediaPlaying(state, payload) {
|
setMediaPlaying(state, payload) {
|
||||||
if (!payload) {
|
if (!payload) {
|
||||||
state.streamLibraryItem = null
|
state.streamLibraryItem = null
|
||||||
|
@ -130,6 +130,8 @@ class PlaybackSessionManager {
|
|||||||
const itemProgress = user.getMediaProgress(session.libraryItemId, session.episodeId)
|
const itemProgress = user.getMediaProgress(session.libraryItemId, session.episodeId)
|
||||||
SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
|
SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
|
||||||
id: itemProgress.id,
|
id: itemProgress.id,
|
||||||
|
sessionId: session.id,
|
||||||
|
deviceDescription: session.deviceDescription,
|
||||||
data: itemProgress.toJSON()
|
data: itemProgress.toJSON()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -239,6 +241,8 @@ class PlaybackSessionManager {
|
|||||||
const itemProgress = user.getMediaProgress(session.libraryItemId, session.episodeId)
|
const itemProgress = user.getMediaProgress(session.libraryItemId, session.episodeId)
|
||||||
SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
|
SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
|
||||||
id: itemProgress.id,
|
id: itemProgress.id,
|
||||||
|
sessionId: session.id,
|
||||||
|
deviceDescription: session.deviceDescription,
|
||||||
data: itemProgress.toJSON()
|
data: itemProgress.toJSON()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -306,7 +310,7 @@ class PlaybackSessionManager {
|
|||||||
// See https://github.com/advplyr/audiobookshelf/issues/868
|
// See https://github.com/advplyr/audiobookshelf/issues/868
|
||||||
// Remove playback sessions with listening time too high
|
// Remove playback sessions with listening time too high
|
||||||
async removeInvalidSessions() {
|
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)
|
const numSessionsRemoved = await this.db.removeEntities('session', selectFunc, true)
|
||||||
if (numSessionsRemoved) {
|
if (numSessionsRemoved) {
|
||||||
Logger.info(`[PlaybackSessionManager] Removed ${numSessionsRemoved} invalid playback sessions`)
|
Logger.info(`[PlaybackSessionManager] Removed ${numSessionsRemoved} invalid playback sessions`)
|
||||||
|
Loading…
Reference in New Issue
Block a user