diff --git a/client/components/app/LazyBookshelf.vue b/client/components/app/LazyBookshelf.vue
index e9037bed..ea7795b4 100644
--- a/client/components/app/LazyBookshelf.vue
+++ b/client/components/app/LazyBookshelf.vue
@@ -378,8 +378,6 @@ export default {
let searchParams = new URLSearchParams()
if (this.page === 'series-books') {
searchParams.set('filter', `series.${this.$encode(this.seriesId)}`)
- searchParams.set('sort', 'book.volumeNumber')
- searchParams.set('desc', 0)
} else {
if (this.filterBy && this.filterBy !== 'all') {
searchParams.set('filter', this.filterBy)
diff --git a/client/components/cards/LazyBookCard.vue b/client/components/cards/LazyBookCard.vue
index f0f62f29..1fe5d76d 100644
--- a/client/components/cards/LazyBookCard.vue
+++ b/client/components/cards/LazyBookCard.vue
@@ -35,8 +35,8 @@
-
-
@@ -78,8 +78,13 @@
-
-
#{{ volumeNumber }}
+
+
#{{ seriesSequence }}
+
+
+
+
@@ -100,7 +105,7 @@ export default {
default: 192
},
bookCoverAspectRatio: Number,
- showVolumeNumber: Boolean,
+ showSequence: Boolean,
bookshelfView: Number,
bookMount: {
// Book can be passed as prop or set with setEntity()
@@ -162,8 +167,12 @@ export default {
return this._libraryItem.id
},
series() {
+ // Only included when filtering by series or collapse series
return this.mediaMetadata.series
},
+ seriesSequence() {
+ return this.series ? this.series.sequence : null
+ },
libraryId() {
return this._libraryItem.libraryId
},
@@ -174,12 +183,20 @@ export default {
if (this.media.tracks) return this.media.tracks.length
return this.media.numTracks || 0 // toJSONMinified
},
+ numEpisodes() {
+ if (!this.isPodcast) return 0
+ return this.media.numEpisodes || 0
+ },
processingBatch() {
return this.store.state.processingBatch
},
+ collapsedSeries() {
+ // Only added to item object when collapseSeries is enabled
+ return this._libraryItem.collapsedSeries
+ },
booksInSeries() {
// Only added to item object when collapseSeries is enabled
- return this._libraryItem.booksInSeries
+ return this.collapsedSeries ? this.collapsedSeries.numBooks : 0
},
hasCover() {
return !!this.media.coverPath
@@ -204,9 +221,6 @@ export default {
authorLF() {
return this.mediaMetadata.authorNameLF
},
- volumeNumber() {
- return this.mediaMetadata.volumeNumber || null
- },
displayTitle() {
if (this.orderBy === 'media.metadata.title' && this.sortingIgnorePrefix) {
return this.mediaMetadata.titleIgnorePrefix
@@ -392,7 +406,7 @@ export default {
} else {
var router = this.$router || this.$nuxt.$router
if (router) {
- if (this.booksInSeries) router.push(`/library/${this.libraryId}/series/${this.$encode(this.series)}`)
+ if (this.collapsedSeries) router.push(`/library/${this.libraryId}/series/${this.collapsedSeries.id}`)
else router.push(`/item/${this.libraryItemId}`)
}
}
diff --git a/client/mixins/bookshelfCardsHelpers.js b/client/mixins/bookshelfCardsHelpers.js
index b9b379c3..935807f4 100644
--- a/client/mixins/bookshelfCardsHelpers.js
+++ b/client/mixins/bookshelfCardsHelpers.js
@@ -54,7 +54,7 @@ export default {
bookCoverAspectRatio: this.bookCoverAspectRatio,
bookshelfView: this.bookshelfView
}
- if (this.entityName === 'series-books') props.showVolumeNumber = true
+ if (this.entityName === 'series-books') props.showSequence = true
if (this.entityName === 'books') {
props.filterBy = this.filterBy
props.orderBy = this.orderBy
diff --git a/server/controllers/LibraryController.js b/server/controllers/LibraryController.js
index b41404d9..d4c61acc 100644
--- a/server/controllers/LibraryController.js
+++ b/server/controllers/LibraryController.js
@@ -152,7 +152,11 @@ class LibraryController {
collapseseries: req.query.collapseseries === '1'
}
+ var filterSeries = null
if (payload.filterBy) {
+ // If filtering by series, will include seriesName and seriesSequence on media metadata
+ filterSeries = (payload.mediaType == 'book' && payload.filterBy.startsWith('series.')) ? libraryHelpers.decode(payload.filterBy.replace('series.', '')) : null
+
libraryItems = libraryHelpers.getFilteredLibraryItems(libraryItems, payload.filterBy, req.user)
payload.total = libraryItems.length
}
@@ -180,7 +184,21 @@ class LibraryController {
}
// TODO: Potentially implement collapse series again
- libraryItems = libraryItems.map(ab => payload.minified ? ab.toJSONMinified() : ab.toJSON())
+ if (payload.collapseseries) {
+ libraryItems = libraryHelpers.collapseBookSeries(libraryItems)
+ payload.total = libraryItems.length
+ } else if (filterSeries) {
+ // Book media when filtering series will include series object on media metadata
+ libraryItems = libraryItems.map(li => {
+ var series = li.media.metadata.getSeries(filterSeries)
+ var liJson = payload.minified ? li.toJSONMinified() : li.toJSON()
+ liJson.media.metadata.series = series
+ return liJson
+ })
+ libraryItems = naturalSort(libraryItems).asc(li => li.media.metadata.series.sequence)
+ } else {
+ libraryItems = libraryItems.map(li => payload.minified ? li.toJSONMinified() : li.toJSON())
+ }
if (payload.limit) {
var startIndex = payload.page * payload.limit
diff --git a/server/objects/mediaTypes/Podcast.js b/server/objects/mediaTypes/Podcast.js
index 4244afec..708569ea 100644
--- a/server/objects/mediaTypes/Podcast.js
+++ b/server/objects/mediaTypes/Podcast.js
@@ -57,7 +57,7 @@ class Podcast {
metadata: this.metadata.toJSON(),
coverPath: this.coverPath,
tags: [...this.tags],
- episodes: this.episodes.map(e => e.toJSON()),
+ numEpisodes: this.episodes.length,
autoDownloadEpisodes: this.autoDownloadEpisodes,
lastEpisodeCheck: this.lastEpisodeCheck,
size: this.size
diff --git a/server/objects/metadata/BookMetadata.js b/server/objects/metadata/BookMetadata.js
index 7c1e1003..c5bedc66 100644
--- a/server/objects/metadata/BookMetadata.js
+++ b/server/objects/metadata/BookMetadata.js
@@ -151,6 +151,12 @@ class BookMetadata {
hasNarrator(narratorName) {
return this.narrators.includes(narratorName)
}
+ getSeries(seriesId) {
+ return this.series.find(se => se.id == seriesId)
+ }
+ getFirstSeries() {
+ return this.series.length ? this.series[0] : null
+ }
getSeriesSequence(seriesId) {
var series = this.series.find(se => se.id == seriesId)
if (!series) return null
diff --git a/server/utils/libraryHelpers.js b/server/utils/libraryHelpers.js
index e8990140..1578401f 100644
--- a/server/utils/libraryHelpers.js
+++ b/server/utils/libraryHelpers.js
@@ -262,4 +262,33 @@ module.exports = {
})
return totalSize
},
+
+ collapseBookSeries(libraryItems) {
+ var seriesObjects = this.getSeriesFromBooks(libraryItems, true)
+ var seriesToUse = {}
+ var libraryItemIdsToHide = []
+ seriesObjects.forEach((series) => {
+ series.firstBook = series.books.find(b => !seriesToUse[b.id]) // Find first book not already used
+ if (series.firstBook) {
+ seriesToUse[series.firstBook.id] = series
+ libraryItemIdsToHide = libraryItemIdsToHide.concat(series.books.filter(b => !seriesToUse[b.id]).map(b => b.id))
+ }
+ })
+
+ return libraryItems.map((li) => {
+ if (li.mediaType != 'book') return
+ var libraryItemJson = li.toJSONMinified()
+ if (libraryItemIdsToHide.includes(li.id)) {
+ return null
+ }
+ if (seriesToUse[li.id]) {
+ libraryItemJson.collapsedSeries = {
+ id: seriesToUse[li.id].id,
+ name: seriesToUse[li.id].name,
+ numBooks: seriesToUse[li.id].books.length
+ }
+ }
+ return libraryItemJson
+ }).filter(li => li)
+ }
}
\ No newline at end of file