mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-05-30 19:54:55 -04:00
Update get library series api endpoint to load from db
This commit is contained in:
parent
9d7d4c6902
commit
4e4a976050
@ -317,6 +317,8 @@ export default {
|
|||||||
// TODO: Temp use new library items API for everything except collapse sub-series
|
// TODO: Temp use new library items API for everything except collapse sub-series
|
||||||
if (entityPath === 'items' && !this.collapseBookSeries && !(this.filterName === 'Series' && this.collapseSeries)) {
|
if (entityPath === 'items' && !this.collapseBookSeries && !(this.filterName === 'Series' && this.collapseSeries)) {
|
||||||
entityPath += '2'
|
entityPath += '2'
|
||||||
|
} else if (entityPath === 'series') {
|
||||||
|
entityPath += '2'
|
||||||
}
|
}
|
||||||
|
|
||||||
const sfQueryString = this.currentSFQueryString ? this.currentSFQueryString + '&' : ''
|
const sfQueryString = this.currentSFQueryString ? this.currentSFQueryString + '&' : ''
|
||||||
@ -628,6 +630,11 @@ export default {
|
|||||||
return entitiesPerShelfBefore < this.entitiesPerShelf // Books per shelf has changed
|
return entitiesPerShelfBefore < this.entitiesPerShelf // Books per shelf has changed
|
||||||
},
|
},
|
||||||
async init(bookshelf) {
|
async init(bookshelf) {
|
||||||
|
if (this.entityName === 'series') {
|
||||||
|
this.booksPerFetch = 50
|
||||||
|
} else {
|
||||||
|
this.booksPerFetch = 100
|
||||||
|
}
|
||||||
this.checkUpdateSearchParams()
|
this.checkUpdateSearchParams()
|
||||||
this.initSizeData(bookshelf)
|
this.initSizeData(bookshelf)
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ const Library = require('../objects/Library')
|
|||||||
const libraryHelpers = require('../utils/libraryHelpers')
|
const libraryHelpers = require('../utils/libraryHelpers')
|
||||||
const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')
|
const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')
|
||||||
const libraryItemFilters = require('../utils/queries/libraryItemFilters')
|
const libraryItemFilters = require('../utils/queries/libraryItemFilters')
|
||||||
|
const seriesFilters = require('../utils/queries/seriesFilters')
|
||||||
const { sort, createNewSortInstance } = require('../libs/fastSort')
|
const { sort, createNewSortInstance } = require('../libs/fastSort')
|
||||||
const naturalSort = createNewSortInstance({
|
const naturalSort = createNewSortInstance({
|
||||||
comparer: new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare
|
comparer: new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare
|
||||||
@ -519,12 +520,42 @@ class LibraryController {
|
|||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET: /api/libraries/:id/series2
|
||||||
|
* Optional query string: `?include=rssfeed` that adds `rssFeed` to series if a feed is open
|
||||||
|
*
|
||||||
|
* @param {import('express').Request} req
|
||||||
|
* @param {import('express').Response} res
|
||||||
|
*/
|
||||||
|
async getAllSeriesForLibraryNew(req, res) {
|
||||||
|
const include = (req.query.include || '').split(',').map(v => v.trim().toLowerCase()).filter(v => !!v)
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
results: [],
|
||||||
|
total: 0,
|
||||||
|
limit: req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 0,
|
||||||
|
page: req.query.page && !isNaN(req.query.page) ? Number(req.query.page) : 0,
|
||||||
|
sortBy: req.query.sort,
|
||||||
|
sortDesc: req.query.desc === '1',
|
||||||
|
filterBy: req.query.filter,
|
||||||
|
minified: req.query.minified === '1',
|
||||||
|
include: include.join(',')
|
||||||
|
}
|
||||||
|
|
||||||
|
const offset = payload.page * payload.limit
|
||||||
|
const { series, count } = await seriesFilters.getFilteredSeries(req.library, req.user, payload.filterBy, payload.sortBy, payload.sortDesc, include, payload.limit, offset)
|
||||||
|
|
||||||
|
payload.total = count
|
||||||
|
payload.results = series
|
||||||
|
res.json(payload)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET: /api/libraries/:id/series
|
* GET: /api/libraries/:id/series
|
||||||
* Optional query string: `?include=rssfeed` that adds `rssFeed` to series if a feed is open
|
* Optional query string: `?include=rssfeed` that adds `rssFeed` to series if a feed is open
|
||||||
*
|
*
|
||||||
* @param {*} req
|
* @param {import('express').Request} req
|
||||||
* @param {*} res
|
* @param {import('express').Response} res
|
||||||
*/
|
*/
|
||||||
async getAllSeriesForLibrary(req, res) {
|
async getAllSeriesForLibrary(req, res) {
|
||||||
const libraryItems = req.libraryItems
|
const libraryItems = req.libraryItems
|
||||||
|
@ -100,7 +100,24 @@ class Series extends Model {
|
|||||||
description: DataTypes.TEXT
|
description: DataTypes.TEXT
|
||||||
}, {
|
}, {
|
||||||
sequelize,
|
sequelize,
|
||||||
modelName: 'series'
|
modelName: 'series',
|
||||||
|
indexes: [
|
||||||
|
{
|
||||||
|
fields: [{
|
||||||
|
name: 'name',
|
||||||
|
collate: 'NOCASE'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fields: [{
|
||||||
|
name: 'nameIgnorePrefix',
|
||||||
|
collate: 'NOCASE'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fields: ['libraryId']
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
const { library } = sequelize.models
|
const { library } = sequelize.models
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const uuidv4 = require("uuid").v4
|
const uuidv4 = require("uuid").v4
|
||||||
const { getTitleIgnorePrefix } = require('../../utils/index')
|
const { getTitleIgnorePrefix, getTitlePrefixAtEnd } = require('../../utils/index')
|
||||||
|
|
||||||
class Series {
|
class Series {
|
||||||
constructor(series) {
|
constructor(series) {
|
||||||
@ -33,6 +33,7 @@ class Series {
|
|||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
nameIgnorePrefix: getTitlePrefixAtEnd(this.name),
|
||||||
description: this.description,
|
description: this.description,
|
||||||
addedAt: this.addedAt,
|
addedAt: this.addedAt,
|
||||||
updatedAt: this.updatedAt,
|
updatedAt: this.updatedAt,
|
||||||
|
@ -78,6 +78,7 @@ class ApiRouter {
|
|||||||
this.router.get('/libraries/:id/items', LibraryController.middleware.bind(this), LibraryController.getLibraryItems.bind(this))
|
this.router.get('/libraries/:id/items', LibraryController.middleware.bind(this), LibraryController.getLibraryItems.bind(this))
|
||||||
this.router.delete('/libraries/:id/issues', LibraryController.middlewareNew.bind(this), LibraryController.removeLibraryItemsWithIssues.bind(this))
|
this.router.delete('/libraries/:id/issues', LibraryController.middlewareNew.bind(this), LibraryController.removeLibraryItemsWithIssues.bind(this))
|
||||||
this.router.get('/libraries/:id/episode-downloads', LibraryController.middlewareNew.bind(this), LibraryController.getEpisodeDownloadQueue.bind(this))
|
this.router.get('/libraries/:id/episode-downloads', LibraryController.middlewareNew.bind(this), LibraryController.getEpisodeDownloadQueue.bind(this))
|
||||||
|
this.router.get('/libraries/:id/series2', LibraryController.middlewareNew.bind(this), LibraryController.getAllSeriesForLibraryNew.bind(this))
|
||||||
this.router.get('/libraries/:id/series', LibraryController.middleware.bind(this), LibraryController.getAllSeriesForLibrary.bind(this))
|
this.router.get('/libraries/:id/series', LibraryController.middleware.bind(this), LibraryController.getAllSeriesForLibrary.bind(this))
|
||||||
this.router.get('/libraries/:id/series/:seriesId', LibraryController.middlewareNew.bind(this), LibraryController.getSeriesForLibrary.bind(this))
|
this.router.get('/libraries/:id/series/:seriesId', LibraryController.middlewareNew.bind(this), LibraryController.getSeriesForLibrary.bind(this))
|
||||||
this.router.get('/libraries/:id/collections', LibraryController.middlewareNew.bind(this), LibraryController.getCollectionsForLibrary.bind(this))
|
this.router.get('/libraries/:id/collections', LibraryController.middlewareNew.bind(this), LibraryController.getCollectionsForLibrary.bind(this))
|
||||||
|
@ -41,11 +41,11 @@ module.exports = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get library items for continue listening & continue reading shelves
|
* Get library items for continue listening & continue reading shelves
|
||||||
* @param {oldLibrary} library
|
* @param {import('../../objects/Library')} library
|
||||||
* @param {oldUser} user
|
* @param {import('../../objects/user/User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {object} { items:LibraryItem[], count:number }
|
* @returns {Promise<{ items:import('../../models/LibraryItem')[], count:number }>}
|
||||||
*/
|
*/
|
||||||
async getMediaItemsInProgress(library, user, include, limit) {
|
async getMediaItemsInProgress(library, user, include, limit) {
|
||||||
if (library.mediaType === 'book') {
|
if (library.mediaType === 'book') {
|
||||||
@ -176,14 +176,14 @@ module.exports = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get series for recent series shelf
|
* Get series for recent series shelf
|
||||||
* @param {oldLibrary} library
|
* @param {import('../../objects/Library')} library
|
||||||
* @param {oldUser} user
|
* @param {import('../../objects/user/User')} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {object} { series:oldSeries[], count:number}
|
* @returns {{ series:import('../../objects/entities/Series')[], count:number}}
|
||||||
*/
|
*/
|
||||||
async getSeriesMostRecentlyAdded(library, user, include, limit) {
|
async getSeriesMostRecentlyAdded(library, user, include, limit) {
|
||||||
if (library.mediaType !== 'book') return { series: [], count: 0 }
|
if (!library.isBook) return { series: [], count: 0 }
|
||||||
|
|
||||||
const seriesIncludes = []
|
const seriesIncludes = []
|
||||||
if (include.includes('rssfeed')) {
|
if (include.includes('rssfeed')) {
|
||||||
@ -390,7 +390,7 @@ module.exports = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get filter data used in filter menus
|
* Get filter data used in filter menus
|
||||||
* @param {oldLibrary} oldLibrary
|
* @param {import('../../objects/Library')} oldLibrary
|
||||||
* @returns {Promise<object>}
|
* @returns {Promise<object>}
|
||||||
*/
|
*/
|
||||||
async getFilterData(oldLibrary) {
|
async getFilterData(oldLibrary) {
|
||||||
|
@ -6,7 +6,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* User permissions to restrict books for explicit content & tags
|
* User permissions to restrict books for explicit content & tags
|
||||||
* @param {oldUser} user
|
* @param {oldUser} user
|
||||||
* @returns {object} { bookWhere:Sequelize.WhereOptions, replacements:string[] }
|
* @returns {{ bookWhere:Sequelize.WhereOptions, replacements:object }}
|
||||||
*/
|
*/
|
||||||
getUserPermissionBookWhereQuery(user) {
|
getUserPermissionBookWhereQuery(user) {
|
||||||
const bookWhere = []
|
const bookWhere = []
|
||||||
|
206
server/utils/queries/seriesFilters.js
Normal file
206
server/utils/queries/seriesFilters.js
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
const Sequelize = require('sequelize')
|
||||||
|
const Logger = require('../../Logger')
|
||||||
|
const Database = require('../../Database')
|
||||||
|
const libraryItemsBookFilters = require('./libraryItemsBookFilters')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
decode(text) {
|
||||||
|
return Buffer.from(decodeURIComponent(text), 'base64').toString()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get series filtered and sorted
|
||||||
|
*
|
||||||
|
* @param {import('../../objects/Library')} library
|
||||||
|
* @param {import('../../objects/user/User')} user
|
||||||
|
* @param {string} filterBy
|
||||||
|
* @param {string} sortBy
|
||||||
|
* @param {boolean} sortDesc
|
||||||
|
* @param {string[]} include
|
||||||
|
* @param {number} limit
|
||||||
|
* @param {number} offset
|
||||||
|
* @returns {Promise<{ series:object[], count:number }>}
|
||||||
|
*/
|
||||||
|
async getFilteredSeries(library, user, filterBy, sortBy, sortDesc, include, limit, offset) {
|
||||||
|
let filterValue = null
|
||||||
|
let filterGroup = null
|
||||||
|
if (filterBy) {
|
||||||
|
const searchGroups = ['genres', 'tags', 'authors', 'progress', 'narrators', 'publishers', 'languages']
|
||||||
|
const group = searchGroups.find(_group => filterBy.startsWith(_group + '.'))
|
||||||
|
filterGroup = group || filterBy
|
||||||
|
filterValue = group ? this.decode(filterBy.replace(`${group}.`, '')) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
const seriesIncludes = []
|
||||||
|
if (include.includes('rssfeed')) {
|
||||||
|
seriesIncludes.push({
|
||||||
|
model: Database.models.feed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const userPermissionBookWhere = libraryItemsBookFilters.getUserPermissionBookWhereQuery(user)
|
||||||
|
|
||||||
|
const seriesWhere = [
|
||||||
|
{
|
||||||
|
libraryId: library.id
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// Handle library setting to hide single book series
|
||||||
|
// TODO: Merge with existing query
|
||||||
|
if (library.settings.hideSingleBookSeries) {
|
||||||
|
seriesWhere.push(Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id)`), {
|
||||||
|
[Sequelize.Op.gt]: 1
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle filters
|
||||||
|
// TODO: Simplify and break-out
|
||||||
|
let attrQuery = null
|
||||||
|
if (['genres', 'tags', 'narrators'].includes(filterGroup)) {
|
||||||
|
attrQuery = `SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id AND (SELECT count(*) FROM json_each(b.${filterGroup}) WHERE json_valid(b.${filterGroup}) AND json_each.value = :filterValue) > 0`
|
||||||
|
userPermissionBookWhere.replacements.filterValue = filterValue
|
||||||
|
} else if (filterGroup === 'authors') {
|
||||||
|
attrQuery = 'SELECT count(*) FROM books b, bookSeries bs, bookAuthors ba WHERE bs.seriesId = series.id AND bs.bookId = b.id AND ba.bookId = b.id AND ba.authorId = :filterValue'
|
||||||
|
userPermissionBookWhere.replacements.filterValue = filterValue
|
||||||
|
} else if (filterGroup === 'publishers') {
|
||||||
|
attrQuery = 'SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id AND b.publisher = :filterValue'
|
||||||
|
userPermissionBookWhere.replacements.filterValue = filterValue
|
||||||
|
} else if (filterGroup === 'languages') {
|
||||||
|
attrQuery = 'SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id AND b.language = :filterValue'
|
||||||
|
userPermissionBookWhere.replacements.filterValue = filterValue
|
||||||
|
} else if (filterGroup === 'progress') {
|
||||||
|
if (filterValue === 'not-finished') {
|
||||||
|
attrQuery = 'SELECT count(*) FROM books b, bookSeries bs LEFT OUTER JOIN mediaProgresses mp ON mp.mediaItemId = b.id WHERE bs.seriesId = series.id AND bs.bookId = b.id AND (mp.isFinished IS NULL OR mp.isFinished = 0)'
|
||||||
|
} else if (filterValue === 'finished') {
|
||||||
|
const progQuery = 'SELECT count(*) FROM books b, bookSeries bs LEFT OUTER JOIN mediaProgresses mp ON mp.mediaItemId = b.id WHERE bs.seriesId = series.id AND bs.bookId = b.id AND (mp.isFinished IS NULL OR mp.isFinished = 0)'
|
||||||
|
seriesWhere.push(Sequelize.where(Sequelize.literal(`(${progQuery})`), 0))
|
||||||
|
} else if (filterValue === 'not-started') {
|
||||||
|
const progQuery = 'SELECT count(*) FROM books b, bookSeries bs LEFT OUTER JOIN mediaProgresses mp ON mp.mediaItemId = b.id WHERE bs.seriesId = series.id AND bs.bookId = b.id AND (mp.isFinished = 1 OR mp.currentTime > 0)'
|
||||||
|
seriesWhere.push(Sequelize.where(Sequelize.literal(`(${progQuery})`), 0))
|
||||||
|
} else if (filterValue === 'in-progress') {
|
||||||
|
attrQuery = 'SELECT count(*) FROM books b, bookSeries bs LEFT OUTER JOIN mediaProgresses mp ON mp.mediaItemId = b.id WHERE bs.seriesId = series.id AND bs.bookId = b.id AND (mp.currentTime > 0 OR mp.ebookProgress > 0) AND mp.isFinished = 0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle user permissions to only include series with at least 1 book
|
||||||
|
// TODO: Simplify to a single query
|
||||||
|
if (userPermissionBookWhere.bookWhere.length) {
|
||||||
|
if (!attrQuery) attrQuery = 'SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id'
|
||||||
|
|
||||||
|
if (!user.canAccessExplicitContent) {
|
||||||
|
attrQuery += ' AND b.explicit = 0'
|
||||||
|
}
|
||||||
|
if (!user.permissions.accessAllTags && user.itemTagsSelected.length) {
|
||||||
|
if (user.permissions.selectedTagsNotAccessible) {
|
||||||
|
attrQuery += ' AND (SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected)) = 0'
|
||||||
|
} else {
|
||||||
|
attrQuery += ' AND (SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected)) > 0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrQuery) {
|
||||||
|
seriesWhere.push(Sequelize.where(Sequelize.literal(`(${attrQuery})`), {
|
||||||
|
[Sequelize.Op.gt]: 0
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const order = []
|
||||||
|
let seriesAttributes = {
|
||||||
|
include: []
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle sort order
|
||||||
|
const dir = sortDesc ? 'DESC' : 'ASC'
|
||||||
|
if (sortBy === 'numBooks') {
|
||||||
|
seriesAttributes.include.push([Sequelize.literal('(SELECT count(*) FROM bookSeries bs WHERE bs.seriesId = series.id)'), 'numBooks'])
|
||||||
|
order.push(['numBooks', dir])
|
||||||
|
} else if (sortBy === 'addedAt') {
|
||||||
|
order.push(['createdAt', dir])
|
||||||
|
} else if (sortBy === 'name') {
|
||||||
|
if (global.ServerSettings.sortingIgnorePrefix) {
|
||||||
|
order.push([Sequelize.literal('nameIgnorePrefix COLLATE NOCASE'), dir])
|
||||||
|
} else {
|
||||||
|
order.push([Sequelize.literal('`series`.`name` COLLATE NOCASE'), dir])
|
||||||
|
}
|
||||||
|
} else if (sortBy === 'totalDuration') {
|
||||||
|
seriesAttributes.include.push([Sequelize.literal('(SELECT SUM(b.duration) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND b.id = bs.bookId)'), 'totalDuration'])
|
||||||
|
order.push(['totalDuration', dir])
|
||||||
|
} else if (sortBy === 'lastBookAdded') {
|
||||||
|
seriesAttributes.include.push([Sequelize.literal('(SELECT MAX(b.createdAt) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND b.id = bs.bookId)'), 'mostRecentBookAdded'])
|
||||||
|
order.push(['mostRecentBookAdded', dir])
|
||||||
|
} else if (sortBy === 'lastBookUpdated') {
|
||||||
|
seriesAttributes.include.push([Sequelize.literal('(SELECT MAX(b.updatedAt) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND b.id = bs.bookId)'), 'mostRecentBookUpdated'])
|
||||||
|
order.push(['mostRecentBookUpdated', dir])
|
||||||
|
}
|
||||||
|
|
||||||
|
const { rows: series, count } = await Database.seriesModel.findAndCountAll({
|
||||||
|
where: seriesWhere,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
distinct: true,
|
||||||
|
subQuery: false,
|
||||||
|
benchmark: true,
|
||||||
|
logging: (sql, timeMs) => {
|
||||||
|
console.log(`[Query] Series filter/sort. Elapsed ${timeMs}ms`)
|
||||||
|
},
|
||||||
|
attributes: seriesAttributes,
|
||||||
|
replacements: userPermissionBookWhere.replacements,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Database.models.bookSeries,
|
||||||
|
include: {
|
||||||
|
model: Database.models.book,
|
||||||
|
where: userPermissionBookWhere.bookWhere,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Database.models.libraryItem
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
separate: true
|
||||||
|
},
|
||||||
|
...seriesIncludes
|
||||||
|
],
|
||||||
|
order
|
||||||
|
})
|
||||||
|
|
||||||
|
// Map series to old series
|
||||||
|
const allOldSeries = []
|
||||||
|
for (const s of series) {
|
||||||
|
const oldSeries = s.getOldSeries().toJSON()
|
||||||
|
|
||||||
|
if (s.dataValues.totalDuration) {
|
||||||
|
oldSeries.totalDuration = s.dataValues.totalDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.feeds?.length) {
|
||||||
|
oldSeries.rssFeed = Database.models.feed.getOldFeed(s.feeds[0]).toJSONMinified()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Sort books by sequence in query
|
||||||
|
s.bookSeries.sort((a, b) => {
|
||||||
|
if (!a.sequence) return 1
|
||||||
|
if (!b.sequence) return -1
|
||||||
|
return a.sequence.localeCompare(b.sequence, undefined, {
|
||||||
|
numeric: true,
|
||||||
|
sensitivity: 'base'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
oldSeries.books = s.bookSeries.map(bs => {
|
||||||
|
const libraryItem = bs.book.libraryItem.toJSON()
|
||||||
|
delete bs.book.libraryItem
|
||||||
|
libraryItem.media = bs.book
|
||||||
|
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(libraryItem).toJSONMinified()
|
||||||
|
return oldLibraryItem
|
||||||
|
})
|
||||||
|
allOldSeries.push(oldSeries)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
series: allOldSeries,
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user