mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Series order by volume number, show volume number, keyword filter, fix overflow bug
This commit is contained in:
		
							parent
							
								
									0d556c3f76
								
							
						
					
					
						commit
						68f534a97e
					
				@ -108,5 +108,5 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.box-shadow-side {
 | 
					.box-shadow-side {
 | 
				
			||||||
  box-shadow: 4px 0px 4px #11111166;
 | 
					  box-shadow: 5px 0px 5px #11111166;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div id="bookshelf" ref="wrapper" class="w-full h-full overflow-y-auto relative">
 | 
					  <div id="bookshelf" ref="wrapper" class="w-full h-full overflow-y-scroll relative">
 | 
				
			||||||
    <!-- Cover size widget -->
 | 
					    <!-- Cover size widget -->
 | 
				
			||||||
    <div v-show="!isSelectionMode" class="fixed bottom-2 right-4 z-20">
 | 
					    <div v-show="!isSelectionMode" class="fixed bottom-2 right-4 z-20">
 | 
				
			||||||
      <div class="rounded-full py-1 bg-primary px-2 border border-black-100 text-center flex items-center box-shadow-md" @mousedown.prevent @mouseup.prevent>
 | 
					      <div class="rounded-full py-1 bg-primary px-2 border border-black-100 text-center flex items-center box-shadow-md" @mousedown.prevent @mouseup.prevent>
 | 
				
			||||||
@ -23,7 +23,7 @@
 | 
				
			|||||||
            <template v-for="entity in shelf">
 | 
					            <template v-for="entity in shelf">
 | 
				
			||||||
              <cards-group-card v-if="showGroups" :key="entity.id" :width="bookCoverWidth" :group="entity" @click="clickGroup" />
 | 
					              <cards-group-card v-if="showGroups" :key="entity.id" :width="bookCoverWidth" :group="entity" @click="clickGroup" />
 | 
				
			||||||
              <!-- <cards-book-3d :key="entity.id" v-else :width="100" :src="$store.getters['audiobooks/getBookCoverSrc'](entity.book)" /> -->
 | 
					              <!-- <cards-book-3d :key="entity.id" v-else :width="100" :src="$store.getters['audiobooks/getBookCoverSrc'](entity.book)" /> -->
 | 
				
			||||||
              <cards-book-card v-else :key="entity.id" :width="bookCoverWidth" :user-progress="userAudiobooks[entity.id]" :audiobook="entity" />
 | 
					              <cards-book-card v-else :key="entity.id" :show-volume-number="selectedSeries" :width="bookCoverWidth" :user-progress="userAudiobooks[entity.id]" :audiobook="entity" />
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
          <div class="bookshelfDivider h-4 w-full absolute bottom-0 left-0 right-0 z-10" />
 | 
					          <div class="bookshelfDivider h-4 w-full absolute bottom-0 left-0 right-0 z-10" />
 | 
				
			||||||
@ -58,7 +58,8 @@ export default {
 | 
				
			|||||||
      selectedSizeIndex: 3,
 | 
					      selectedSizeIndex: 3,
 | 
				
			||||||
      rowPaddingX: 40,
 | 
					      rowPaddingX: 40,
 | 
				
			||||||
      keywordFilterTimeout: null,
 | 
					      keywordFilterTimeout: null,
 | 
				
			||||||
      scannerParseSubtitle: false
 | 
					      scannerParseSubtitle: false,
 | 
				
			||||||
 | 
					      wrapperClientWidth: 0
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  watch: {
 | 
					  watch: {
 | 
				
			||||||
@ -159,7 +160,8 @@ export default {
 | 
				
			|||||||
      this.$store.dispatch('user/updateUserSettings', { bookshelfCoverSize: this.bookCoverWidth })
 | 
					      this.$store.dispatch('user/updateUserSettings', { bookshelfCoverSize: this.bookCoverWidth })
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    setBookshelfEntities() {
 | 
					    setBookshelfEntities() {
 | 
				
			||||||
      var width = Math.max(0, this.$refs.wrapper.clientWidth - this.rowPaddingX * 2)
 | 
					      this.wrapperClientWidth = this.$refs.wrapper.clientWidth
 | 
				
			||||||
 | 
					      var width = Math.max(0, this.wrapperClientWidth - this.rowPaddingX * 2)
 | 
				
			||||||
      var booksPerRow = Math.floor(width / this.bookWidth)
 | 
					      var booksPerRow = Math.floor(width / this.bookWidth)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      var entities = this.entities
 | 
					      var entities = this.entities
 | 
				
			||||||
@ -182,6 +184,8 @@ export default {
 | 
				
			|||||||
      this.shelves = groups
 | 
					      this.shelves = groups
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    async init() {
 | 
					    async init() {
 | 
				
			||||||
 | 
					      this.wrapperClientWidth = this.$refs.wrapper ? this.$refs.wrapper.clientWidth : 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      var bookshelfCoverSize = this.$store.getters['user/getUserSetting']('bookshelfCoverSize')
 | 
					      var bookshelfCoverSize = this.$store.getters['user/getUserSetting']('bookshelfCoverSize')
 | 
				
			||||||
      var sizeIndex = this.availableSizes.findIndex((s) => s === bookshelfCoverSize)
 | 
					      var sizeIndex = this.availableSizes.findIndex((s) => s === bookshelfCoverSize)
 | 
				
			||||||
      if (!isNaN(sizeIndex)) this.selectedSizeIndex = sizeIndex
 | 
					      if (!isNaN(sizeIndex)) this.selectedSizeIndex = sizeIndex
 | 
				
			||||||
@ -192,9 +196,7 @@ export default {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    resize() {
 | 
					    resize() {
 | 
				
			||||||
      this.$nextTick(() => {
 | 
					      this.$nextTick(this.setBookshelfEntities)
 | 
				
			||||||
        this.setBookshelfEntities()
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    audiobooksUpdated() {
 | 
					    audiobooksUpdated() {
 | 
				
			||||||
      console.log('[AudioBookshelf] Audiobooks Updated')
 | 
					      console.log('[AudioBookshelf] Audiobooks Updated')
 | 
				
			||||||
@ -216,10 +218,18 @@ export default {
 | 
				
			|||||||
      this.$root.socket.emit('scan')
 | 
					      this.$root.socket.emit('scan')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  updated() {
 | 
				
			||||||
 | 
					    if (this.$refs.wrapper) {
 | 
				
			||||||
 | 
					      if (this.wrapperClientWidth !== this.$refs.wrapper.clientWidth) {
 | 
				
			||||||
 | 
					        this.$nextTick(this.setBookshelfEntities)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  mounted() {
 | 
					  mounted() {
 | 
				
			||||||
    window.addEventListener('resize', this.resize)
 | 
					    window.addEventListener('resize', this.resize)
 | 
				
			||||||
    this.$store.commit('audiobooks/addListener', { id: 'bookshelf', meth: this.audiobooksUpdated })
 | 
					    this.$store.commit('audiobooks/addListener', { id: 'bookshelf', meth: this.audiobooksUpdated })
 | 
				
			||||||
    this.$store.commit('user/addSettingsListener', { id: 'bookshelf', meth: this.settingsUpdated })
 | 
					    this.$store.commit('user/addSettingsListener', { id: 'bookshelf', meth: this.settingsUpdated })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.init()
 | 
					    this.init()
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  beforeDestroy() {
 | 
					  beforeDestroy() {
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div class="flex-grow" />
 | 
					        <div class="flex-grow" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <ui-text-input v-show="showSortFilters" v-model="_keywordFilter" placeholder="Keyword Filter" :padding-y="1.5" class="text-xs w-40" />
 | 
					        <ui-text-input v-show="!selectedSeries" v-model="_keywordFilter" placeholder="Keyword Filter" :padding-y="1.5" class="text-xs w-40" />
 | 
				
			||||||
        <controls-filter-select v-show="showSortFilters" v-model="settings.filterBy" class="w-48 h-7.5 ml-4" @change="updateFilter" />
 | 
					        <controls-filter-select v-show="showSortFilters" v-model="settings.filterBy" class="w-48 h-7.5 ml-4" @change="updateFilter" />
 | 
				
			||||||
        <controls-order-select v-show="showSortFilters" v-model="settings.orderBy" :descending.sync="settings.orderDesc" class="w-48 h-7.5 ml-4" @change="updateOrder" />
 | 
					        <controls-order-select v-show="showSortFilters" v-model="settings.orderBy" :descending.sync="settings.orderDesc" class="w-48 h-7.5 ml-4" @change="updateOrder" />
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
@ -121,6 +121,6 @@ export default {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<style>
 | 
					<style>
 | 
				
			||||||
#toolbar {
 | 
					#toolbar {
 | 
				
			||||||
  box-shadow: 0px 8px 8px #111111aa;
 | 
					  box-shadow: 0px 8px 6px #111111aa;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="w-20 border-r border-primary bg-bg h-full relative box-shadow-side z-40" style="min-width: 80px">
 | 
					  <div class="w-20 bg-bg h-full relative box-shadow-side z-20" style="min-width: 80px">
 | 
				
			||||||
 | 
					    <div class="absolute top-0 -right-4 w-4 bg-bg h-10 pointer-events-none" />
 | 
				
			||||||
    <nuxt-link to="/library" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === '' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
 | 
					    <nuxt-link to="/library" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === '' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
 | 
				
			||||||
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
 | 
					      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
 | 
				
			||||||
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
 | 
					        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
 | 
				
			||||||
 | 
				
			|||||||
@ -29,6 +29,10 @@
 | 
				
			|||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div v-if="volumeNumber && showVolumeNumber && !isHovering" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', padding: `${0.1 * sizeMultiplier}rem ${0.25 * sizeMultiplier}rem` }">
 | 
				
			||||||
 | 
					            <p :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }">#{{ volumeNumber }}</p>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <div v-show="!isSelectionMode" class="absolute bottom-0 left-0 h-1 shadow-sm max-w-full" :class="userIsRead ? 'bg-success' : 'bg-yellow-400'" :style="{ width: width * userProgressPercent + 'px' }"></div>
 | 
					          <div v-show="!isSelectionMode" class="absolute bottom-0 left-0 h-1 shadow-sm max-w-full" :class="userIsRead ? 'bg-success' : 'bg-yellow-400'" :style="{ width: width * userProgressPercent + 'px' }"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <ui-tooltip v-if="showError" :text="errorText" class="absolute bottom-4 left-0">
 | 
					          <ui-tooltip v-if="showError" :text="errorText" class="absolute bottom-4 left-0">
 | 
				
			||||||
@ -56,7 +60,8 @@ export default {
 | 
				
			|||||||
    width: {
 | 
					    width: {
 | 
				
			||||||
      type: Number,
 | 
					      type: Number,
 | 
				
			||||||
      default: 120
 | 
					      default: 120
 | 
				
			||||||
    }
 | 
					    },
 | 
				
			||||||
 | 
					    showVolumeNumber: Boolean
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  data() {
 | 
					  data() {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
 | 
				
			|||||||
@ -5,13 +5,16 @@
 | 
				
			|||||||
        <div class="w-full relative" :class="isHovering ? 'bg-black-400' : 'bg-primary'" :style="{ height: height + 'px', width: height + 'px' }">
 | 
					        <div class="w-full relative" :class="isHovering ? 'bg-black-400' : 'bg-primary'" :style="{ height: height + 'px', width: height + 'px' }">
 | 
				
			||||||
          <cards-group-cover ref="groupcover" :name="groupName" :book-items="bookItems" :width="height" :height="height" />
 | 
					          <cards-group-cover ref="groupcover" :name="groupName" :book-items="bookItems" :width="height" :height="height" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <div v-if="hasValidCovers" class="bg-black bg-opacity-60 absolute top-0 left-0 w-full h-full flex items-center justify-center text-center transition-opacity" :class="isHovering ? '' : 'opacity-0'">
 | 
					          <div v-if="hasValidCovers" class="bg-black bg-opacity-60 absolute top-0 left-0 w-full h-full flex items-center justify-center text-center transition-opacity" :class="isHovering ? '' : 'opacity-0'" :style="{ padding: `${sizeMultiplier}rem` }">
 | 
				
			||||||
            <p class="truncate font-book" :style="{ fontSize: sizeMultiplier + 'rem' }">{{ groupName }}</p>
 | 
					            <p class="font-book" :style="{ fontSize: sizeMultiplier + 'rem' }">{{ groupName }}</p>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <div class="absolute top-2 right-2 w-7 h-7 rounded-lg bg-black bg-opacity-90 text-gray-300 box-shadow-book flex items-center justify-center border border-white border-opacity-25 pointer-events-none">
 | 
					          <div class="absolute top-2 right-2 w-7 h-7 rounded-lg bg-black bg-opacity-90 text-gray-300 box-shadow-book flex items-center justify-center border border-white border-opacity-25 pointer-events-none">
 | 
				
			||||||
            <p class="font-book text-xl">{{ bookItems.length }}</p>
 | 
					            <p class="font-book text-xl">{{ bookItems.length }}</p>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="absolute bottom-0 left-0 w-full h-1 flex flex-nowrap">
 | 
				
			||||||
 | 
					            <div v-for="userProgress in userProgressItems" :key="userProgress.audiobookId" class="h-full w-full" :class="userProgress.isRead ? 'bg-success' : userProgress.progress > 0 ? 'bg-yellow-400' : ''" />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </nuxt-link>
 | 
					      </nuxt-link>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@ -60,6 +63,15 @@ export default {
 | 
				
			|||||||
    bookItems() {
 | 
					    bookItems() {
 | 
				
			||||||
      return this._group.books || []
 | 
					      return this._group.books || []
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    userAudiobooks() {
 | 
				
			||||||
 | 
					      return Object.values(this.$store.state.user.user ? this.$store.state.user.user.audiobooks || {} : {})
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    userProgressItems() {
 | 
				
			||||||
 | 
					      return this.bookItems.map((item) => {
 | 
				
			||||||
 | 
					        var userAudiobook = this.userAudiobooks.find((ab) => ab.audiobookId === item.id)
 | 
				
			||||||
 | 
					        return userAudiobook || {}
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    groupName() {
 | 
					    groupName() {
 | 
				
			||||||
      return this._group.name || 'No Name'
 | 
					      return this._group.name || 'No Name'
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -81,7 +93,6 @@ export default {
 | 
				
			|||||||
    clickCard() {
 | 
					    clickCard() {
 | 
				
			||||||
      this.$emit('click', this.group)
 | 
					      this.$emit('click', this.group)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  }
 | 
				
			||||||
  mounted() {}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div ref="wrapper" :style="{ height: height + 'px', width: width + 'px' }" class="relative">
 | 
					  <div ref="wrapper" :style="{ height: height + 'px', width: width + 'px' }" class="relative">
 | 
				
			||||||
    <div v-if="noValidCovers" class="absolute top-0 left-0 w-full h-full flex items-center justify-center box-shadow-book">
 | 
					    <div v-if="noValidCovers" class="absolute top-0 left-0 w-full h-full flex items-center justify-center box-shadow-book" :style="{ padding: `${sizeMultiplier}rem` }">
 | 
				
			||||||
      <p :style="{ fontSize: sizeMultiplier + 'rem' }">{{ name }}</p>
 | 
					      <p :style="{ fontSize: sizeMultiplier + 'rem' }">{{ name }}</p>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -26,6 +26,9 @@ export default {
 | 
				
			|||||||
      if (this.$store.state.selectedAudiobooks) {
 | 
					      if (this.$store.state.selectedAudiobooks) {
 | 
				
			||||||
        this.$store.commit('setSelectedAudiobooks', [])
 | 
					        this.$store.commit('setSelectedAudiobooks', [])
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      if (this.$store.state.audiobooks.keywordFilter) {
 | 
				
			||||||
 | 
					        this.$store.commit('audiobooks/setKeywordFilter', '')
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "audiobookshelf-client",
 | 
					  "name": "audiobookshelf-client",
 | 
				
			||||||
  "version": "1.2.3",
 | 
					  "version": "1.2.4",
 | 
				
			||||||
  "description": "Audiobook manager and player",
 | 
					  "description": "Audiobook manager and player",
 | 
				
			||||||
  "main": "index.js",
 | 
					  "main": "index.js",
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
 | 
				
			|||||||
@ -73,13 +73,23 @@ export const getters = {
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          series[audiobook.book.series] = {
 | 
					          series[audiobook.book.series] = {
 | 
				
			||||||
            type: 'series',
 | 
					            type: 'series',
 | 
				
			||||||
            name: audiobook.book.series,
 | 
					            name: audiobook.book.series || '',
 | 
				
			||||||
            books: [audiobook]
 | 
					            books: [audiobook]
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    return Object.values(series)
 | 
					    var seriesArray = Object.values(series).map((_series) => {
 | 
				
			||||||
 | 
					      _series.books = sort(_series.books)['asc']((ab) => {
 | 
				
			||||||
 | 
					        return ab.book && ab.book.volumeNumber && !isNaN(ab.book.volumeNumber) ? Number(ab.book.volumeNumber) : null
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      return _series
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    if (state.keywordFilter) {
 | 
				
			||||||
 | 
					      const keywordFilter = state.keywordFilter.toLowerCase()
 | 
				
			||||||
 | 
					      return seriesArray.filter((_series) => _series.name.toLowerCase().includes(keywordFilter))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return seriesArray
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  getUniqueAuthors: (state) => {
 | 
					  getUniqueAuthors: (state) => {
 | 
				
			||||||
    var _authors = state.audiobooks.filter(ab => !!(ab.book && ab.book.author)).map(ab => ab.book.author)
 | 
					    var _authors = state.audiobooks.filter(ab => !!(ab.book && ab.book.author)).map(ab => ab.book.author)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "audiobookshelf",
 | 
					  "name": "audiobookshelf",
 | 
				
			||||||
  "version": "1.2.3",
 | 
					  "version": "1.2.4",
 | 
				
			||||||
  "description": "Self-hosted audiobook server for managing and playing audiobooks",
 | 
					  "description": "Self-hosted audiobook server for managing and playing audiobooks",
 | 
				
			||||||
  "main": "index.js",
 | 
					  "main": "index.js",
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user