2021-09-28 13:44:40 +02:00
|
|
|
<template>
|
|
|
|
<div id="bookshelf" ref="wrapper" class="w-full h-full overflow-y-scroll relative">
|
|
|
|
<!-- Cover size widget -->
|
2021-12-02 02:07:03 +01:00
|
|
|
<widgets-cover-size-widget class="fixed bottom-4 right-4 z-30" />
|
2021-11-28 03:11:35 +01:00
|
|
|
<!-- Experimental Bookshelf Texture -->
|
|
|
|
<div v-show="showExperimentalFeatures" class="fixed bottom-4 right-28 z-40">
|
|
|
|
<div class="rounded-full py-1 bg-primary hover:bg-bg cursor-pointer px-2 border border-black-100 text-center flex items-center box-shadow-md" @mousedown.prevent @mouseup.prevent @click="showBookshelfTextureModal"><p class="text-sm py-0.5">Texture</p></div>
|
|
|
|
</div>
|
2021-09-28 13:44:40 +02:00
|
|
|
|
2021-12-02 02:07:03 +01:00
|
|
|
<div v-if="loaded && !shelves.length && isRootUser" class="w-full flex flex-col items-center justify-center py-12">
|
|
|
|
<p class="text-center text-2xl font-book mb-4 py-4">Audiobookshelf is empty!</p>
|
2021-09-28 13:44:40 +02:00
|
|
|
<div class="flex">
|
2021-12-02 02:07:03 +01:00
|
|
|
<ui-btn to="/config" color="primary" class="w-52 mr-2">Configure Scanner</ui-btn>
|
2021-09-28 13:44:40 +02:00
|
|
|
<ui-btn color="success" class="w-52" @click="scan">Scan Audiobooks</ui-btn>
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-11-04 23:35:59 +01:00
|
|
|
<div v-else class="w-full flex flex-col items-center">
|
2021-09-28 13:44:40 +02:00
|
|
|
<template v-for="(shelf, index) in shelves">
|
2021-12-02 22:49:03 +01:00
|
|
|
<app-book-shelf-row :key="index" :index="index" :shelf="shelf" :size-multiplier="sizeMultiplier" :book-cover-width="bookCoverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" />
|
2021-09-28 13:44:40 +02:00
|
|
|
</template>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
export default {
|
2021-12-01 03:02:40 +01:00
|
|
|
props: {
|
|
|
|
search: Boolean,
|
|
|
|
results: {
|
|
|
|
type: Object,
|
|
|
|
default: () => {}
|
|
|
|
}
|
|
|
|
},
|
2021-09-28 13:44:40 +02:00
|
|
|
data() {
|
|
|
|
return {
|
2021-12-01 03:02:40 +01:00
|
|
|
loaded: false,
|
2021-09-28 13:44:40 +02:00
|
|
|
keywordFilterTimeout: null,
|
|
|
|
scannerParseSubtitle: false,
|
2021-09-29 00:36:41 +02:00
|
|
|
wrapperClientWidth: 0,
|
2021-12-01 03:02:40 +01:00
|
|
|
shelves: []
|
2021-09-28 13:44:40 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: {
|
2021-12-02 02:07:03 +01:00
|
|
|
isRootUser() {
|
|
|
|
return this.$store.getters['user/getIsRoot']
|
|
|
|
},
|
2021-11-28 03:11:35 +01:00
|
|
|
showExperimentalFeatures() {
|
|
|
|
return this.$store.state.showExperimentalFeatures
|
|
|
|
},
|
2021-12-01 03:02:40 +01:00
|
|
|
currentLibraryId() {
|
|
|
|
return this.$store.state.libraries.currentLibraryId
|
2021-09-28 13:44:40 +02:00
|
|
|
},
|
|
|
|
bookCoverWidth() {
|
2021-12-02 22:49:03 +01:00
|
|
|
var coverSize = this.$store.getters['user/getUserSetting']('bookshelfCoverSize')
|
|
|
|
if (this.isCoverSquareAspectRatio) return coverSize * 1.6
|
|
|
|
return coverSize
|
|
|
|
},
|
|
|
|
coverAspectRatio() {
|
|
|
|
return this.$store.getters['getServerSetting']('coverAspectRatio')
|
|
|
|
},
|
|
|
|
isCoverSquareAspectRatio() {
|
|
|
|
return this.coverAspectRatio === this.$constants.BookCoverAspectRatio.SQUARE
|
|
|
|
},
|
|
|
|
bookCoverAspectRatio() {
|
|
|
|
return this.isCoverSquareAspectRatio ? 1 : 1.6
|
2021-09-28 13:44:40 +02:00
|
|
|
},
|
|
|
|
sizeMultiplier() {
|
2021-12-03 02:02:38 +01:00
|
|
|
var baseSize = this.isCoverSquareAspectRatio ? 192 : 120
|
|
|
|
return this.bookCoverWidth / baseSize
|
2021-09-28 13:44:40 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
2021-11-28 03:11:35 +01:00
|
|
|
showBookshelfTextureModal() {
|
|
|
|
this.$store.commit('globals/setShowBookshelfTextureModal', true)
|
|
|
|
},
|
2021-09-28 13:44:40 +02:00
|
|
|
async init() {
|
|
|
|
this.wrapperClientWidth = this.$refs.wrapper ? this.$refs.wrapper.clientWidth : 0
|
|
|
|
|
2021-12-01 03:02:40 +01:00
|
|
|
if (this.search) {
|
|
|
|
this.setShelvesFromSearch()
|
|
|
|
} else {
|
2021-12-02 02:07:03 +01:00
|
|
|
await this.fetchCategories()
|
2021-12-01 03:02:40 +01:00
|
|
|
}
|
|
|
|
this.loaded = true
|
|
|
|
},
|
2021-12-02 02:07:03 +01:00
|
|
|
async fetchCategories() {
|
|
|
|
var categories = await this.$axios
|
|
|
|
.$get(`/api/libraries/${this.currentLibraryId}/categories`)
|
|
|
|
.then((data) => {
|
|
|
|
return data
|
|
|
|
})
|
|
|
|
.catch((error) => {
|
|
|
|
console.error('Failed to fetch categories', error)
|
|
|
|
return []
|
|
|
|
})
|
|
|
|
this.shelves = categories
|
|
|
|
},
|
2021-12-01 03:02:40 +01:00
|
|
|
async setShelvesFromSearch() {
|
|
|
|
var shelves = []
|
|
|
|
if (this.results.audiobooks) {
|
|
|
|
shelves.push({
|
|
|
|
id: 'audiobooks',
|
|
|
|
label: 'Books',
|
|
|
|
type: 'books',
|
|
|
|
entities: this.results.audiobooks.map((ab) => ab.audiobook)
|
|
|
|
})
|
|
|
|
}
|
2021-12-02 02:07:03 +01:00
|
|
|
|
2021-12-01 03:02:40 +01:00
|
|
|
if (this.results.series) {
|
|
|
|
shelves.push({
|
|
|
|
id: 'series',
|
|
|
|
label: 'Series',
|
|
|
|
type: 'series',
|
|
|
|
entities: this.results.series.map((seriesObj) => {
|
|
|
|
return {
|
|
|
|
name: seriesObj.series,
|
|
|
|
books: seriesObj.audiobooks,
|
|
|
|
type: 'series'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if (this.results.tags) {
|
|
|
|
shelves.push({
|
|
|
|
id: 'tags',
|
|
|
|
label: 'Tags',
|
|
|
|
type: 'tags',
|
|
|
|
entities: this.results.tags.map((tagObj) => {
|
|
|
|
return {
|
|
|
|
name: tagObj.tag,
|
|
|
|
books: tagObj.audiobooks,
|
|
|
|
type: 'tags'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2021-12-03 02:02:38 +01:00
|
|
|
if (this.results.authors) {
|
|
|
|
shelves.push({
|
|
|
|
id: 'authors',
|
|
|
|
label: 'Authors',
|
|
|
|
type: 'authors',
|
|
|
|
entities: this.results.authors.map((a) => {
|
|
|
|
return {
|
|
|
|
id: a.author,
|
|
|
|
name: a.author,
|
|
|
|
numBooks: a.numBooks,
|
|
|
|
type: 'author'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-12-01 03:02:40 +01:00
|
|
|
this.shelves = shelves
|
2021-09-28 13:44:40 +02:00
|
|
|
},
|
2021-12-02 02:07:03 +01:00
|
|
|
settingsUpdated(settings) {},
|
|
|
|
scan() {
|
|
|
|
this.$root.socket.emit('scan', this.$store.state.libraries.currentLibraryId)
|
|
|
|
},
|
|
|
|
audiobookAdded(audiobook) {
|
|
|
|
console.log('Audiobook added', audiobook)
|
|
|
|
// TODO: Check if audiobook would be on this shelf
|
|
|
|
if (!this.search) {
|
|
|
|
this.fetchCategories()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
audiobookUpdated(audiobook) {
|
|
|
|
console.log('Audiobook updated', audiobook)
|
|
|
|
this.shelves.forEach((shelf) => {
|
|
|
|
if (shelf.type === 'books') {
|
|
|
|
shelf.entities = shelf.entities.map((ent) => {
|
|
|
|
if (ent.id === audiobook.id) {
|
|
|
|
return audiobook
|
|
|
|
}
|
|
|
|
return ent
|
|
|
|
})
|
|
|
|
} else if (shelf.type === 'series') {
|
|
|
|
shelf.entities.forEach((ent) => {
|
|
|
|
ent.books = ent.books.map((book) => {
|
|
|
|
if (book.id === audiobook.id) return audiobook
|
|
|
|
return book
|
|
|
|
})
|
|
|
|
})
|
2021-09-28 13:44:40 +02:00
|
|
|
}
|
2021-12-02 02:07:03 +01:00
|
|
|
})
|
|
|
|
},
|
|
|
|
removeBookFromShelf(audiobook) {
|
|
|
|
this.shelves.forEach((shelf) => {
|
|
|
|
if (shelf.type === 'books') {
|
|
|
|
shelf.entities = shelf.entities.filter((ent) => {
|
|
|
|
return ent.id !== audiobook.id
|
|
|
|
})
|
|
|
|
} else if (shelf.type === 'series') {
|
|
|
|
shelf.entities.forEach((ent) => {
|
|
|
|
ent.books = ent.books.filter((book) => {
|
|
|
|
return book.id !== audiobook.id
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
audiobookRemoved(audiobook) {
|
|
|
|
this.removeBookFromShelf(audiobook)
|
|
|
|
},
|
|
|
|
audiobooksAdded(audiobooks) {
|
|
|
|
console.log('audiobooks added', audiobooks)
|
|
|
|
// TODO: Check if audiobook would be on this shelf
|
|
|
|
if (!this.search) {
|
|
|
|
this.fetchCategories()
|
2021-09-28 13:44:40 +02:00
|
|
|
}
|
|
|
|
},
|
2021-12-02 02:07:03 +01:00
|
|
|
audiobooksUpdated(audiobooks) {
|
|
|
|
audiobooks.forEach((ab) => {
|
|
|
|
this.audiobookUpdated(ab)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
initListeners() {
|
|
|
|
this.$store.commit('user/addSettingsListener', { id: 'bookshelf', meth: this.settingsUpdated })
|
|
|
|
|
|
|
|
if (this.$root.socket) {
|
|
|
|
this.$root.socket.on('audiobook_updated', this.audiobookUpdated)
|
|
|
|
this.$root.socket.on('audiobook_added', this.audiobookAdded)
|
|
|
|
this.$root.socket.on('audiobook_removed', this.audiobookRemoved)
|
|
|
|
this.$root.socket.on('audiobooks_updated', this.audiobooksUpdated)
|
|
|
|
this.$root.socket.on('audiobooks_added', this.audiobooksAdded)
|
|
|
|
} else {
|
|
|
|
console.error('Error socket not initialized')
|
|
|
|
}
|
|
|
|
},
|
|
|
|
removeListeners() {
|
|
|
|
this.$store.commit('user/removeSettingsListener', 'bookshelf')
|
|
|
|
|
|
|
|
if (this.$root.socket) {
|
|
|
|
this.$root.socket.off('audiobook_updated', this.audiobookUpdated)
|
|
|
|
this.$root.socket.off('audiobook_added', this.audiobookAdded)
|
|
|
|
this.$root.socket.off('audiobook_removed', this.audiobookRemoved)
|
|
|
|
this.$root.socket.off('audiobooks_updated', this.audiobooksUpdated)
|
|
|
|
this.$root.socket.off('audiobooks_added', this.audiobooksAdded)
|
|
|
|
} else {
|
|
|
|
console.error('Error socket not initialized')
|
|
|
|
}
|
2021-09-28 13:44:40 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
mounted() {
|
2021-12-02 02:07:03 +01:00
|
|
|
this.initListeners()
|
2021-09-28 13:44:40 +02:00
|
|
|
this.init()
|
|
|
|
},
|
|
|
|
beforeDestroy() {
|
2021-12-02 02:07:03 +01:00
|
|
|
this.removeListeners()
|
2021-09-28 13:44:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|