mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2024-12-30 18:48:55 +01:00
Update MiscController api routes to load library items from db
This commit is contained in:
parent
fc44c801f2
commit
8d03b23f46
@ -1,9 +1,11 @@
|
|||||||
|
const Sequelize = require('sequelize')
|
||||||
const Path = require('path')
|
const Path = require('path')
|
||||||
const fs = require('../libs/fsExtra')
|
const fs = require('../libs/fsExtra')
|
||||||
const Logger = require('../Logger')
|
const Logger = require('../Logger')
|
||||||
const SocketAuthority = require('../SocketAuthority')
|
const SocketAuthority = require('../SocketAuthority')
|
||||||
const Database = require('../Database')
|
const Database = require('../Database')
|
||||||
|
|
||||||
|
const libraryItemFilters = require('../utils/queries/libraryItemFilters')
|
||||||
const filePerms = require('../utils/filePerms')
|
const filePerms = require('../utils/filePerms')
|
||||||
const patternValidation = require('../libs/nodeCron/pattern-validation')
|
const patternValidation = require('../libs/nodeCron/pattern-validation')
|
||||||
const { isObject } = require('../utils/index')
|
const { isObject } = require('../utils/index')
|
||||||
@ -14,7 +16,12 @@ const { isObject } = require('../utils/index')
|
|||||||
class MiscController {
|
class MiscController {
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
// POST: api/upload
|
/**
|
||||||
|
* POST: /api/upload
|
||||||
|
* Update library item
|
||||||
|
* @param {*} req
|
||||||
|
* @param {*} res
|
||||||
|
*/
|
||||||
async handleUpload(req, res) {
|
async handleUpload(req, res) {
|
||||||
if (!req.user.canUpload) {
|
if (!req.user.canUpload) {
|
||||||
Logger.warn('User attempted to upload without permission', req.user)
|
Logger.warn('User attempted to upload without permission', req.user)
|
||||||
@ -88,7 +95,12 @@ class MiscController {
|
|||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: api/tasks
|
/**
|
||||||
|
* GET: /api/tasks
|
||||||
|
* Get tasks for task manager
|
||||||
|
* @param {*} req
|
||||||
|
* @param {*} res
|
||||||
|
*/
|
||||||
getTasks(req, res) {
|
getTasks(req, res) {
|
||||||
const includeArray = (req.query.include || '').split(',')
|
const includeArray = (req.query.include || '').split(',')
|
||||||
|
|
||||||
@ -105,7 +117,12 @@ class MiscController {
|
|||||||
res.json(data)
|
res.json(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PATCH: api/settings (admin)
|
/**
|
||||||
|
* PATCH: /api/settings
|
||||||
|
* Update server settings
|
||||||
|
* @param {*} req
|
||||||
|
* @param {*} res
|
||||||
|
*/
|
||||||
async updateServerSettings(req, res) {
|
async updateServerSettings(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.user.isAdminOrUp) {
|
||||||
Logger.error('User other than admin attempting to update server settings', req.user)
|
Logger.error('User other than admin attempting to update server settings', req.user)
|
||||||
@ -147,26 +164,55 @@ class MiscController {
|
|||||||
res.json(userResponse)
|
res.json(userResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: api/tags
|
/**
|
||||||
getAllTags(req, res) {
|
* GET: /api/tags
|
||||||
|
* Get all tags
|
||||||
|
* @param {*} req
|
||||||
|
* @param {*} res
|
||||||
|
*/
|
||||||
|
async getAllTags(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.user.isAdminOrUp) {
|
||||||
Logger.error(`[MiscController] Non-admin user attempted to getAllTags`)
|
Logger.error(`[MiscController] Non-admin user attempted to getAllTags`)
|
||||||
return res.sendStatus(404)
|
return res.sendStatus(404)
|
||||||
}
|
}
|
||||||
|
|
||||||
const tags = []
|
const tags = []
|
||||||
Database.libraryItems.forEach((li) => {
|
const books = await Database.models.book.findAll({
|
||||||
if (li.media.tags && li.media.tags.length) {
|
attributes: ['tags'],
|
||||||
li.media.tags.forEach((tag) => {
|
where: Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('tags')), {
|
||||||
|
[Sequelize.Op.gt]: 0
|
||||||
|
})
|
||||||
|
})
|
||||||
|
for (const book of books) {
|
||||||
|
for (const tag of book.tags) {
|
||||||
if (!tags.includes(tag)) tags.push(tag)
|
if (!tags.includes(tag)) tags.push(tag)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const podcasts = await Database.models.podcast.findAll({
|
||||||
|
attributes: ['tags'],
|
||||||
|
where: Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('tags')), {
|
||||||
|
[Sequelize.Op.gt]: 0
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
for (const podcast of podcasts) {
|
||||||
|
for (const tag of podcast.tags) {
|
||||||
|
if (!tags.includes(tag)) tags.push(tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
tags: tags
|
tags: tags
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST: api/tags/rename
|
/**
|
||||||
|
* POST: /api/tags/rename
|
||||||
|
* Rename tag
|
||||||
|
* Req.body { tag, newTag }
|
||||||
|
* @param {*} req
|
||||||
|
* @param {*} res
|
||||||
|
*/
|
||||||
async renameTag(req, res) {
|
async renameTag(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.user.isAdminOrUp) {
|
||||||
Logger.error(`[MiscController] Non-admin user attempted to renameTag`)
|
Logger.error(`[MiscController] Non-admin user attempted to renameTag`)
|
||||||
@ -183,19 +229,24 @@ class MiscController {
|
|||||||
let tagMerged = false
|
let tagMerged = false
|
||||||
let numItemsUpdated = 0
|
let numItemsUpdated = 0
|
||||||
|
|
||||||
for (const li of Database.libraryItems) {
|
const libraryItemsWithTag = await libraryItemFilters.getAllLibraryItemsWithTags([tag, newTag])
|
||||||
if (!li.media.tags || !li.media.tags.length) continue
|
for (const libraryItem of libraryItemsWithTag) {
|
||||||
|
let existingTags = libraryItem.media.tags
|
||||||
if (li.media.tags.includes(newTag)) tagMerged = true // new tag is an existing tag so this is a merge
|
if (existingTags.includes(newTag)) {
|
||||||
|
tagMerged = true // new tag is an existing tag so this is a merge
|
||||||
if (li.media.tags.includes(tag)) {
|
|
||||||
li.media.tags = li.media.tags.filter(t => t !== tag) // Remove old tag
|
|
||||||
if (!li.media.tags.includes(newTag)) {
|
|
||||||
li.media.tags.push(newTag) // Add new tag
|
|
||||||
}
|
}
|
||||||
Logger.debug(`[MiscController] Rename tag "${tag}" to "${newTag}" for item "${li.media.metadata.title}"`)
|
|
||||||
await Database.updateLibraryItem(li)
|
if (existingTags.includes(tag)) {
|
||||||
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
|
existingTags = existingTags.filter(t => t !== tag) // Remove old tag
|
||||||
|
if (!existingTags.includes(newTag)) {
|
||||||
|
existingTags.push(newTag)
|
||||||
|
}
|
||||||
|
Logger.debug(`[MiscController] Rename tag "${tag}" to "${newTag}" for item "${libraryItem.media.title}"`)
|
||||||
|
await libraryItem.media.update({
|
||||||
|
tags: existingTags
|
||||||
|
})
|
||||||
|
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(libraryItem)
|
||||||
|
SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
|
||||||
numItemsUpdated++
|
numItemsUpdated++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,7 +257,13 @@ class MiscController {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE: api/tags/:tag
|
/**
|
||||||
|
* DELETE: /api/tags/:tag
|
||||||
|
* Remove a tag
|
||||||
|
* :tag param is base64 encoded
|
||||||
|
* @param {*} req
|
||||||
|
* @param {*} res
|
||||||
|
*/
|
||||||
async deleteTag(req, res) {
|
async deleteTag(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.user.isAdminOrUp) {
|
||||||
Logger.error(`[MiscController] Non-admin user attempted to deleteTag`)
|
Logger.error(`[MiscController] Non-admin user attempted to deleteTag`)
|
||||||
@ -215,44 +272,74 @@ class MiscController {
|
|||||||
|
|
||||||
const tag = Buffer.from(decodeURIComponent(req.params.tag), 'base64').toString()
|
const tag = Buffer.from(decodeURIComponent(req.params.tag), 'base64').toString()
|
||||||
|
|
||||||
let numItemsUpdated = 0
|
// Get all items with tag
|
||||||
for (const li of Database.libraryItems) {
|
const libraryItemsWithTag = await libraryItemFilters.getAllLibraryItemsWithTags([tag])
|
||||||
if (!li.media.tags || !li.media.tags.length) continue
|
|
||||||
|
|
||||||
if (li.media.tags.includes(tag)) {
|
let numItemsUpdated = 0
|
||||||
li.media.tags = li.media.tags.filter(t => t !== tag)
|
// Remove tag from items
|
||||||
Logger.debug(`[MiscController] Remove tag "${tag}" from item "${li.media.metadata.title}"`)
|
for (const libraryItem of libraryItemsWithTag) {
|
||||||
await Database.updateLibraryItem(li)
|
Logger.debug(`[MiscController] Remove tag "${tag}" from item "${libraryItem.media.title}"`)
|
||||||
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
|
await libraryItem.media.update({
|
||||||
|
tags: libraryItem.media.tags.filter(t => t !== tag)
|
||||||
|
})
|
||||||
|
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(libraryItem)
|
||||||
|
SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
|
||||||
numItemsUpdated++
|
numItemsUpdated++
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
numItemsUpdated
|
numItemsUpdated
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: api/genres
|
/**
|
||||||
getAllGenres(req, res) {
|
* GET: /api/genres
|
||||||
|
* Get all genres
|
||||||
|
* @param {*} req
|
||||||
|
* @param {*} res
|
||||||
|
*/
|
||||||
|
async getAllGenres(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.user.isAdminOrUp) {
|
||||||
Logger.error(`[MiscController] Non-admin user attempted to getAllGenres`)
|
Logger.error(`[MiscController] Non-admin user attempted to getAllGenres`)
|
||||||
return res.sendStatus(404)
|
return res.sendStatus(404)
|
||||||
}
|
}
|
||||||
const genres = []
|
const genres = []
|
||||||
Database.libraryItems.forEach((li) => {
|
const books = await Database.models.book.findAll({
|
||||||
if (li.media.metadata.genres && li.media.metadata.genres.length) {
|
attributes: ['genres'],
|
||||||
li.media.metadata.genres.forEach((genre) => {
|
where: Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('genres')), {
|
||||||
if (!genres.includes(genre)) genres.push(genre)
|
[Sequelize.Op.gt]: 0
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
for (const book of books) {
|
||||||
|
for (const tag of book.genres) {
|
||||||
|
if (!genres.includes(tag)) genres.push(tag)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const podcasts = await Database.models.podcast.findAll({
|
||||||
|
attributes: ['genres'],
|
||||||
|
where: Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('genres')), {
|
||||||
|
[Sequelize.Op.gt]: 0
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
for (const podcast of podcasts) {
|
||||||
|
for (const tag of podcast.genres) {
|
||||||
|
if (!genres.includes(tag)) genres.push(tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
genres
|
genres
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST: api/genres/rename
|
/**
|
||||||
|
* POST: /api/genres/rename
|
||||||
|
* Rename genres
|
||||||
|
* Req.body { genre, newGenre }
|
||||||
|
* @param {*} req
|
||||||
|
* @param {*} res
|
||||||
|
*/
|
||||||
async renameGenre(req, res) {
|
async renameGenre(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.user.isAdminOrUp) {
|
||||||
Logger.error(`[MiscController] Non-admin user attempted to renameGenre`)
|
Logger.error(`[MiscController] Non-admin user attempted to renameGenre`)
|
||||||
@ -269,19 +356,24 @@ class MiscController {
|
|||||||
let genreMerged = false
|
let genreMerged = false
|
||||||
let numItemsUpdated = 0
|
let numItemsUpdated = 0
|
||||||
|
|
||||||
for (const li of Database.libraryItems) {
|
const libraryItemsWithGenre = await libraryItemFilters.getAllLibraryItemsWithGenres([genre, newGenre])
|
||||||
if (!li.media.metadata.genres || !li.media.metadata.genres.length) continue
|
for (const libraryItem of libraryItemsWithGenre) {
|
||||||
|
let existingGenres = libraryItem.media.genres
|
||||||
if (li.media.metadata.genres.includes(newGenre)) genreMerged = true // new genre is an existing genre so this is a merge
|
if (existingGenres.includes(newGenre)) {
|
||||||
|
genreMerged = true // new genre is an existing genre so this is a merge
|
||||||
if (li.media.metadata.genres.includes(genre)) {
|
|
||||||
li.media.metadata.genres = li.media.metadata.genres.filter(g => g !== genre) // Remove old genre
|
|
||||||
if (!li.media.metadata.genres.includes(newGenre)) {
|
|
||||||
li.media.metadata.genres.push(newGenre) // Add new genre
|
|
||||||
}
|
}
|
||||||
Logger.debug(`[MiscController] Rename genre "${genre}" to "${newGenre}" for item "${li.media.metadata.title}"`)
|
|
||||||
await Database.updateLibraryItem(li)
|
if (existingGenres.includes(genre)) {
|
||||||
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
|
existingGenres = existingGenres.filter(t => t !== genre) // Remove old genre
|
||||||
|
if (!existingGenres.includes(newGenre)) {
|
||||||
|
existingGenres.push(newGenre)
|
||||||
|
}
|
||||||
|
Logger.debug(`[MiscController] Rename genre "${genre}" to "${newGenre}" for item "${libraryItem.media.title}"`)
|
||||||
|
await libraryItem.media.update({
|
||||||
|
genres: existingGenres
|
||||||
|
})
|
||||||
|
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(libraryItem)
|
||||||
|
SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
|
||||||
numItemsUpdated++
|
numItemsUpdated++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,7 +384,13 @@ class MiscController {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE: api/genres/:genre
|
/**
|
||||||
|
* DELETE: /api/genres/:genre
|
||||||
|
* Remove a genre
|
||||||
|
* :genre param is base64 encoded
|
||||||
|
* @param {*} req
|
||||||
|
* @param {*} res
|
||||||
|
*/
|
||||||
async deleteGenre(req, res) {
|
async deleteGenre(req, res) {
|
||||||
if (!req.user.isAdminOrUp) {
|
if (!req.user.isAdminOrUp) {
|
||||||
Logger.error(`[MiscController] Non-admin user attempted to deleteGenre`)
|
Logger.error(`[MiscController] Non-admin user attempted to deleteGenre`)
|
||||||
@ -301,18 +399,20 @@ class MiscController {
|
|||||||
|
|
||||||
const genre = Buffer.from(decodeURIComponent(req.params.genre), 'base64').toString()
|
const genre = Buffer.from(decodeURIComponent(req.params.genre), 'base64').toString()
|
||||||
|
|
||||||
let numItemsUpdated = 0
|
// Get all items with genre
|
||||||
for (const li of Database.libraryItems) {
|
const libraryItemsWithGenre = await libraryItemFilters.getAllLibraryItemsWithGenres([genre])
|
||||||
if (!li.media.metadata.genres || !li.media.metadata.genres.length) continue
|
|
||||||
|
|
||||||
if (li.media.metadata.genres.includes(genre)) {
|
let numItemsUpdated = 0
|
||||||
li.media.metadata.genres = li.media.metadata.genres.filter(t => t !== genre)
|
// Remove genre from items
|
||||||
Logger.debug(`[MiscController] Remove genre "${genre}" from item "${li.media.metadata.title}"`)
|
for (const libraryItem of libraryItemsWithGenre) {
|
||||||
await Database.updateLibraryItem(li)
|
Logger.debug(`[MiscController] Remove genre "${genre}" from item "${libraryItem.media.title}"`)
|
||||||
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
|
await libraryItem.media.update({
|
||||||
|
genres: libraryItem.media.genres.filter(g => g !== genre)
|
||||||
|
})
|
||||||
|
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(libraryItem)
|
||||||
|
SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
|
||||||
numItemsUpdated++
|
numItemsUpdated++
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
numItemsUpdated
|
numItemsUpdated
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
const Sequelize = require('sequelize')
|
const Sequelize = require('sequelize')
|
||||||
const Database = require('../../Database')
|
const Database = require('../../Database')
|
||||||
const Logger = require('../../Logger')
|
|
||||||
const libraryItemsBookFilters = require('./libraryItemsBookFilters')
|
const libraryItemsBookFilters = require('./libraryItemsBookFilters')
|
||||||
const libraryItemsPodcastFilters = require('./libraryItemsPodcastFilters')
|
const libraryItemsPodcastFilters = require('./libraryItemsPodcastFilters')
|
||||||
|
|
||||||
|
126
server/utils/queries/libraryItemFilters.js
Normal file
126
server/utils/queries/libraryItemFilters.js
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
const Sequelize = require('sequelize')
|
||||||
|
const Database = require('../../Database')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Get all library items that have tags
|
||||||
|
* @param {string[]} tags
|
||||||
|
* @returns {Promise<LibraryItem[]>}
|
||||||
|
*/
|
||||||
|
async getAllLibraryItemsWithTags(tags) {
|
||||||
|
const libraryItems = []
|
||||||
|
const booksWithTag = await Database.models.book.findAll({
|
||||||
|
where: Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:tags))`), {
|
||||||
|
[Sequelize.Op.gte]: 1
|
||||||
|
}),
|
||||||
|
replacements: {
|
||||||
|
tags
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Database.models.libraryItem
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.models.author,
|
||||||
|
through: {
|
||||||
|
attributes: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.models.series,
|
||||||
|
through: {
|
||||||
|
attributes: ['sequence']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
for (const book of booksWithTag) {
|
||||||
|
const libraryItem = book.libraryItem
|
||||||
|
libraryItem.media = book
|
||||||
|
libraryItems.push(libraryItem)
|
||||||
|
}
|
||||||
|
const podcastsWithTag = await Database.models.podcast.findAll({
|
||||||
|
where: Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:tags))`), {
|
||||||
|
[Sequelize.Op.gte]: 1
|
||||||
|
}),
|
||||||
|
replacements: {
|
||||||
|
tags
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Database.models.libraryItem
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.models.podcastEpisode
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
for (const podcast of podcastsWithTag) {
|
||||||
|
const libraryItem = podcast.libraryItem
|
||||||
|
libraryItem.media = podcast
|
||||||
|
libraryItems.push(libraryItem)
|
||||||
|
}
|
||||||
|
return libraryItems
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all library items that have genres
|
||||||
|
* @param {string[]} genres
|
||||||
|
* @returns {Promise<LibraryItem[]>}
|
||||||
|
*/
|
||||||
|
async getAllLibraryItemsWithGenres(genres) {
|
||||||
|
const libraryItems = []
|
||||||
|
const booksWithGenre = await Database.models.book.findAll({
|
||||||
|
where: Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(genres) WHERE json_valid(genres) AND json_each.value IN (:genres))`), {
|
||||||
|
[Sequelize.Op.gte]: 1
|
||||||
|
}),
|
||||||
|
replacements: {
|
||||||
|
genres
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Database.models.libraryItem
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.models.author,
|
||||||
|
through: {
|
||||||
|
attributes: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.models.series,
|
||||||
|
through: {
|
||||||
|
attributes: ['sequence']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
for (const book of booksWithGenre) {
|
||||||
|
const libraryItem = book.libraryItem
|
||||||
|
libraryItem.media = book
|
||||||
|
libraryItems.push(libraryItem)
|
||||||
|
}
|
||||||
|
const podcastsWithGenre = await Database.models.podcast.findAll({
|
||||||
|
where: Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(genres) WHERE json_valid(genres) AND json_each.value IN (:genres))`), {
|
||||||
|
[Sequelize.Op.gte]: 1
|
||||||
|
}),
|
||||||
|
replacements: {
|
||||||
|
genres
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Database.models.libraryItem
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.models.podcastEpisode
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
for (const podcast of podcastsWithGenre) {
|
||||||
|
const libraryItem = podcast.libraryItem
|
||||||
|
libraryItem.media = podcast
|
||||||
|
libraryItems.push(libraryItem)
|
||||||
|
}
|
||||||
|
return libraryItems
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user