mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-11-03 19:07:00 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			576 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			576 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						|
  <div class="text-white max-h-screen h-screen overflow-hidden bg-bg">
 | 
						|
    <app-appbar />
 | 
						|
 | 
						|
    <app-side-rail v-if="isShowingSideRail" class="hidden md:block" />
 | 
						|
    <div id="app-content" class="h-full" :class="{ 'has-siderail': isShowingSideRail }">
 | 
						|
      <Nuxt />
 | 
						|
    </div>
 | 
						|
 | 
						|
    <app-stream-container ref="streamContainer" />
 | 
						|
 | 
						|
    <modals-item-edit-modal />
 | 
						|
    <modals-user-collections-modal />
 | 
						|
    <modals-edit-collection-modal />
 | 
						|
    <modals-podcast-edit-episode />
 | 
						|
    <modals-podcast-view-episode />
 | 
						|
    <modals-authors-edit-modal />
 | 
						|
    <readers-reader />
 | 
						|
  </div>
 | 
						|
</template>
 | 
						|
 | 
						|
<script>
 | 
						|
import CloseButton from '@/components/widgets/CloseButton'
 | 
						|
 | 
						|
export default {
 | 
						|
  middleware: 'authenticated',
 | 
						|
  data() {
 | 
						|
    return {
 | 
						|
      socket: null,
 | 
						|
      isSocketConnected: false,
 | 
						|
      isFirstSocketConnection: true,
 | 
						|
      socketConnectionToastId: null
 | 
						|
    }
 | 
						|
  },
 | 
						|
  watch: {
 | 
						|
    $route(newVal) {
 | 
						|
      if (this.$store.state.showEditModal) {
 | 
						|
        this.$store.commit('setShowEditModal', false)
 | 
						|
      }
 | 
						|
      if (this.$store.state.selectedLibraryItems) {
 | 
						|
        this.$store.commit('setSelectedLibraryItems', [])
 | 
						|
      }
 | 
						|
    }
 | 
						|
  },
 | 
						|
  computed: {
 | 
						|
    user() {
 | 
						|
      return this.$store.state.user.user
 | 
						|
    },
 | 
						|
    isCasting() {
 | 
						|
      return this.$store.state.globals.isCasting
 | 
						|
    },
 | 
						|
    isShowingSideRail() {
 | 
						|
      if (!this.$route.name) return false
 | 
						|
      return !this.$route.name.startsWith('config') && this.$store.state.libraries.currentLibraryId
 | 
						|
    },
 | 
						|
    appContentMarginLeft() {
 | 
						|
      return this.isShowingSideRail ? 80 : 0
 | 
						|
    }
 | 
						|
  },
 | 
						|
  methods: {
 | 
						|
    updateSocketConnectionToast(content, type, timeout) {
 | 
						|
      if (this.socketConnectionToastId !== null && this.socketConnectionToastId !== undefined) {
 | 
						|
        this.$toast.update(this.socketConnectionToastId, { content: content, options: { timeout: timeout, type: type, closeButton: false, position: 'bottom-center', onClose: () => null, closeOnClick: timeout !== null } }, false)
 | 
						|
      } else {
 | 
						|
        this.socketConnectionToastId = this.$toast[type](content, { position: 'bottom-center', timeout: timeout, closeButton: false, closeOnClick: timeout !== null })
 | 
						|
      }
 | 
						|
    },
 | 
						|
    connect() {
 | 
						|
      console.log('[SOCKET] Connected')
 | 
						|
      var token = this.$store.getters['user/getToken']
 | 
						|
      this.socket.emit('auth', token)
 | 
						|
 | 
						|
      if (!this.isFirstSocketConnection || this.socketConnectionToastId !== null) {
 | 
						|
        this.updateSocketConnectionToast('Socket Connected', 'success', 5000)
 | 
						|
      }
 | 
						|
      this.isFirstSocketConnection = false
 | 
						|
      this.isSocketConnected = true
 | 
						|
    },
 | 
						|
    connectError() {
 | 
						|
      console.error('[SOCKET] connect error')
 | 
						|
      this.updateSocketConnectionToast('Socket Failed to Connect', 'error', null)
 | 
						|
    },
 | 
						|
    disconnect() {
 | 
						|
      console.log('[SOCKET] Disconnected')
 | 
						|
      this.isSocketConnected = false
 | 
						|
      this.updateSocketConnectionToast('Socket Disconnected', 'error', null)
 | 
						|
    },
 | 
						|
    reconnect() {
 | 
						|
      console.error('[SOCKET] reconnected')
 | 
						|
    },
 | 
						|
    reconnectAttempt(val) {
 | 
						|
      console.log(`[SOCKET] reconnect attempt ${val}`)
 | 
						|
    },
 | 
						|
    reconnectError() {
 | 
						|
      // console.error('[SOCKET] reconnect error')
 | 
						|
    },
 | 
						|
    reconnectFailed() {
 | 
						|
      console.error('[SOCKET] reconnect failed')
 | 
						|
    },
 | 
						|
    init(payload, count = 0) {
 | 
						|
      if (!this.$refs.streamContainer) {
 | 
						|
        if (count > 20) {
 | 
						|
          console.error('Stream container never mounted')
 | 
						|
          return
 | 
						|
        }
 | 
						|
        setTimeout(() => {
 | 
						|
          this.init(payload, ++count)
 | 
						|
        }, 100)
 | 
						|
        return
 | 
						|
      }
 | 
						|
      console.log('Init Payload', payload)
 | 
						|
      if (payload.session) {
 | 
						|
        if (this.$refs.streamContainer) {
 | 
						|
          this.$refs.streamContainer.sessionOpen(payload.session)
 | 
						|
        } else {
 | 
						|
          console.warn('Stream Container not mounted')
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (payload.serverSettings) {
 | 
						|
      }
 | 
						|
 | 
						|
      // Start scans currently running
 | 
						|
      if (payload.librariesScanning) {
 | 
						|
        payload.librariesScanning.forEach((libraryScan) => {
 | 
						|
          this.scanStart(libraryScan)
 | 
						|
        })
 | 
						|
      }
 | 
						|
 | 
						|
      // Remove any current scans that are no longer running
 | 
						|
      var currentScans = [...this.$store.state.scanners.libraryScans]
 | 
						|
      currentScans.forEach((ls) => {
 | 
						|
        if (!payload.librariesScanning || !payload.librariesScanning.find((_ls) => _ls.id === ls.id)) {
 | 
						|
          this.$toast.dismiss(ls.toastId)
 | 
						|
          this.$store.commit('scanners/remove', ls)
 | 
						|
        }
 | 
						|
      })
 | 
						|
 | 
						|
      if (payload.backups && payload.backups.length) {
 | 
						|
        this.$store.commit('setBackups', payload.backups)
 | 
						|
      }
 | 
						|
      if (payload.usersOnline) {
 | 
						|
        this.$store.commit('users/resetUsers')
 | 
						|
        payload.usersOnline.forEach((user) => {
 | 
						|
          this.$store.commit('users/updateUser', user)
 | 
						|
        })
 | 
						|
      }
 | 
						|
 | 
						|
      this.$eventBus.$emit('socket_init')
 | 
						|
    },
 | 
						|
    streamOpen(stream) {
 | 
						|
      if (this.$refs.streamContainer) this.$refs.streamContainer.streamOpen(stream)
 | 
						|
    },
 | 
						|
    streamClosed(streamId) {
 | 
						|
      if (this.$refs.streamContainer) this.$refs.streamContainer.streamClosed(streamId)
 | 
						|
    },
 | 
						|
    streamProgress(data) {
 | 
						|
      if (this.$refs.streamContainer) this.$refs.streamContainer.streamProgress(data)
 | 
						|
    },
 | 
						|
    streamReady() {
 | 
						|
      if (this.$refs.streamContainer) this.$refs.streamContainer.streamReady()
 | 
						|
    },
 | 
						|
    streamReset(payload) {
 | 
						|
      if (this.$refs.streamContainer) this.$refs.streamContainer.streamReset(payload)
 | 
						|
    },
 | 
						|
    streamError({ id, errorMessage }) {
 | 
						|
      this.$toast.error(`Stream Failed: ${errorMessage}`)
 | 
						|
      if (this.$refs.streamContainer) this.$refs.streamContainer.streamError(id)
 | 
						|
    },
 | 
						|
    libraryAdded(library) {
 | 
						|
      this.$store.commit('libraries/addUpdate', library)
 | 
						|
    },
 | 
						|
    libraryUpdated(library) {
 | 
						|
      this.$store.commit('libraries/addUpdate', library)
 | 
						|
    },
 | 
						|
    async libraryRemoved(library) {
 | 
						|
      console.log('Library removed', library)
 | 
						|
      this.$store.commit('libraries/remove', library)
 | 
						|
 | 
						|
      // When removed currently selected library then set next accessible library
 | 
						|
      const currLibraryId = this.$store.state.libraries.currentLibraryId
 | 
						|
      if (currLibraryId === library.id) {
 | 
						|
        var nextLibrary = this.$store.getters['libraries/getNextAccessibleLibrary']
 | 
						|
        if (nextLibrary) {
 | 
						|
          await this.$store.dispatch('libraries/fetch', nextLibrary.id)
 | 
						|
 | 
						|
          if (this.$route.name.startsWith('config')) {
 | 
						|
            // No need to refresh
 | 
						|
          } else if (this.$route.name.startsWith('library')) {
 | 
						|
            var newRoute = this.$route.path.replace(currLibraryId, nextLibrary.id)
 | 
						|
            this.$router.push(newRoute)
 | 
						|
          } else {
 | 
						|
            this.$router.push(`/library/${nextLibrary.id}`)
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          console.error('User has no more accessible libraries')
 | 
						|
          this.$store.commit('libraries/setCurrentLibrary', null)
 | 
						|
        }
 | 
						|
      }
 | 
						|
    },
 | 
						|
    libraryItemAdded(libraryItem) {
 | 
						|
      this.$store.commit('libraries/updateFilterDataWithItem', libraryItem)
 | 
						|
    },
 | 
						|
    libraryItemUpdated(libraryItem) {
 | 
						|
      if (this.$store.state.selectedLibraryItem && this.$store.state.selectedLibraryItem.id === libraryItem.id) {
 | 
						|
        this.$store.commit('setSelectedLibraryItem', libraryItem)
 | 
						|
      }
 | 
						|
      this.$eventBus.$emit(`${libraryItem.id}_updated`, libraryItem)
 | 
						|
      this.$store.commit('libraries/updateFilterDataWithItem', libraryItem)
 | 
						|
    },
 | 
						|
    libraryItemRemoved(item) {
 | 
						|
      if (this.$route.name.startsWith('item')) {
 | 
						|
        if (this.$route.params.id === item.id) {
 | 
						|
          this.$router.replace(`/library/${this.$store.state.libraries.currentLibraryId}`)
 | 
						|
        }
 | 
						|
      }
 | 
						|
    },
 | 
						|
    libraryItemsUpdated(libraryItems) {
 | 
						|
      libraryItems.forEach((li) => {
 | 
						|
        this.libraryItemUpdated(li)
 | 
						|
      })
 | 
						|
    },
 | 
						|
    libraryItemsAdded(libraryItems) {
 | 
						|
      libraryItems.forEach((ab) => {
 | 
						|
        this.libraryItemAdded(ab)
 | 
						|
      })
 | 
						|
    },
 | 
						|
    scanComplete(data) {
 | 
						|
      console.log('Scan complete received', data)
 | 
						|
 | 
						|
      var message = `${data.type === 'match' ? 'Match' : 'Scan'} "${data.name}" complete!`
 | 
						|
      if (data.results) {
 | 
						|
        var scanResultMsgs = []
 | 
						|
        var results = data.results
 | 
						|
        if (results.added) scanResultMsgs.push(`${results.added} added`)
 | 
						|
        if (results.updated) scanResultMsgs.push(`${results.updated} updated`)
 | 
						|
        if (results.removed) scanResultMsgs.push(`${results.removed} removed`)
 | 
						|
        if (results.missing) scanResultMsgs.push(`${results.missing} missing`)
 | 
						|
        if (!scanResultMsgs.length) message += '\nEverything was up to date'
 | 
						|
        else message += '\n' + scanResultMsgs.join('\n')
 | 
						|
      } else {
 | 
						|
        message = `${data.type === 'match' ? 'Match' : 'Scan'} "${data.name}" was canceled`
 | 
						|
      }
 | 
						|
 | 
						|
      var existingScan = this.$store.getters['scanners/getLibraryScan'](data.id)
 | 
						|
      if (existingScan && !isNaN(existingScan.toastId)) {
 | 
						|
        this.$toast.update(existingScan.toastId, { content: message, options: { timeout: 5000, type: 'success', closeButton: false, position: 'bottom-center', onClose: () => null } }, true)
 | 
						|
      } else {
 | 
						|
        this.$toast.success(message, { timeout: 5000, position: 'bottom-center' })
 | 
						|
      }
 | 
						|
 | 
						|
      this.$store.commit('scanners/remove', data)
 | 
						|
    },
 | 
						|
    onScanToastCancel(id) {
 | 
						|
      this.$root.socket.emit('cancel_scan', id)
 | 
						|
    },
 | 
						|
    scanStart(data) {
 | 
						|
      data.toastId = this.$toast(`${data.type === 'match' ? 'Matching' : 'Scanning'} "${data.name}"...`, { timeout: false, type: 'info', draggable: false, closeOnClick: false, closeButton: CloseButton, closeButtonClassName: 'cancel-scan-btn', showCloseButtonOnHover: false, position: 'bottom-center', onClose: () => this.onScanToastCancel(data.id) })
 | 
						|
      this.$store.commit('scanners/addUpdate', data)
 | 
						|
    },
 | 
						|
    scanProgress(data) {
 | 
						|
      var existingScan = this.$store.getters['scanners/getLibraryScan'](data.id)
 | 
						|
      if (existingScan && !isNaN(existingScan.toastId)) {
 | 
						|
        data.toastId = existingScan.toastId
 | 
						|
        this.$toast.update(existingScan.toastId, { content: `Scanning "${existingScan.name}"... ${data.progress.progress || 0}%`, options: { timeout: false } }, true)
 | 
						|
      } else {
 | 
						|
        data.toastId = this.$toast(`Scanning "${data.name}"...`, { timeout: false, type: 'info', draggable: false, closeOnClick: false, closeButton: CloseButton, closeButtonClassName: 'cancel-scan-btn', showCloseButtonOnHover: false, position: 'bottom-center', onClose: () => this.onScanToastCancel(data.id) })
 | 
						|
      }
 | 
						|
 | 
						|
      this.$store.commit('scanners/addUpdate', data)
 | 
						|
    },
 | 
						|
    userUpdated(user) {
 | 
						|
      if (this.$store.state.user.user.id === user.id) {
 | 
						|
        this.$store.commit('user/setUser', user)
 | 
						|
        this.$store.commit('user/setSettings', user.settings)
 | 
						|
      }
 | 
						|
    },
 | 
						|
    userOnline(user) {
 | 
						|
      this.$store.commit('users/updateUser', user)
 | 
						|
    },
 | 
						|
    userOffline(user) {
 | 
						|
      this.$store.commit('users/removeUser', user)
 | 
						|
    },
 | 
						|
    userStreamUpdate(user) {
 | 
						|
      this.$store.commit('users/updateUser', user)
 | 
						|
    },
 | 
						|
    userMediaProgressUpdate(payload) {
 | 
						|
      this.$store.commit('user/updateMediaProgress', payload)
 | 
						|
    },
 | 
						|
    collectionAdded(collection) {
 | 
						|
      this.$store.commit('user/addUpdateCollection', collection)
 | 
						|
    },
 | 
						|
    collectionUpdated(collection) {
 | 
						|
      this.$store.commit('user/addUpdateCollection', collection)
 | 
						|
    },
 | 
						|
    collectionRemoved(collection) {
 | 
						|
      if (this.$route.name.startsWith('collection')) {
 | 
						|
        if (this.$route.params.id === collection.id) {
 | 
						|
          this.$router.replace(`/library/${this.$store.state.libraries.currentLibraryId}/bookshelf/collections`)
 | 
						|
        }
 | 
						|
      }
 | 
						|
      this.$store.commit('user/removeCollection', collection)
 | 
						|
    },
 | 
						|
    abmergeStarted(download) {
 | 
						|
      download.status = this.$constants.DownloadStatus.PENDING
 | 
						|
      download.toastId = this.$toast(`Preparing download "${download.filename}"`, { timeout: false, draggable: false, closeOnClick: false })
 | 
						|
      this.$store.commit('downloads/addUpdateDownload', download)
 | 
						|
    },
 | 
						|
    abmergeReady(download) {
 | 
						|
      download.status = this.$constants.DownloadStatus.READY
 | 
						|
      var existingDownload = this.$store.getters['downloads/getDownload'](download.id)
 | 
						|
 | 
						|
      if (existingDownload && existingDownload.toastId !== undefined) {
 | 
						|
        download.toastId = existingDownload.toastId
 | 
						|
        this.$toast.update(existingDownload.toastId, { content: `Download "${download.filename}" is ready!`, options: { timeout: 5000, type: 'success' } }, true)
 | 
						|
      } else {
 | 
						|
        this.$toast.success(`Download "${download.filename}" is ready!`)
 | 
						|
      }
 | 
						|
      this.$store.commit('downloads/addUpdateDownload', download)
 | 
						|
    },
 | 
						|
    abmergeFailed(download) {
 | 
						|
      download.status = this.$constants.DownloadStatus.FAILED
 | 
						|
      var existingDownload = this.$store.getters['downloads/getDownload'](download.id)
 | 
						|
 | 
						|
      var failedMsg = download.isTimedOut ? 'timed out' : 'failed'
 | 
						|
 | 
						|
      if (existingDownload && existingDownload.toastId !== undefined) {
 | 
						|
        download.toastId = existingDownload.toastId
 | 
						|
        this.$toast.update(existingDownload.toastId, { content: `Download "${download.filename}" ${failedMsg}`, options: { timeout: 5000, type: 'error' } }, true)
 | 
						|
      } else {
 | 
						|
        console.warn('Download failed no existing download', existingDownload)
 | 
						|
        this.$toast.error(`Download "${download.filename}" ${failedMsg}`)
 | 
						|
      }
 | 
						|
      this.$store.commit('downloads/addUpdateDownload', download)
 | 
						|
    },
 | 
						|
    abmergeKilled(download) {
 | 
						|
      var existingDownload = this.$store.getters['downloads/getDownload'](download.id)
 | 
						|
      if (existingDownload && existingDownload.toastId !== undefined) {
 | 
						|
        download.toastId = existingDownload.toastId
 | 
						|
        this.$toast.update(existingDownload.toastId, { content: `Download "${download.filename}" was terminated`, options: { timeout: 5000, type: 'error' } }, true)
 | 
						|
      } else {
 | 
						|
        console.warn('Download killed no existing download found', existingDownload)
 | 
						|
        this.$toast.error(`Download "${download.filename}" was terminated`)
 | 
						|
      }
 | 
						|
      this.$store.commit('downloads/removeDownload', download)
 | 
						|
    },
 | 
						|
    abmergeExpired(download) {
 | 
						|
      download.status = this.$constants.DownloadStatus.EXPIRED
 | 
						|
      this.$store.commit('downloads/addUpdateDownload', download)
 | 
						|
    },
 | 
						|
    showErrorToast(message) {
 | 
						|
      this.$toast.error(message)
 | 
						|
    },
 | 
						|
    showSuccessToast(message) {
 | 
						|
      this.$toast.success(message)
 | 
						|
    },
 | 
						|
    backupApplied() {
 | 
						|
      // Force refresh
 | 
						|
      location.reload()
 | 
						|
    },
 | 
						|
    initializeSocket() {
 | 
						|
      this.socket = this.$nuxtSocket({
 | 
						|
        name: process.env.NODE_ENV === 'development' ? 'dev' : 'prod',
 | 
						|
        persist: 'main',
 | 
						|
        teardown: false,
 | 
						|
        transports: ['websocket'],
 | 
						|
        upgrade: false,
 | 
						|
        reconnection: true
 | 
						|
      })
 | 
						|
      this.$root.socket = this.socket
 | 
						|
      console.log('Socket initialized')
 | 
						|
 | 
						|
      this.socket.on('connect', this.connect)
 | 
						|
      this.socket.on('connect_error', this.connectError)
 | 
						|
      this.socket.on('disconnect', this.disconnect)
 | 
						|
      this.socket.io.on('reconnect_attempt', this.reconnectAttempt)
 | 
						|
      this.socket.io.on('reconnect', this.reconnect)
 | 
						|
      this.socket.io.on('reconnect_error', this.reconnectError)
 | 
						|
      this.socket.io.on('reconnect_failed', this.reconnectFailed)
 | 
						|
 | 
						|
      this.socket.on('init', this.init)
 | 
						|
 | 
						|
      // Stream Listeners
 | 
						|
      this.socket.on('stream_open', this.streamOpen)
 | 
						|
      this.socket.on('stream_closed', this.streamClosed)
 | 
						|
      this.socket.on('stream_progress', this.streamProgress)
 | 
						|
      this.socket.on('stream_ready', this.streamReady)
 | 
						|
      this.socket.on('stream_reset', this.streamReset)
 | 
						|
      this.socket.on('stream_error', this.streamError)
 | 
						|
 | 
						|
      // Library Listeners
 | 
						|
      this.socket.on('library_updated', this.libraryUpdated)
 | 
						|
      this.socket.on('library_added', this.libraryAdded)
 | 
						|
      this.socket.on('library_removed', this.libraryRemoved)
 | 
						|
 | 
						|
      // Library Item Listeners
 | 
						|
      this.socket.on('item_added', this.libraryItemAdded)
 | 
						|
      this.socket.on('item_updated', this.libraryItemUpdated)
 | 
						|
      this.socket.on('item_removed', this.libraryItemRemoved)
 | 
						|
      this.socket.on('items_updated', this.libraryItemsUpdated)
 | 
						|
      this.socket.on('items_added', this.libraryItemsAdded)
 | 
						|
 | 
						|
      // User Listeners
 | 
						|
      this.socket.on('user_updated', this.userUpdated)
 | 
						|
      this.socket.on('user_online', this.userOnline)
 | 
						|
      this.socket.on('user_offline', this.userOffline)
 | 
						|
      this.socket.on('user_stream_update', this.userStreamUpdate)
 | 
						|
      this.socket.on('user_item_progress_updated', this.userMediaProgressUpdate)
 | 
						|
 | 
						|
      // User Collection Listeners
 | 
						|
      this.socket.on('collection_added', this.collectionAdded)
 | 
						|
      this.socket.on('collection_updated', this.collectionUpdated)
 | 
						|
      this.socket.on('collection_removed', this.collectionRemoved)
 | 
						|
 | 
						|
      // Scan Listeners
 | 
						|
      this.socket.on('scan_start', this.scanStart)
 | 
						|
      this.socket.on('scan_complete', this.scanComplete)
 | 
						|
      this.socket.on('scan_progress', this.scanProgress)
 | 
						|
 | 
						|
      // Download Listeners
 | 
						|
      this.socket.on('abmerge_started', this.abmergeStarted)
 | 
						|
      this.socket.on('abmerge_ready', this.abmergeReady)
 | 
						|
      this.socket.on('abmerge_failed', this.abmergeFailed)
 | 
						|
      this.socket.on('abmerge_killed', this.abmergeKilled)
 | 
						|
      this.socket.on('abmerge_expired', this.abmergeExpired)
 | 
						|
 | 
						|
      // Toast Listeners
 | 
						|
      this.socket.on('show_error_toast', this.showErrorToast)
 | 
						|
      this.socket.on('show_success_toast', this.showSuccessToast)
 | 
						|
 | 
						|
      this.socket.on('backup_applied', this.backupApplied)
 | 
						|
    },
 | 
						|
    showUpdateToast(versionData) {
 | 
						|
      var ignoreVersion = localStorage.getItem('ignoreVersion')
 | 
						|
      var latestVersion = versionData.latestVersion
 | 
						|
 | 
						|
      if (!ignoreVersion || ignoreVersion !== latestVersion) {
 | 
						|
        this.$toast.info(`Update is available!\nCheck release notes for v${versionData.latestVersion}`, {
 | 
						|
          position: 'top-center',
 | 
						|
          toastClassName: 'cursor-pointer',
 | 
						|
          bodyClassName: 'custom-class-1',
 | 
						|
          timeout: 20000,
 | 
						|
          closeOnClick: false,
 | 
						|
          draggable: false,
 | 
						|
          hideProgressBar: false,
 | 
						|
          onClick: () => {
 | 
						|
            window.open(versionData.githubTagUrl, '_blank')
 | 
						|
          },
 | 
						|
          onClose: () => {
 | 
						|
            localStorage.setItem('ignoreVersion', versionData.latestVersion)
 | 
						|
          }
 | 
						|
        })
 | 
						|
      } else {
 | 
						|
        console.warn(`Update is available but user chose to dismiss it! v${versionData.latestVersion}`)
 | 
						|
      }
 | 
						|
    },
 | 
						|
    checkActiveElementIsInput() {
 | 
						|
      var activeElement = document.activeElement
 | 
						|
      var inputs = ['input', 'select', 'button', 'textarea']
 | 
						|
      return activeElement && inputs.indexOf(activeElement.tagName.toLowerCase()) !== -1
 | 
						|
    },
 | 
						|
    getHotkeyName(e) {
 | 
						|
      var keyCode = e.keyCode || e.which
 | 
						|
      if (!this.$keynames[keyCode]) {
 | 
						|
        // Unused hotkey
 | 
						|
        return null
 | 
						|
      }
 | 
						|
 | 
						|
      var keyName = this.$keynames[keyCode]
 | 
						|
      var name = keyName
 | 
						|
      if (e.shiftKey) name = 'Shift-' + keyName
 | 
						|
      if (process.env.NODE_ENV !== 'production') {
 | 
						|
        console.log('Hotkey command', name)
 | 
						|
      }
 | 
						|
      return name
 | 
						|
    },
 | 
						|
    keyDown(e) {
 | 
						|
      var name = this.getHotkeyName(e)
 | 
						|
      if (!name) return
 | 
						|
 | 
						|
      // Input is focused then ignore key press
 | 
						|
      if (this.checkActiveElementIsInput()) {
 | 
						|
        return
 | 
						|
      }
 | 
						|
 | 
						|
      // Modal is open
 | 
						|
      if (this.$store.state.openModal && Object.values(this.$hotkeys.Modal).includes(name)) {
 | 
						|
        this.$eventBus.$emit('modal-hotkey', name)
 | 
						|
        e.preventDefault()
 | 
						|
        return
 | 
						|
      }
 | 
						|
 | 
						|
      // EReader is open
 | 
						|
      if (this.$store.state.showEReader && Object.values(this.$hotkeys.EReader).includes(name)) {
 | 
						|
        this.$eventBus.$emit('reader-hotkey', name)
 | 
						|
        e.preventDefault()
 | 
						|
        return
 | 
						|
      }
 | 
						|
 | 
						|
      // Batch selecting
 | 
						|
      if (this.$store.getters['getNumLibraryItemsSelected'] && name === 'Escape') {
 | 
						|
        // ESCAPE key cancels batch selection
 | 
						|
        this.$store.commit('setSelectedLibraryItems', [])
 | 
						|
        this.$eventBus.$emit('bookshelf-clear-selection')
 | 
						|
        e.preventDefault()
 | 
						|
        return
 | 
						|
      }
 | 
						|
 | 
						|
      // Playing audiobook
 | 
						|
      if (this.$store.state.streamLibraryItem && Object.values(this.$hotkeys.AudioPlayer).includes(name)) {
 | 
						|
        this.$eventBus.$emit('player-hotkey', name)
 | 
						|
        e.preventDefault()
 | 
						|
      }
 | 
						|
    },
 | 
						|
    resize() {
 | 
						|
      this.$store.commit('globals/updateWindowSize', { width: window.innerWidth, height: window.innerHeight })
 | 
						|
    },
 | 
						|
    checkVersionUpdate() {
 | 
						|
      this.$store
 | 
						|
        .dispatch('checkForUpdate')
 | 
						|
        .then((res) => {
 | 
						|
          if (res && res.hasUpdate) this.showUpdateToast(res)
 | 
						|
        })
 | 
						|
        .catch((err) => console.error(err))
 | 
						|
    }
 | 
						|
  },
 | 
						|
  beforeMount() {
 | 
						|
    this.initializeSocket()
 | 
						|
  },
 | 
						|
  mounted() {
 | 
						|
    this.resize()
 | 
						|
    window.addEventListener('resize', this.resize)
 | 
						|
    window.addEventListener('keydown', this.keyDown)
 | 
						|
 | 
						|
    this.$store.dispatch('libraries/load')
 | 
						|
 | 
						|
    // If experimental features set in local storage
 | 
						|
    var experimentalFeaturesSaved = localStorage.getItem('experimental')
 | 
						|
    if (experimentalFeaturesSaved === '1') {
 | 
						|
      this.$store.commit('setExperimentalFeatures', true)
 | 
						|
    }
 | 
						|
 | 
						|
    this.checkVersionUpdate()
 | 
						|
 | 
						|
    if (this.$route.query.error) {
 | 
						|
      this.$toast.error(this.$route.query.error)
 | 
						|
      this.$router.replace(this.$route.path)
 | 
						|
    }
 | 
						|
  },
 | 
						|
  beforeDestroy() {
 | 
						|
    window.removeEventListener('resize', this.resize)
 | 
						|
    window.removeEventListener('keydown', this.keyDown)
 | 
						|
  }
 | 
						|
}
 | 
						|
</script>
 | 
						|
 | 
						|
<style>
 | 
						|
.Vue-Toastification__toast-body.custom-class-1 {
 | 
						|
  font-size: 14px;
 | 
						|
}
 | 
						|
 | 
						|
#app-content {
 | 
						|
  width: 100%;
 | 
						|
}
 | 
						|
#app-content.has-siderail {
 | 
						|
  width: calc(100% - 80px);
 | 
						|
  max-width: calc(100% - 80px);
 | 
						|
  margin-left: 80px;
 | 
						|
}
 | 
						|
@media (max-width: 768px) {
 | 
						|
  #app-content.has-siderail {
 | 
						|
    width: 100%;
 | 
						|
    max-width: 100%;
 | 
						|
    margin-left: 0px;
 | 
						|
  }
 | 
						|
}
 | 
						|
</style> |