mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-27 16:29:30 +01:00
Include library item podcast queries
This commit is contained in:
parent
eeaf012cdc
commit
95c4b3862b
@ -314,8 +314,8 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let entityPath = this.entityName === 'series-books' ? 'items' : this.entityName
|
let entityPath = this.entityName === 'series-books' ? 'items' : this.entityName
|
||||||
// TODO: Temp use new library items API for everything except podcasts and collapse sub-series
|
// TODO: Temp use new library items API for everything except collapse sub-series
|
||||||
if (entityPath === 'items' && !this.isPodcast && !this.collapseBookSeries && !(this.filterName === 'Series' && this.collapseSeries)) {
|
if (entityPath === 'items' && !this.collapseBookSeries && !(this.filterName === 'Series' && this.collapseSeries)) {
|
||||||
entityPath += '2'
|
entityPath += '2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ class LibraryController {
|
|||||||
}
|
}
|
||||||
payload.offset = payload.page * payload.limit
|
payload.offset = payload.page * payload.limit
|
||||||
|
|
||||||
const { libraryItems, count } = await Database.models.libraryItem.getByFilterAndSort(req.library.id, req.user.id, payload)
|
const { libraryItems, count } = await Database.models.libraryItem.getByFilterAndSort(req.library, req.user.id, payload)
|
||||||
payload.results = libraryItems
|
payload.results = libraryItems
|
||||||
payload.total = count
|
payload.total = count
|
||||||
|
|
||||||
|
@ -400,8 +400,15 @@ module.exports = (sequelize) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getByFilterAndSort(libraryId, userId, options) {
|
/**
|
||||||
const { libraryItems, count } = await libraryFilters.getFilteredLibraryItems(libraryId, userId, options)
|
* Get library items using filter and sort
|
||||||
|
* @param {oldLibrary} library
|
||||||
|
* @param {string} userId
|
||||||
|
* @param {object} options
|
||||||
|
* @returns {object} { libraryItems:oldLibraryItem[], count:number }
|
||||||
|
*/
|
||||||
|
static async getByFilterAndSort(library, userId, options) {
|
||||||
|
const { libraryItems, count } = await libraryFilters.getFilteredLibraryItems(library, userId, options)
|
||||||
return {
|
return {
|
||||||
libraryItems: libraryItems.map(li => {
|
libraryItems: libraryItems.map(li => {
|
||||||
const oldLibraryItem = this.getOldLibraryItem(li).toJSONMinified()
|
const oldLibraryItem = this.getOldLibraryItem(li).toJSONMinified()
|
||||||
@ -414,6 +421,16 @@ module.exports = (sequelize) => {
|
|||||||
if (li.rssFeed) {
|
if (li.rssFeed) {
|
||||||
oldLibraryItem.rssFeed = sequelize.models.feed.getOldFeed(li.rssFeed).toJSONMinified()
|
oldLibraryItem.rssFeed = sequelize.models.feed.getOldFeed(li.rssFeed).toJSONMinified()
|
||||||
}
|
}
|
||||||
|
if (li.media.numEpisodes) {
|
||||||
|
oldLibraryItem.media.numEpisodes = li.media.numEpisodes
|
||||||
|
}
|
||||||
|
if (li.size && !oldLibraryItem.media.size) {
|
||||||
|
oldLibraryItem.media.size = li.size
|
||||||
|
}
|
||||||
|
if (li.numEpisodesIncomplete) {
|
||||||
|
oldLibraryItem.numEpisodesIncomplete = li.numEpisodesIncomplete
|
||||||
|
}
|
||||||
|
|
||||||
return oldLibraryItem
|
return oldLibraryItem
|
||||||
}),
|
}),
|
||||||
count
|
count
|
||||||
|
@ -4,7 +4,7 @@ module.exports = (sequelize) => {
|
|||||||
class Podcast extends Model {
|
class Podcast extends Model {
|
||||||
static getOldPodcast(libraryItemExpanded) {
|
static getOldPodcast(libraryItemExpanded) {
|
||||||
const podcastExpanded = libraryItemExpanded.media
|
const podcastExpanded = libraryItemExpanded.media
|
||||||
const podcastEpisodes = podcastExpanded.podcastEpisodes.map(ep => ep.getOldPodcastEpisode(libraryItemExpanded.id)).sort((a, b) => a.index - b.index)
|
const podcastEpisodes = podcastExpanded.podcastEpisodes?.map(ep => ep.getOldPodcastEpisode(libraryItemExpanded.id)).sort((a, b) => a.index - b.index)
|
||||||
return {
|
return {
|
||||||
id: podcastExpanded.id,
|
id: podcastExpanded.id,
|
||||||
libraryItemId: libraryItemExpanded.id,
|
libraryItemId: libraryItemExpanded.id,
|
||||||
@ -25,7 +25,7 @@ module.exports = (sequelize) => {
|
|||||||
},
|
},
|
||||||
coverPath: podcastExpanded.coverPath,
|
coverPath: podcastExpanded.coverPath,
|
||||||
tags: podcastExpanded.tags,
|
tags: podcastExpanded.tags,
|
||||||
episodes: podcastEpisodes,
|
episodes: podcastEpisodes || [],
|
||||||
autoDownloadEpisodes: podcastExpanded.autoDownloadEpisodes,
|
autoDownloadEpisodes: podcastExpanded.autoDownloadEpisodes,
|
||||||
autoDownloadSchedule: podcastExpanded.autoDownloadSchedule,
|
autoDownloadSchedule: podcastExpanded.autoDownloadSchedule,
|
||||||
lastEpisodeCheck: podcastExpanded.lastEpisodeCheck?.valueOf() || null,
|
lastEpisodeCheck: podcastExpanded.lastEpisodeCheck?.valueOf() || null,
|
||||||
|
@ -1,12 +1,20 @@
|
|||||||
const libraryItemsBookFilters = require('./libraryItemsBookFilters')
|
const libraryItemsBookFilters = require('./libraryItemsBookFilters')
|
||||||
|
const libraryItemsPodcastFilters = require('./libraryItemsPodcastFilters')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
decode(text) {
|
decode(text) {
|
||||||
return Buffer.from(decodeURIComponent(text), 'base64').toString()
|
return Buffer.from(decodeURIComponent(text), 'base64').toString()
|
||||||
},
|
},
|
||||||
|
|
||||||
async getFilteredLibraryItems(libraryId, userId, options) {
|
/**
|
||||||
const { filterBy, sortBy, sortDesc, limit, offset, collapseseries, include } = options
|
* Get library items using filter and sort
|
||||||
|
* @param {oldLibrary} library
|
||||||
|
* @param {string} userId
|
||||||
|
* @param {object} options
|
||||||
|
* @returns {object} { libraryItems:LibraryItem[], count:number }
|
||||||
|
*/
|
||||||
|
async getFilteredLibraryItems(library, userId, options) {
|
||||||
|
const { filterBy, sortBy, sortDesc, limit, offset, collapseseries, include, mediaType } = options
|
||||||
|
|
||||||
let filterValue = null
|
let filterValue = null
|
||||||
let filterGroup = null
|
let filterGroup = null
|
||||||
@ -17,7 +25,11 @@ module.exports = {
|
|||||||
filterValue = group ? this.decode(filterBy.replace(`${group}.`, '')) : null
|
filterValue = group ? this.decode(filterBy.replace(`${group}.`, '')) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle podcast filters
|
if (mediaType === 'book') {
|
||||||
return libraryItemsBookFilters.getFilteredLibraryItems(libraryId, userId, filterGroup, filterValue, sortBy, sortDesc, collapseseries, include, limit, offset)
|
return libraryItemsBookFilters.getFilteredLibraryItems(library.id, userId, filterGroup, filterValue, sortBy, sortDesc, collapseseries, include, limit, offset)
|
||||||
|
} else {
|
||||||
|
return libraryItemsPodcastFilters.getFilteredLibraryItems(library.id, userId, filterGroup, filterValue, sortBy, sortDesc, include, limit, offset)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,6 +3,13 @@ const Database = require('../../Database')
|
|||||||
const Logger = require('../../Logger')
|
const Logger = require('../../Logger')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* When collapsing series and filtering by progress
|
||||||
|
* different where options are required
|
||||||
|
*
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {Sequelize.WhereOptions}
|
||||||
|
*/
|
||||||
getCollapseSeriesMediaProgressFilter(value) {
|
getCollapseSeriesMediaProgressFilter(value) {
|
||||||
const mediaWhere = {}
|
const mediaWhere = {}
|
||||||
if (value === 'not-finished') {
|
if (value === 'not-finished') {
|
||||||
@ -52,10 +59,13 @@ module.exports = {
|
|||||||
* Get where options for Book model
|
* Get where options for Book model
|
||||||
* @param {string} group
|
* @param {string} group
|
||||||
* @param {[string]} value
|
* @param {[string]} value
|
||||||
* @returns {Sequelize.WhereOptions}
|
* @returns {object} { Sequelize.WhereOptions, string[] }
|
||||||
*/
|
*/
|
||||||
getMediaGroupQuery(group, value) {
|
getMediaGroupQuery(group, value) {
|
||||||
|
if (!group) return { mediaWhere: {}, replacements: {} }
|
||||||
|
|
||||||
let mediaWhere = {}
|
let mediaWhere = {}
|
||||||
|
const replacements = {}
|
||||||
|
|
||||||
if (group === 'progress') {
|
if (group === 'progress') {
|
||||||
if (value === 'not-finished') {
|
if (value === 'not-finished') {
|
||||||
@ -103,9 +113,10 @@ module.exports = {
|
|||||||
} else if (group === 'abridged') {
|
} else if (group === 'abridged') {
|
||||||
mediaWhere['abridged'] = true
|
mediaWhere['abridged'] = true
|
||||||
} else if (['genres', 'tags', 'narrators'].includes(group)) {
|
} else if (['genres', 'tags', 'narrators'].includes(group)) {
|
||||||
mediaWhere[group] = Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(${group}) WHERE json_valid(${group}) AND json_each.value = "${value}")`), {
|
mediaWhere[group] = Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(${group}) WHERE json_valid(${group}) AND json_each.value = :filterValue)`), {
|
||||||
[Sequelize.Op.gte]: 1
|
[Sequelize.Op.gte]: 1
|
||||||
})
|
})
|
||||||
|
replacements.filterValue = value
|
||||||
} else if (group === 'publishers') {
|
} else if (group === 'publishers') {
|
||||||
mediaWhere['publisher'] = value
|
mediaWhere['publisher'] = value
|
||||||
} else if (group === 'languages') {
|
} else if (group === 'languages') {
|
||||||
@ -142,7 +153,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mediaWhere
|
return { mediaWhere, replacements }
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,18 +178,18 @@ module.exports = {
|
|||||||
} else if (sortBy === 'media.metadata.publishedYear') {
|
} else if (sortBy === 'media.metadata.publishedYear') {
|
||||||
return [['publishedYear', dir]]
|
return [['publishedYear', dir]]
|
||||||
} else if (sortBy === 'media.metadata.authorNameLF') {
|
} else if (sortBy === 'media.metadata.authorNameLF') {
|
||||||
return [['author_name', dir]]
|
return [[Sequelize.literal('author_name COLLATE NOCASE'), dir]]
|
||||||
} else if (sortBy === 'media.metadata.authorName') {
|
} else if (sortBy === 'media.metadata.authorName') {
|
||||||
return [['author_name', dir]]
|
return [[Sequelize.literal('author_name COLLATE NOCASE'), dir]]
|
||||||
} else if (sortBy === 'media.metadata.title') {
|
} else if (sortBy === 'media.metadata.title') {
|
||||||
if (collapseseries) {
|
if (collapseseries) {
|
||||||
return [[Sequelize.literal('display_title COLLATE NOCASE'), dir]]
|
return [[Sequelize.literal('display_title COLLATE NOCASE'), dir]]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.ServerSettings.sortingIgnorePrefix) {
|
if (global.ServerSettings.sortingIgnorePrefix) {
|
||||||
return [['titleIgnorePrefix', dir]]
|
return [[Sequelize.literal('titleIgnorePrefix COLLATE NOCASE'), dir]]
|
||||||
} else {
|
} else {
|
||||||
return [['title', dir]]
|
return [[Sequelize.literal('title COLLATE NOCASE'), dir]]
|
||||||
}
|
}
|
||||||
} else if (sortBy === 'sequence') {
|
} else if (sortBy === 'sequence') {
|
||||||
const nullDir = sortDesc ? 'DESC NULLS FIRST' : 'ASC NULLS LAST'
|
const nullDir = sortDesc ? 'DESC NULLS FIRST' : 'ASC NULLS LAST'
|
||||||
@ -187,6 +198,15 @@ module.exports = {
|
|||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When collapsing series get first book in each series
|
||||||
|
* to know which books to exclude from primary query.
|
||||||
|
* Additionally use this query to get the number of books in each series
|
||||||
|
*
|
||||||
|
* @param {Sequelize.ModelStatic} bookFindOptions
|
||||||
|
* @param {Sequelize.WhereOptions} seriesWhere
|
||||||
|
* @returns {object} { booksToExclude, bookSeriesToInclude }
|
||||||
|
*/
|
||||||
async getCollapseSeriesBooksToExclude(bookFindOptions, seriesWhere) {
|
async getCollapseSeriesBooksToExclude(bookFindOptions, seriesWhere) {
|
||||||
const allSeries = await Database.models.series.findAll({
|
const allSeries = await Database.models.series.findAll({
|
||||||
attributes: [
|
attributes: [
|
||||||
@ -386,7 +406,7 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const bookWhere = filterGroup ? this.getMediaGroupQuery(filterGroup, filterValue) : {}
|
const { mediaWhere, replacements } = this.getMediaGroupQuery(filterGroup, filterValue)
|
||||||
|
|
||||||
let collapseSeriesBookSeries = []
|
let collapseSeriesBookSeries = []
|
||||||
if (collapseseries) {
|
if (collapseseries) {
|
||||||
@ -399,7 +419,7 @@ module.exports = {
|
|||||||
['$books.authors.id$']: null
|
['$books.authors.id$']: null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
seriesBookWhere = bookWhere
|
seriesBookWhere = mediaWhere
|
||||||
}
|
}
|
||||||
|
|
||||||
const bookFindOptions = {
|
const bookFindOptions = {
|
||||||
@ -417,12 +437,15 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
const { booksToExclude, bookSeriesToInclude } = await this.getCollapseSeriesBooksToExclude(bookFindOptions, seriesWhere)
|
const { booksToExclude, bookSeriesToInclude } = await this.getCollapseSeriesBooksToExclude(bookFindOptions, seriesWhere)
|
||||||
if (booksToExclude.length) {
|
if (booksToExclude.length) {
|
||||||
bookWhere['id'] = {
|
mediaWhere['id'] = {
|
||||||
[Sequelize.Op.notIn]: booksToExclude
|
[Sequelize.Op.notIn]: booksToExclude
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
collapseSeriesBookSeries = bookSeriesToInclude
|
collapseSeriesBookSeries = bookSeriesToInclude
|
||||||
if (!bookAttributes?.include) bookAttributes = { include: [] }
|
if (!bookAttributes?.include) bookAttributes = { include: [] }
|
||||||
|
|
||||||
|
// When collapsing series and sorting by title then use the series name instead of the book title
|
||||||
|
// for this set an attribute "display_title" to use in sorting
|
||||||
if (global.ServerSettings.sortingIgnorePrefix) {
|
if (global.ServerSettings.sortingIgnorePrefix) {
|
||||||
bookAttributes.include.push([Sequelize.literal(`IFNULL((SELECT s.nameIgnorePrefix FROM bookSeries AS bs, series AS s WHERE bs.seriesId = s.id AND bs.bookId = book.id AND bs.id IN (${bookSeriesToInclude.map(v => `"${v.id}"`).join(', ')})), titleIgnorePrefix)`), 'display_title'])
|
bookAttributes.include.push([Sequelize.literal(`IFNULL((SELECT s.nameIgnorePrefix FROM bookSeries AS bs, series AS s WHERE bs.seriesId = s.id AND bs.bookId = book.id AND bs.id IN (${bookSeriesToInclude.map(v => `"${v.id}"`).join(', ')})), titleIgnorePrefix)`), 'display_title'])
|
||||||
} else {
|
} else {
|
||||||
@ -431,9 +454,10 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { rows: books, count } = await Database.models.book.findAndCountAll({
|
const { rows: books, count } = await Database.models.book.findAndCountAll({
|
||||||
where: bookWhere,
|
where: mediaWhere,
|
||||||
distinct: true,
|
distinct: true,
|
||||||
attributes: bookAttributes,
|
attributes: bookAttributes,
|
||||||
|
replacements,
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: Database.models.libraryItem,
|
model: Database.models.libraryItem,
|
||||||
|
156
server/utils/queries/libraryItemsPodcastFilters.js
Normal file
156
server/utils/queries/libraryItemsPodcastFilters.js
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
|
||||||
|
const Sequelize = require('sequelize')
|
||||||
|
const Database = require('../../Database')
|
||||||
|
const Logger = require('../../Logger')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get where options for Podcast model
|
||||||
|
* @param {string} group
|
||||||
|
* @param {[string]} value
|
||||||
|
* @returns {object} { Sequelize.WhereOptions, string[] }
|
||||||
|
*/
|
||||||
|
getMediaGroupQuery(group, value) {
|
||||||
|
if (!group) return { mediaWhere: {}, replacements: {} }
|
||||||
|
|
||||||
|
let mediaWhere = {}
|
||||||
|
const replacements = {}
|
||||||
|
|
||||||
|
if (['genres', 'tags'].includes(group)) {
|
||||||
|
mediaWhere[group] = Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(${group}) WHERE json_valid(${group}) AND json_each.value = :filterValue)`), {
|
||||||
|
[Sequelize.Op.gte]: 1
|
||||||
|
})
|
||||||
|
replacements.filterValue = value
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
mediaWhere,
|
||||||
|
replacements
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get sequelize order
|
||||||
|
* @param {string} sortBy
|
||||||
|
* @param {boolean} sortDesc
|
||||||
|
* @returns {Sequelize.order}
|
||||||
|
*/
|
||||||
|
getOrder(sortBy, sortDesc) {
|
||||||
|
const dir = sortDesc ? 'DESC' : 'ASC'
|
||||||
|
if (sortBy === 'addedAt') {
|
||||||
|
return [[Sequelize.literal('libraryItem.createdAt'), dir]]
|
||||||
|
} else if (sortBy === 'size') {
|
||||||
|
return [[Sequelize.literal('libraryItem.size'), dir]]
|
||||||
|
} else if (sortBy === 'birthtimeMs') {
|
||||||
|
return [[Sequelize.literal('libraryItem.birthtime'), dir]]
|
||||||
|
} else if (sortBy === 'mtimeMs') {
|
||||||
|
return [[Sequelize.literal('libraryItem.mtime'), dir]]
|
||||||
|
} else if (sortBy === 'media.metadata.author') {
|
||||||
|
const nullDir = sortDesc ? 'DESC NULLS FIRST' : 'ASC NULLS LAST'
|
||||||
|
return [[Sequelize.literal(`\`podcast\`.\`author\` COLLATE NOCASE ${nullDir}`)]]
|
||||||
|
} else if (sortBy === 'media.metadata.title') {
|
||||||
|
if (global.ServerSettings.sortingIgnorePrefix) {
|
||||||
|
return [[Sequelize.literal('titleIgnorePrefix COLLATE NOCASE'), dir]]
|
||||||
|
} else {
|
||||||
|
return [[Sequelize.literal('title COLLATE NOCASE'), dir]]
|
||||||
|
}
|
||||||
|
} else if (sortBy === 'media.numTracks') {
|
||||||
|
return [['numEpisodes', dir]]
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get library items for podcast media type using filter and sort
|
||||||
|
* @param {string} libraryId
|
||||||
|
* @param {[string]} filterGroup
|
||||||
|
* @param {[string]} filterValue
|
||||||
|
* @param {string} sortBy
|
||||||
|
* @param {string} sortDesc
|
||||||
|
* @param {string[]} include
|
||||||
|
* @param {number} limit
|
||||||
|
* @param {number} offset
|
||||||
|
* @returns {object} { libraryItems:LibraryItem[], count:number }
|
||||||
|
*/
|
||||||
|
async getFilteredLibraryItems(libraryId, userId, filterGroup, filterValue, sortBy, sortDesc, include, limit, offset) {
|
||||||
|
const includeRSSFeed = include.includes('rssfeed')
|
||||||
|
const includeNumEpisodesIncomplete = include.includes('numepisodesincomplete')
|
||||||
|
|
||||||
|
const libraryItemWhere = {
|
||||||
|
libraryId
|
||||||
|
}
|
||||||
|
const libraryItemIncludes = []
|
||||||
|
if (includeRSSFeed) {
|
||||||
|
libraryItemIncludes.push({
|
||||||
|
model: Database.models.feed,
|
||||||
|
required: filterGroup === 'feed-open'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (filterGroup === 'issues') {
|
||||||
|
libraryItemWhere[Sequelize.Op.or] = [
|
||||||
|
{
|
||||||
|
isMissing: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
isInvalid: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const podcastIncludes = []
|
||||||
|
if (includeNumEpisodesIncomplete) {
|
||||||
|
podcastIncludes.push([Sequelize.literal(`(SELECT count(*) FROM podcastEpisodes pe LEFT OUTER JOIN mediaProgresses mp ON mp.mediaItemId = pe.id AND mp.userId = :userId WHERE pe.podcastId = podcast.id AND (mp.isFinished = 0 OR mp.isFinished IS NULL))`), 'numEpisodesIncomplete'])
|
||||||
|
}
|
||||||
|
|
||||||
|
const { mediaWhere, replacements } = this.getMediaGroupQuery(filterGroup, filterValue)
|
||||||
|
replacements.userId = userId
|
||||||
|
|
||||||
|
const { rows: podcasts, count } = await Database.models.podcast.findAndCountAll({
|
||||||
|
where: mediaWhere,
|
||||||
|
replacements,
|
||||||
|
distinct: true,
|
||||||
|
attributes: {
|
||||||
|
include: [
|
||||||
|
[Sequelize.literal(`(SELECT count(*) FROM podcastEpisodes pe WHERE pe.podcastId = podcast.id)`), 'numEpisodes'],
|
||||||
|
...podcastIncludes
|
||||||
|
]
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Database.models.libraryItem,
|
||||||
|
required: true,
|
||||||
|
where: libraryItemWhere,
|
||||||
|
include: libraryItemIncludes
|
||||||
|
}
|
||||||
|
],
|
||||||
|
order: this.getOrder(sortBy, sortDesc),
|
||||||
|
subQuery: false,
|
||||||
|
limit,
|
||||||
|
offset
|
||||||
|
})
|
||||||
|
|
||||||
|
const libraryItems = podcasts.map((podcastExpanded) => {
|
||||||
|
const libraryItem = podcastExpanded.libraryItem.toJSON()
|
||||||
|
const podcast = podcastExpanded.toJSON()
|
||||||
|
|
||||||
|
delete podcast.libraryItem
|
||||||
|
|
||||||
|
if (libraryItem.feeds?.length) {
|
||||||
|
libraryItem.rssFeed = libraryItem.feeds[0]
|
||||||
|
}
|
||||||
|
if (podcast.numEpisodesIncomplete) {
|
||||||
|
libraryItem.numEpisodesIncomplete = podcast.numEpisodesIncomplete
|
||||||
|
}
|
||||||
|
|
||||||
|
libraryItem.media = podcast
|
||||||
|
|
||||||
|
return libraryItem
|
||||||
|
})
|
||||||
|
Logger.debug('Found', libraryItems.length, 'library items', 'total=', count)
|
||||||
|
return {
|
||||||
|
libraryItems,
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user