diff --git a/client/components/cards/LazyBookCard.vue b/client/components/cards/LazyBookCard.vue index a642df71..65f48fcb 100644 --- a/client/components/cards/LazyBookCard.vue +++ b/client/components/cards/LazyBookCard.vue @@ -78,7 +78,7 @@ -
+

#{{ seriesSequence }}

@@ -110,7 +110,6 @@ export default { default: 192 }, bookCoverAspectRatio: Number, - showSequence: Boolean, bookshelfView: Number, bookMount: { // Book can be passed as prop or set with setEntity() @@ -176,7 +175,7 @@ export default { return this._libraryItem.id }, series() { - // Only included when filtering by series or collapse series + // Only included when filtering by series or collapse series or Continue Series shelf on home page return this.mediaMetadata.series }, seriesSequence() { diff --git a/client/mixins/bookshelfCardsHelpers.js b/client/mixins/bookshelfCardsHelpers.js index 935807f4..08bd1e9b 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.showSequence = true + if (this.entityName === 'books') { props.filterBy = this.filterBy props.orderBy = this.orderBy diff --git a/server/utils/libraryHelpers.js b/server/utils/libraryHelpers.js index 67db7cda..f107711f 100644 --- a/server/utils/libraryHelpers.js +++ b/server/utils/libraryHelpers.js @@ -245,6 +245,13 @@ module.exports = { entities: [], category: 'recentlyListened' }, + { + id: 'continue-series', + label: 'Continue Series', + type: mediaType, + entities: [], + category: 'continueSeries' + }, { id: 'recently-added', label: 'Recently Added', @@ -282,7 +289,7 @@ module.exports = { } ] - const categories = ['recentlyListened', 'newestEpisodes', 'newestItems', 'newestSeries', 'recentlyFinished', 'newestAuthors'] + const categories = ['recentlyListened', 'continueSeries', 'newestEpisodes', 'newestItems', 'newestSeries', 'recentlyFinished', 'newestAuthors'] const categoryMap = {} categories.forEach((cat) => { categoryMap[cat] = { @@ -398,20 +405,24 @@ module.exports = { // Newest series if (libraryItem.media.metadata.series.length) { for (const librarySeries of libraryItem.media.metadata.series) { + const mediaProgress = allItemProgress.length ? allItemProgress[0] : null + const bookInProgress = mediaProgress && mediaProgress.inProgress + const libraryItemJson = libraryItem.toJSONMinified() + libraryItemJson.seriesSequence = librarySeries.sequence if (!seriesMap[librarySeries.id]) { const seriesObj = allSeries.find(se => se.id === librarySeries.id) if (seriesObj) { var series = { ...seriesObj.toJSON(), - books: [] + books: [libraryItemJson], + inProgress: bookInProgress, + bookInProgressLastUpdate: bookInProgress ? mediaProgress.lastUpdate : null, + sequenceInProgress: bookInProgress ? libraryItemJson.seriesSequence : null } + seriesMap[librarySeries.id] = series if (series.addedAt > categoryMap.newestSeries.smallest) { - const libraryItemJson = libraryItem.toJSONMinified() - libraryItemJson.seriesSequence = librarySeries.sequence - series.books.push(libraryItemJson) - var indexToPut = categoryMap.newestSeries.items.findIndex(i => series.addedAt > i.addedAt) if (indexToPut >= 0) { categoryMap.newestSeries.items.splice(indexToPut, 0, series) @@ -426,15 +437,19 @@ module.exports = { } categoryMap.newestSeries.biggest = categoryMap.newestSeries.items[0].addedAt - - seriesMap[librarySeries.id] = series } } } else { // series already in map - add book - const libraryItemJson = libraryItem.toJSONMinified() - libraryItemJson.seriesSequence = librarySeries.sequence seriesMap[librarySeries.id].books.push(libraryItemJson) + + if (bookInProgress) { // Update if this series is in progress + seriesMap[librarySeries.id].inProgress = true + if (!seriesMap[librarySeries.id].sequenceInProgress) { + seriesMap[librarySeries.id].sequenceInProgress = librarySeries.sequence + seriesMap[librarySeries.id].bookInProgressLastUpdate = mediaProgress.lastUpdate + } + } } } } @@ -525,6 +540,38 @@ module.exports = { } } + // For Continue Series - Find next book in series for series that are in progress + for (const seriesId in seriesMap) { + if (seriesMap[seriesId].inProgress) { + seriesMap[seriesId].books = naturalSort(seriesMap[seriesId].books).asc(li => li.seriesSequence) + + const nextBookInSeries = seriesMap[seriesId].books.find(li => { + if (!seriesMap[seriesId].sequenceInProgress) return true + // True if book series sequence is greater than the current book sequence in progress + return String(li.seriesSequence).localeCompare(String(seriesMap[seriesId].sequenceInProgress), undefined, { sensitivity: 'base', numeric: true }) > 0 + }) + + if (nextBookInSeries) { + const bookForContinueSeries = { + ...nextBookInSeries, + prevBookInProgressLastUpdate: seriesMap[seriesId].bookInProgressLastUpdate + } + bookForContinueSeries.media.metadata.series = { + id: seriesId, + name: seriesMap[seriesId].name, + sequence: nextBookInSeries.seriesSequence + } + + const indexToPut = categoryMap.continueSeries.items.findIndex(i => i.prevBookInProgressLastUpdate < bookForContinueSeries.prevBookInProgressLastUpdate) + if (indexToPut >= 0) { + categoryMap.continueSeries.items.splice(indexToPut, 0, bookForContinueSeries) + } else if (categoryMap.continueSeries.items.length < 10) { // Max 10 books + categoryMap.continueSeries.items.push(bookForContinueSeries) + } + } + } + } + // Sort series books by sequence if (categoryMap.newestSeries.items.length) { for (const seriesItem of categoryMap.newestSeries.items) {