mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-13 04:41:36 +00:00
first_progress
This commit is contained in:
parent
09d7880779
commit
2d10669700
15 changed files with 643 additions and 108 deletions
|
|
@ -21,7 +21,7 @@
|
|||
<div v-if="isChromecastInitialized" class="w-6 min-w-6 h-6 ml-2 mr-1 sm:mx-2 cursor-pointer">
|
||||
<google-cast-launcher></google-cast-launcher>
|
||||
</div>
|
||||
|
||||
<ui-dlna-dropdown class="mr-2" />
|
||||
<widgets-notification-widget class="hidden md:block" />
|
||||
|
||||
<nuxt-link v-if="currentLibrary" to="/config/stats" class="hover:text-gray-200 cursor-pointer w-8 h-8 hidden sm:flex items-center justify-center mx-1">
|
||||
|
|
@ -155,6 +155,7 @@ export default {
|
|||
isChromecastInitialized() {
|
||||
return this.$store.state.globals.isChromecastInitialized
|
||||
},
|
||||
|
||||
isHttps() {
|
||||
return location.protocol === 'https:' || process.env.NODE_ENV === 'development'
|
||||
},
|
||||
|
|
|
|||
95
client/components/ui/DlnaDropdown.vue
Normal file
95
client/components/ui/DlnaDropdown.vue
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
<template>
|
||||
<div class="max-w-52" v-click-outside="clickOutsideObj" v-if="has_devices">
|
||||
<button type="button" :disabled="disabled" aria-haspopup="listbox" :aria-expanded="showMenu" @click.stop.prevent="clickShowMenu">
|
||||
<div class="flex">
|
||||
<span class="hidden sm:block truncate">
|
||||
<span v-show="has_devices" class="material-icons-outlined text-2xl text-opacity-50" v-bind:class="{ 'icon-blue': has_device }"> cast </span>
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<transition name="menu">
|
||||
<ul v-show="showMenu" class="absolute z-10 -mt-px w-full min-w-48 bg-primary border border-black-200 shadow-lg rounded-b-md py-1 overflow-auto focus:outline-none sm:text-sm DlnaDropdownMenu" tabindex="-1" role="listbox">
|
||||
<template v-for="device in get_devices">
|
||||
<li :key="device.host" class="text-gray-400 hover:text-white relative py-2 cursor-pointer hover:bg-black-400" v-bind:class="{ 'bg-black-600': get_device == device.host }" role="option" tabindex="0" @keydown.enter="selectDevice(device.host)" @click="selectDevice(device.host)">
|
||||
<div class="flex items-center px-2">
|
||||
<span class="font-normal block truncate font-sans text-sm">{{ device.name }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, computed } from 'vue'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
clickOutsideObj: {
|
||||
handler: this.clickedOutside,
|
||||
events: ['mousedown'],
|
||||
isActive: true
|
||||
},
|
||||
showMenu: false,
|
||||
disabled: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickShowMenu() {
|
||||
if (this.disabled) return
|
||||
this.showMenu = !this.showMenu
|
||||
},
|
||||
clickedOutside() {
|
||||
this.showMenu = false
|
||||
},
|
||||
selectDevice(device) {
|
||||
if (this.selectedDevice == device) {
|
||||
this.$store.commit('globals/setDlnaDevice', '')
|
||||
this.selectedDevice = ''
|
||||
} else {
|
||||
this.selectedDevice = device
|
||||
this.$store.commit('globals/setDlnaDevice', device)
|
||||
this.$root.socket.emit('test')
|
||||
}
|
||||
this.showMenu = false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
has_device() {
|
||||
return Boolean(this.$store.getters['globals/getDLNAdevice'])
|
||||
},
|
||||
has_devices() {
|
||||
return Boolean(this.$store.getters['globals/getDLNAdevices'])
|
||||
},
|
||||
get_device() {
|
||||
return this.$store.getters['globals/getDLNAdevice']
|
||||
},
|
||||
get_devices() {
|
||||
return this.$store.getters['globals/getDLNAdevices']
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$axios
|
||||
.$get('/api/dlna/devices')
|
||||
.catch((error) => {
|
||||
console.error('failed to fetch DLNA devices', error)
|
||||
return null
|
||||
})
|
||||
.then((response) => {
|
||||
this.$store.commit('globals/setDlnaDevices', response)
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.DlnaDropdownMenu {
|
||||
max-height: calc(100vh - 75px);
|
||||
max-width: 100pt;
|
||||
}
|
||||
.icon-blue {
|
||||
color: blue;
|
||||
}
|
||||
</style>
|
||||
88
client/players/DLNAPlayer.js
Normal file
88
client/players/DLNAPlayer.js
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
import EventEmitter from 'events'
|
||||
|
||||
export default class DLNAPlayer extends EventEmitter {
|
||||
constructor(ctx) {
|
||||
super()
|
||||
|
||||
this.ctx = ctx
|
||||
this.player = null
|
||||
this.playerController = null
|
||||
|
||||
this.libraryItem = null
|
||||
this.audioTracks = []
|
||||
this.currentTrackIndex = 0
|
||||
this.isHlsTranscode = null
|
||||
this.currentTime = 0
|
||||
this.playWhenReady = false
|
||||
this.defaultPlaybackRate = 1
|
||||
|
||||
// TODO: Use canDisplayType on receiver to check mime types
|
||||
this.playableMimeTypes = ['audio/flac', 'audio/mpeg', 'audio/mp4', 'audio/ogg', 'audio/aac', 'audio/x-ms-wma', 'audio/x-aiff', 'audio/webm']
|
||||
|
||||
this.coverUrl = ''
|
||||
this.castPlayerState = 'IDLE'
|
||||
|
||||
// Supported audio codecs for chromecast
|
||||
|
||||
this.supportedAudioCodecs = ['opus', 'mp3', 'aac', 'flac', 'webma', 'wav']
|
||||
|
||||
this.initialize()
|
||||
}
|
||||
|
||||
get currentTrack() {
|
||||
return this.audioTracks[this.currentTrackIndex] || {}
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.ctx.$root.socket.on('test', this.destroy)
|
||||
//this.player = this.ctx.$root.castPlayer
|
||||
}
|
||||
|
||||
evtMediaInfoChanged() {}
|
||||
|
||||
destroy() {}
|
||||
|
||||
async set(libraryItem, tracks, isHlsTranscode, startTime, playWhenReady = false) {
|
||||
this.libraryItem = libraryItem
|
||||
this.audioTracks = tracks
|
||||
this.isHlsTranscode = isHlsTranscode
|
||||
this.playWhenReady = playWhenReady
|
||||
this.currentTime = startTime
|
||||
console.log('Tracks: ')
|
||||
console.log(tracks.find((at) => at.startOffset <= startTime && at.startOffset + at.duration > startTime))
|
||||
var coverImg = this.ctx.$store.getters['globals/getLibraryItemCoverSrc'](libraryItem)
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
this.coverUrl = coverImg
|
||||
} else {
|
||||
this.coverUrl = `${window.location.origin}${coverImg}`
|
||||
}
|
||||
this.ctx.$root.socket.emit('dlna_start', this.audioTracks)
|
||||
}
|
||||
|
||||
resetStream(startTime) {}
|
||||
|
||||
playPause() {}
|
||||
|
||||
play() {}
|
||||
|
||||
pause() {}
|
||||
|
||||
getCurrentTime() {
|
||||
//var currentTrackOffset = this.currentTrack.startOffset || 0
|
||||
return 0 //this.player ? currentTrackOffset + this.player.currentTime : 0
|
||||
}
|
||||
|
||||
getDuration() {
|
||||
if (!this.audioTracks.length) return 0
|
||||
var lastTrack = this.audioTracks[this.audioTracks.length - 1]
|
||||
return lastTrack.startOffset + lastTrack.duration
|
||||
}
|
||||
|
||||
setPlaybackRate(playbackRate) {
|
||||
this.defaultPlaybackRate = playbackRate
|
||||
}
|
||||
|
||||
async seek(time, playWhenReady) {}
|
||||
|
||||
setVolume(volume) {}
|
||||
}
|
||||
|
|
@ -113,7 +113,6 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||
this.isHlsTranscode = isHlsTranscode
|
||||
this.playWhenReady = playWhenReady
|
||||
this.startTime = startTime
|
||||
|
||||
if (this.hlsInstance) {
|
||||
this.destroyHlsInstance()
|
||||
}
|
||||
|
|
@ -147,7 +146,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||
timeoutRetry: {
|
||||
maxNumRetry: 4,
|
||||
retryDelayMs: 0,
|
||||
maxRetryDelayMs: 0,
|
||||
maxRetryDelayMs: 0
|
||||
},
|
||||
errorRetry: {
|
||||
maxNumRetry: 8,
|
||||
|
|
@ -160,7 +159,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||
}
|
||||
return retry
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -194,7 +193,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||
|
||||
setDirectPlay() {
|
||||
// Set initial track and track time offset
|
||||
var trackIndex = this.audioTracks.findIndex(t => this.startTime >= t.startOffset && this.startTime < (t.startOffset + t.duration))
|
||||
var trackIndex = this.audioTracks.findIndex((t) => this.startTime >= t.startOffset && this.startTime < t.startOffset + t.duration)
|
||||
this.currentTrackIndex = trackIndex >= 0 ? trackIndex : 0
|
||||
|
||||
this.loadCurrentTrack()
|
||||
|
|
@ -270,7 +269,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||
// Seeking Direct play
|
||||
if (time < this.currentTrack.startOffset || time > this.currentTrack.startOffset + this.currentTrack.duration) {
|
||||
// Change Track
|
||||
var trackIndex = this.audioTracks.findIndex(t => time >= t.startOffset && time < (t.startOffset + t.duration))
|
||||
var trackIndex = this.audioTracks.findIndex((t) => time >= t.startOffset && time < t.startOffset + t.duration)
|
||||
if (trackIndex >= 0) {
|
||||
this.startTime = time
|
||||
this.currentTrackIndex = trackIndex
|
||||
|
|
@ -293,7 +292,6 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||
this.player.volume = volume
|
||||
}
|
||||
|
||||
|
||||
// Utils
|
||||
isValidDuration(duration) {
|
||||
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
|
||||
|
|
@ -338,4 +336,4 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||
var last = bufferedRanges[bufferedRanges.length - 1]
|
||||
return last.end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import LocalVideoPlayer from './LocalVideoPlayer'
|
|||
import CastPlayer from './CastPlayer'
|
||||
import AudioTrack from './AudioTrack'
|
||||
import VideoTrack from './VideoTrack'
|
||||
import DLNAPlayer from './DLNAPlayer'
|
||||
|
||||
export default class PlayerHandler {
|
||||
constructor(ctx) {
|
||||
|
|
@ -32,14 +33,17 @@ export default class PlayerHandler {
|
|||
get isCasting() {
|
||||
return this.ctx.$store.state.globals.isCasting
|
||||
}
|
||||
get get_Dlna() {
|
||||
return this.ctx.$store.state.globals.dlnaDevice
|
||||
}
|
||||
get libraryItemId() {
|
||||
return this.libraryItem ? this.libraryItem.id : null
|
||||
}
|
||||
get isPlayingCastedItem() {
|
||||
return this.libraryItem && (this.player instanceof CastPlayer)
|
||||
return this.libraryItem && this.player instanceof CastPlayer
|
||||
}
|
||||
get isPlayingLocalItem() {
|
||||
return this.libraryItem && (this.player instanceof LocalAudioPlayer)
|
||||
return this.libraryItem && this.player instanceof LocalAudioPlayer
|
||||
}
|
||||
get userToken() {
|
||||
return this.ctx.$store.getters['user/getToken']
|
||||
|
|
@ -49,7 +53,7 @@ export default class PlayerHandler {
|
|||
}
|
||||
get episode() {
|
||||
if (!this.episodeId) return null
|
||||
return this.libraryItem.media.episodes.find(ep => ep.id === this.episodeId)
|
||||
return this.libraryItem.media.episodes.find((ep) => ep.id === this.episodeId)
|
||||
}
|
||||
|
||||
setSessionId(sessionId) {
|
||||
|
|
@ -66,7 +70,7 @@ export default class PlayerHandler {
|
|||
this.playWhenReady = playWhenReady
|
||||
this.initialPlaybackRate = this.isMusic ? 1 : playbackRate
|
||||
|
||||
this.startTimeOverride = (startTimeOverride == null || isNaN(startTimeOverride)) ? undefined : Number(startTimeOverride)
|
||||
this.startTimeOverride = startTimeOverride == null || isNaN(startTimeOverride) ? undefined : Number(startTimeOverride)
|
||||
|
||||
if (!this.player) this.switchPlayer(playWhenReady)
|
||||
else this.prepare()
|
||||
|
|
@ -86,6 +90,22 @@ export default class PlayerHandler {
|
|||
this.player = new CastPlayer(this.ctx)
|
||||
this.setPlayerListeners()
|
||||
|
||||
if (this.libraryItem) {
|
||||
// libraryItem was already loaded - prepare for cast
|
||||
this.playWhenReady = playWhenReady
|
||||
this.prepare()
|
||||
}
|
||||
} else if (this.get_Dlna) {
|
||||
console.log('[PlayerHandler] Switching to DLNA player')
|
||||
this.stopPlayInterval()
|
||||
this.playerStateChange('LOADING')
|
||||
this.startTime = this.player ? this.player.getCurrentTime() : this.startTime
|
||||
if (this.player) {
|
||||
this.player.destroy()
|
||||
}
|
||||
this.player = new DLNAPlayer(this.ctx)
|
||||
this.setPlayerListeners()
|
||||
|
||||
if (this.libraryItem) {
|
||||
// libraryItem was already loaded - prepare for cast
|
||||
this.playWhenReady = playWhenReady
|
||||
|
|
@ -127,7 +147,7 @@ export default class PlayerHandler {
|
|||
|
||||
playerError() {
|
||||
// Switch to HLS stream on error
|
||||
if (!this.isCasting && (this.player instanceof LocalAudioPlayer)) {
|
||||
if (!this.isCasting && this.player instanceof LocalAudioPlayer) {
|
||||
console.log(`[PlayerHandler] Audio player error switching to HLS stream`)
|
||||
this.prepare(true)
|
||||
}
|
||||
|
|
@ -199,15 +219,17 @@ export default class PlayerHandler {
|
|||
forceTranscode,
|
||||
forceDirectPlay: this.isCasting || this.isVideo // TODO: add transcode support for chromecast
|
||||
}
|
||||
|
||||
console.log('Payload:', payload)
|
||||
const path = this.episodeId ? `/api/items/${this.libraryItem.id}/play/${this.episodeId}` : `/api/items/${this.libraryItem.id}/play`
|
||||
const session = await this.ctx.$axios.$post(path, payload).catch((error) => {
|
||||
console.error('Failed to start stream', error)
|
||||
})
|
||||
console.log(session)
|
||||
this.prepareSession(session)
|
||||
}
|
||||
|
||||
prepareOpenSession(session, playbackRate) { // Session opened on init socket
|
||||
prepareOpenSession(session, playbackRate) {
|
||||
// Session opened on init socket
|
||||
if (!this.player) this.switchPlayer() // Must set player first for open sessions
|
||||
|
||||
this.libraryItem = session.libraryItem
|
||||
|
|
@ -241,14 +263,14 @@ export default class PlayerHandler {
|
|||
|
||||
this.player.set(this.libraryItem, videoTrack, this.isHlsTranscode, this.startTime, this.playWhenReady)
|
||||
} else {
|
||||
var audioTracks = session.audioTracks.map(at => new AudioTrack(at, this.userToken))
|
||||
var audioTracks = session.audioTracks.map((at) => new AudioTrack(at, this.userToken))
|
||||
|
||||
this.ctx.playerLoading = true
|
||||
this.isHlsTranscode = true
|
||||
if (session.playMethod === this.ctx.$constants.PlayMethod.DIRECTPLAY) {
|
||||
this.isHlsTranscode = false
|
||||
}
|
||||
|
||||
console.log('blub', audioTracks)
|
||||
this.player.set(this.libraryItem, audioTracks, this.isHlsTranscode, this.startTime, this.playWhenReady)
|
||||
}
|
||||
|
||||
|
|
@ -295,7 +317,7 @@ export default class PlayerHandler {
|
|||
const currentTime = this.player.getCurrentTime()
|
||||
this.ctx.setCurrentTime(currentTime)
|
||||
|
||||
const exactTimeElapsed = ((Date.now() - lastTick) / 1000)
|
||||
const exactTimeElapsed = (Date.now() - lastTick) / 1000
|
||||
lastTick = Date.now()
|
||||
this.listeningTimeSinceSync += exactTimeElapsed
|
||||
const TimeToWaitBeforeSync = this.lastSyncTime > 0 ? 10 : 20
|
||||
|
|
@ -340,17 +362,20 @@ export default class PlayerHandler {
|
|||
}
|
||||
|
||||
this.listeningTimeSinceSync = 0
|
||||
this.ctx.$axios.$post(`/api/session/${this.currentSessionId}/sync`, syncData, { timeout: 9000 }).then(() => {
|
||||
this.failedProgressSyncs = 0
|
||||
}).catch((error) => {
|
||||
console.error('Failed to update session progress', error)
|
||||
// After 4 failed sync attempts show an alert toast
|
||||
this.failedProgressSyncs++
|
||||
if (this.failedProgressSyncs >= 4) {
|
||||
this.ctx.showFailedProgressSyncs()
|
||||
this.ctx.$axios
|
||||
.$post(`/api/session/${this.currentSessionId}/sync`, syncData, { timeout: 9000 })
|
||||
.then(() => {
|
||||
this.failedProgressSyncs = 0
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to update session progress', error)
|
||||
// After 4 failed sync attempts show an alert toast
|
||||
this.failedProgressSyncs++
|
||||
if (this.failedProgressSyncs >= 4) {
|
||||
this.ctx.showFailedProgressSyncs()
|
||||
this.failedProgressSyncs = 0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
stopPlayInterval() {
|
||||
|
|
@ -411,4 +436,4 @@ export default class PlayerHandler {
|
|||
this.sendProgressSync(time)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ export const state = () => ({
|
|||
selectedRawCoverUrl: null,
|
||||
isCasting: false, // Actively casting
|
||||
isChromecastInitialized: false, // Script loadeds
|
||||
dlnaDevice: '',
|
||||
dlnaDevices: [],
|
||||
showBatchQuickMatchModal: false,
|
||||
dateFormats: [
|
||||
{
|
||||
|
|
@ -118,6 +120,12 @@ export const getters = {
|
|||
},
|
||||
getIsBatchSelectingMediaItems: (state) => {
|
||||
return state.selectedMediaItems.length
|
||||
},
|
||||
getDLNAdevice: (state) => {
|
||||
return state.dlnaDevice
|
||||
},
|
||||
getDLNAdevices: (state) => {
|
||||
return state.dlnaDevices
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,5 +229,17 @@ export const mutations = {
|
|||
} else if (selected && !isAlreadySelected) {
|
||||
state.selectedMediaItems.push(item)
|
||||
}
|
||||
},
|
||||
setDlnaDevices(state, val){
|
||||
state.dlnaDevices = val
|
||||
for (var device in devices){
|
||||
if (device.host == state.dlnaDevice){
|
||||
return
|
||||
}
|
||||
}
|
||||
state.dlnaDevice = ''
|
||||
},
|
||||
setDlnaDevice(state, val){
|
||||
state.dlnaDevice = val
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,33 +32,33 @@ export const state = () => ({
|
|||
})
|
||||
|
||||
export const getters = {
|
||||
getServerSetting: state => key => {
|
||||
getServerSetting: (state) => (key) => {
|
||||
if (!state.serverSettings) return null
|
||||
return state.serverSettings[key]
|
||||
},
|
||||
getLibraryItemIdStreaming: state => {
|
||||
getLibraryItemIdStreaming: (state) => {
|
||||
return state.streamLibraryItem?.id || null
|
||||
},
|
||||
getIsStreamingFromDifferentLibrary: (state, getters, rootState) => {
|
||||
if (!state.streamLibraryItem) return false
|
||||
return state.streamLibraryItem.libraryId !== rootState.libraries.currentLibraryId
|
||||
},
|
||||
getIsMediaStreaming: state => (libraryItemId, episodeId) => {
|
||||
getIsMediaStreaming: (state) => (libraryItemId, episodeId) => {
|
||||
if (!state.streamLibraryItem) return null
|
||||
if (!episodeId) return state.streamLibraryItem.id == libraryItemId
|
||||
return state.streamLibraryItem.id == libraryItemId && state.streamEpisodeId == episodeId
|
||||
},
|
||||
getIsMediaQueued: state => (libraryItemId, episodeId) => {
|
||||
return state.playerQueueItems.some(i => {
|
||||
getIsMediaQueued: (state) => (libraryItemId, episodeId) => {
|
||||
return state.playerQueueItems.some((i) => {
|
||||
if (!episodeId) return i.libraryItemId === libraryItemId
|
||||
return i.libraryItemId === libraryItemId && i.episodeId === episodeId
|
||||
})
|
||||
},
|
||||
getBookshelfView: state => {
|
||||
getBookshelfView: (state) => {
|
||||
if (!state.serverSettings || isNaN(state.serverSettings.bookshelfView)) return Constants.BookshelfView.STANDARD
|
||||
return state.serverSettings.bookshelfView
|
||||
},
|
||||
getHomeBookshelfView: state => {
|
||||
getHomeBookshelfView: (state) => {
|
||||
if (!state.serverSettings || isNaN(state.serverSettings.homeBookshelfView)) return Constants.BookshelfView.STANDARD
|
||||
return state.serverSettings.homeBookshelfView
|
||||
}
|
||||
|
|
@ -69,17 +69,20 @@ export const actions = {
|
|||
const updatePayload = {
|
||||
...payload
|
||||
}
|
||||
return this.$axios.$patch('/api/settings', updatePayload).then((result) => {
|
||||
if (result.success) {
|
||||
commit('setServerSettings', result.serverSettings)
|
||||
return true
|
||||
} else {
|
||||
return this.$axios
|
||||
.$patch('/api/settings', updatePayload)
|
||||
.then((result) => {
|
||||
if (result.success) {
|
||||
commit('setServerSettings', result.serverSettings)
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to update server settings', error)
|
||||
return false
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('Failed to update server settings', error)
|
||||
return false
|
||||
})
|
||||
})
|
||||
},
|
||||
checkForUpdate({ commit }) {
|
||||
const VERSION_CHECK_BUFF = 1000 * 60 * 5 // 5 minutes
|
||||
|
|
@ -180,7 +183,7 @@ export const mutations = {
|
|||
})
|
||||
},
|
||||
addItemToQueue(state, item) {
|
||||
const exists = state.playerQueueItems.some(i => {
|
||||
const exists = state.playerQueueItems.some((i) => {
|
||||
if (!i.episodeId) return i.libraryItemId === item.libraryItemId
|
||||
return i.libraryItemId === item.libraryItemId && i.episodeId === item.episodeId
|
||||
})
|
||||
|
|
@ -235,5 +238,6 @@ export const mutations = {
|
|||
},
|
||||
setInnerModalOpen(state, val) {
|
||||
state.innerModalOpen = val
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue