Merge pull request #2737 from justcallmelarry/feature/add-toggle-for-skipping-earlier-instalments-in-continue-series

Add library toggle setting for skipping earlier instalments in Continue Series
This commit is contained in:
advplyr 2024-03-14 14:40:20 -05:00 committed by GitHub
commit bfd4a378f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 98 additions and 18 deletions

View file

@ -11,6 +11,7 @@ const oldLibrary = require('../objects/Library')
* @property {string} autoScanCronExpression
* @property {boolean} audiobooksOnly
* @property {boolean} hideSingleBookSeries Do not show series that only have 1 book
* @property {boolean} onlyShowLaterBooksInContinueSeries Skip showing books that are earlier than the max sequence read
* @property {string[]} metadataPrecedence
*/

View file

@ -8,7 +8,8 @@ class LibrarySettings {
this.skipMatchingMediaWithIsbn = false
this.autoScanCronExpression = null
this.audiobooksOnly = false
this.hideSingleBookSeries = false // Do not show series that only have 1 book
this.hideSingleBookSeries = false // Do not show series that only have 1 book
this.onlyShowLaterBooksInContinueSeries = false // Skip showing books that are earlier than the max sequence read
this.metadataPrecedence = ['folderStructure', 'audioMetatags', 'nfoFile', 'txtFiles', 'opfFile', 'absMetadata']
this.podcastSearchRegion = 'us'
@ -25,6 +26,7 @@ class LibrarySettings {
this.autoScanCronExpression = settings.autoScanCronExpression || null
this.audiobooksOnly = !!settings.audiobooksOnly
this.hideSingleBookSeries = !!settings.hideSingleBookSeries
this.onlyShowLaterBooksInContinueSeries = !!settings.onlyShowLaterBooksInContinueSeries
if (settings.metadataPrecedence) {
this.metadataPrecedence = [...settings.metadataPrecedence]
} else {
@ -43,6 +45,7 @@ class LibrarySettings {
autoScanCronExpression: this.autoScanCronExpression,
audiobooksOnly: this.audiobooksOnly,
hideSingleBookSeries: this.hideSingleBookSeries,
onlyShowLaterBooksInContinueSeries: this.onlyShowLaterBooksInContinueSeries,
metadataPrecedence: [...this.metadataPrecedence],
podcastSearchRegion: this.podcastSearchRegion
}

View file

@ -75,7 +75,7 @@ module.exports = {
/**
* Get library items for most recently added shelf
* @param {oldLibrary} library
* @param {import('../../objects/Library')} library
* @param {oldUser} user
* @param {string[]} include
* @param {number} limit
@ -120,14 +120,14 @@ module.exports = {
/**
* Get library items for continue series shelf
* @param {string} library
* @param {import('../../objects/Library')} library
* @param {oldUser} user
* @param {string[]} include
* @param {number} limit
* @returns {object} { libraryItems:LibraryItem[], count:number }
*/
async getLibraryItemsContinueSeries(library, user, include, limit) {
const { libraryItems, count } = await libraryItemsBookFilters.getContinueSeriesLibraryItems(library.id, user, include, limit, 0)
const { libraryItems, count } = await libraryItemsBookFilters.getContinueSeriesLibraryItems(library, user, include, limit, 0)
return {
libraryItems: libraryItems.map(li => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
@ -145,7 +145,7 @@ module.exports = {
/**
* Get library items or podcast episodes for the "Listen Again" and "Read Again" shelf
* @param {oldLibrary} library
* @param {import('../../objects/Library')} library
* @param {oldUser} user
* @param {string[]} include
* @param {number} limit

View file

@ -633,14 +633,15 @@ module.exports = {
* 2. Has no books in progress
* 3. Has at least 1 unfinished book
* TODO: Reduce queries
* @param {string} libraryId
* @param {oldUser} user
* @param {import('../../objects/Library')} library
* @param {import('../../objects/user/User')} user
* @param {string[]} include
* @param {number} limit
* @param {number} offset
* @returns {object} { libraryItems:LibraryItem[], count:number }
* @returns {{ libraryItems:import('../../models/LibraryItem')[], count:number }}
*/
async getContinueSeriesLibraryItems(libraryId, user, include, limit, offset) {
async getContinueSeriesLibraryItems(library, user, include, limit, offset) {
const libraryId = library.id
const libraryItemIncludes = []
if (include.includes('rssfeed')) {
libraryItemIncludes.push({
@ -654,6 +655,13 @@ module.exports = {
const userPermissionBookWhere = this.getUserPermissionBookWhereQuery(user)
bookWhere.push(...userPermissionBookWhere.bookWhere)
let includeAttributes = [
[Sequelize.literal('(SELECT max(mp.updatedAt) FROM bookSeries bs, mediaProgresses mp WHERE mp.mediaItemId = bs.bookId AND mp.userId = :userId AND bs.seriesId = series.id)'), 'recent_progress'],
]
if (library.settings.onlyShowLaterBooksInContinueSeries) {
includeAttributes.push([Sequelize.literal('(SELECT CAST(max(bs.sequence) as FLOAT) FROM bookSeries bs, mediaProgresses mp WHERE mp.mediaItemId = bs.bookId AND mp.isFinished = 1 AND mp.userId = :userId AND bs.seriesId = series.id)'), 'maxSequence'])
}
const { rows: series, count } = await Database.seriesModel.findAndCountAll({
where: [
{
@ -675,9 +683,7 @@ module.exports = {
Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM mediaProgresses mp, bookSeries bs WHERE mp.mediaItemId = bs.bookId AND mp.userId = :userId AND bs.seriesId = series.id AND mp.isFinished = 0 AND mp.currentTime > 0)`), 0)
],
attributes: {
include: [
[Sequelize.literal('(SELECT max(mp.updatedAt) FROM bookSeries bs, mediaProgresses mp WHERE mp.mediaItemId = bs.bookId AND mp.userId = :userId AND bs.seriesId = series.id)'), 'recent_progress']
]
include: includeAttributes
},
replacements: {
userId: user.id,
@ -731,13 +737,26 @@ module.exports = {
const libraryItems = series.map(s => {
if (!s.bookSeries.length) return null // this is only possible if user has restricted books in series
const libraryItem = s.bookSeries[0].book.libraryItem.toJSON()
const book = s.bookSeries[0].book.toJSON()
let bookIndex = 0
// if the library setting is toggled, only show later entries in series, otherwise skip
if (library.settings.onlyShowLaterBooksInContinueSeries) {
bookIndex = s.bookSeries.findIndex(function (b) {
return parseFloat(b.dataValues.sequence) > s.dataValues.maxSequence
})
if (bookIndex === -1) {
// no later books than maxSequence
return null
}
}
const libraryItem = s.bookSeries[bookIndex].book.libraryItem.toJSON()
const book = s.bookSeries[bookIndex].book.toJSON()
delete book.libraryItem
libraryItem.series = {
id: s.id,
name: s.name,
sequence: s.bookSeries[0].sequence
sequence: s.bookSeries[bookIndex].sequence
}
if (libraryItem.feeds?.length) {
libraryItem.rssFeed = libraryItem.feeds[0]