mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-31 15:19:42 +02:00
Update library filter data to load from db and cache, update rss feed routes to load library items from db
This commit is contained in:
parent
8d03b23f46
commit
3651fffbee
13 changed files with 253 additions and 92 deletions
|
@ -5,12 +5,14 @@ const Logger = require('../Logger')
|
|||
const SocketAuthority = require('../SocketAuthority')
|
||||
const Library = require('../objects/Library')
|
||||
const libraryHelpers = require('../utils/libraryHelpers')
|
||||
const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')
|
||||
const { sort, createNewSortInstance } = require('../libs/fastSort')
|
||||
const naturalSort = createNewSortInstance({
|
||||
comparer: new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare
|
||||
})
|
||||
|
||||
const Database = require('../Database')
|
||||
const libraryFilters = require('../utils/queries/libraryFilters')
|
||||
|
||||
class LibraryController {
|
||||
constructor() { }
|
||||
|
@ -80,9 +82,11 @@ class LibraryController {
|
|||
async findOne(req, res) {
|
||||
const includeArray = (req.query.include || '').split(',')
|
||||
if (includeArray.includes('filterdata')) {
|
||||
const filterdata = await libraryFilters.getFilterData(req.library)
|
||||
|
||||
return res.json({
|
||||
filterdata: libraryHelpers.getDistinctFilterDataNew(req.libraryItems),
|
||||
issues: req.libraryItems.filter(li => li.hasIssues).length,
|
||||
filterdata,
|
||||
issues: filterdata.numIssues,
|
||||
numUserPlaylists: await Database.models.playlist.getNumPlaylistsForUserAndLibrary(req.user.id, req.library.id),
|
||||
library: req.library
|
||||
})
|
||||
|
@ -90,9 +94,15 @@ class LibraryController {
|
|||
return res.json(req.library)
|
||||
}
|
||||
|
||||
/**
|
||||
* GET: /api/libraries/:id/episode-downloads
|
||||
* Get podcast episodes in download queue
|
||||
* @param {*} req
|
||||
* @param {*} res
|
||||
*/
|
||||
async getEpisodeDownloadQueue(req, res) {
|
||||
const libraryDownloadQueueDetails = this.podcastManager.getDownloadQueueDetails(req.library.id)
|
||||
return res.json(libraryDownloadQueueDetails)
|
||||
res.json(libraryDownloadQueueDetails)
|
||||
}
|
||||
|
||||
async update(req, res) {
|
||||
|
@ -214,8 +224,12 @@ class LibraryController {
|
|||
res.json(payload)
|
||||
}
|
||||
|
||||
// api/libraries/:id/items
|
||||
// TODO: Optimize this method, items are iterated through several times but can be combined
|
||||
/**
|
||||
* GET: /api/libraries/:id/items
|
||||
* TODO: Remove after implementing getLibraryItemsNew
|
||||
* @param {*} req
|
||||
* @param {*} res
|
||||
*/
|
||||
async getLibraryItems(req, res) {
|
||||
let libraryItems = req.libraryItems
|
||||
|
||||
|
@ -431,7 +445,7 @@ class LibraryController {
|
|||
}
|
||||
|
||||
/**
|
||||
* api/libraries/:id/series
|
||||
* GET: /api/libraries/:id/series
|
||||
* Optional query string: `?include=rssfeed` that adds `rssFeed` to series if a feed is open
|
||||
*
|
||||
* @param {*} req
|
||||
|
@ -498,7 +512,7 @@ class LibraryController {
|
|||
}
|
||||
|
||||
/**
|
||||
* api/libraries/:id/series/:seriesId
|
||||
* GET: /api/libraries/:id/series/:seriesId
|
||||
*
|
||||
* Optional includes (e.g. `?include=rssfeed,progress`)
|
||||
* rssfeed: adds `rssFeed` to series object if a feed is open
|
||||
|
@ -513,7 +527,7 @@ class LibraryController {
|
|||
const series = Database.series.find(se => se.id === req.params.seriesId)
|
||||
if (!series) return res.sendStatus(404)
|
||||
|
||||
const libraryItemsInSeries = req.libraryItems.filter(li => li.media.metadata.hasSeries?.(series.id))
|
||||
const libraryItemsInSeries = await libraryItemsBookFilters.getLibraryItemsForSeries(series, req.user)
|
||||
|
||||
const seriesJson = series.toJSON()
|
||||
if (include.includes('progress')) {
|
||||
|
@ -533,7 +547,12 @@ class LibraryController {
|
|||
res.json(seriesJson)
|
||||
}
|
||||
|
||||
// api/libraries/:id/collections
|
||||
/**
|
||||
* GET: /api/libraries/:id/collections
|
||||
* Get all collections for library
|
||||
* @param {*} req
|
||||
* @param {*} res
|
||||
*/
|
||||
async getCollectionsForLibrary(req, res) {
|
||||
const include = (req.query.include || '').split(',').map(v => v.trim().toLowerCase()).filter(v => !!v)
|
||||
|
||||
|
@ -563,10 +582,15 @@ class LibraryController {
|
|||
res.json(payload)
|
||||
}
|
||||
|
||||
// api/libraries/:id/playlists
|
||||
/**
|
||||
* GET: /api/libraries/:id/playlists
|
||||
* Get playlists for user in library
|
||||
* @param {*} req
|
||||
* @param {*} res
|
||||
*/
|
||||
async getUserPlaylistsForLibrary(req, res) {
|
||||
let playlistsForUser = await Database.models.playlist.getPlaylistsForUserAndLibrary(req.user.id, req.library.id)
|
||||
playlistsForUser = playlistsForUser.map(p => p.toJSONExpanded(Database.libraryItems))
|
||||
playlistsForUser = await Promise.all(playlistsForUser.map(async p => p.getOldJsonExpanded()))
|
||||
|
||||
const payload = {
|
||||
results: [],
|
||||
|
@ -584,8 +608,14 @@ class LibraryController {
|
|||
res.json(payload)
|
||||
}
|
||||
|
||||
/**
|
||||
* GET: /api/libraries/:id/filterdata
|
||||
* @param {*} req
|
||||
* @param {*} res
|
||||
*/
|
||||
async getLibraryFilterData(req, res) {
|
||||
res.json(libraryHelpers.getDistinctFilterDataNew(req.libraryItems))
|
||||
const filterData = await libraryFilters.getFilterData(req.library)
|
||||
res.json(filterData)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -229,6 +229,10 @@ class MiscController {
|
|||
let tagMerged = false
|
||||
let numItemsUpdated = 0
|
||||
|
||||
// Update filter data
|
||||
Database.removeTagFromFilterData(tag)
|
||||
Database.addTagToFilterData(newTag)
|
||||
|
||||
const libraryItemsWithTag = await libraryItemFilters.getAllLibraryItemsWithTags([tag, newTag])
|
||||
for (const libraryItem of libraryItemsWithTag) {
|
||||
let existingTags = libraryItem.media.tags
|
||||
|
@ -275,6 +279,9 @@ class MiscController {
|
|||
// Get all items with tag
|
||||
const libraryItemsWithTag = await libraryItemFilters.getAllLibraryItemsWithTags([tag])
|
||||
|
||||
// Update filterdata
|
||||
Database.removeTagFromFilterData(tag)
|
||||
|
||||
let numItemsUpdated = 0
|
||||
// Remove tag from items
|
||||
for (const libraryItem of libraryItemsWithTag) {
|
||||
|
@ -356,6 +363,10 @@ class MiscController {
|
|||
let genreMerged = false
|
||||
let numItemsUpdated = 0
|
||||
|
||||
// Update filter data
|
||||
Database.removeGenreFromFilterData(genre)
|
||||
Database.addGenreToFilterData(newGenre)
|
||||
|
||||
const libraryItemsWithGenre = await libraryItemFilters.getAllLibraryItemsWithGenres([genre, newGenre])
|
||||
for (const libraryItem of libraryItemsWithGenre) {
|
||||
let existingGenres = libraryItem.media.genres
|
||||
|
@ -399,6 +410,9 @@ class MiscController {
|
|||
|
||||
const genre = Buffer.from(decodeURIComponent(req.params.genre), 'base64').toString()
|
||||
|
||||
// Update filter data
|
||||
Database.removeGenreFromFilterData(genre)
|
||||
|
||||
// Get all items with genre
|
||||
const libraryItemsWithGenre = await libraryItemFilters.getAllLibraryItemsWithGenres([genre])
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const Logger = require('../Logger')
|
||||
const Database = require('../Database')
|
||||
const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')
|
||||
|
||||
class RSSFeedController {
|
||||
constructor() { }
|
||||
|
@ -8,7 +9,7 @@ class RSSFeedController {
|
|||
async openRSSFeedForItem(req, res) {
|
||||
const options = req.body || {}
|
||||
|
||||
const item = Database.libraryItems.find(li => li.id === req.params.itemId)
|
||||
const item = await Database.models.libraryItem.getOldById(req.params.itemId)
|
||||
if (!item) return res.sendStatus(404)
|
||||
|
||||
// Check user can access this library item
|
||||
|
@ -45,7 +46,7 @@ class RSSFeedController {
|
|||
async openRSSFeedForCollection(req, res) {
|
||||
const options = req.body || {}
|
||||
|
||||
const collection = await Database.models.collection.getOldById(req.params.collectionId)
|
||||
const collection = await Database.models.collection.findByPk(req.params.collectionId)
|
||||
if (!collection) return res.sendStatus(404)
|
||||
|
||||
// Check request body options exist
|
||||
|
@ -60,7 +61,7 @@ class RSSFeedController {
|
|||
return res.status(400).send('Slug already in use')
|
||||
}
|
||||
|
||||
const collectionExpanded = collection.toJSONExpanded(Database.libraryItems)
|
||||
const collectionExpanded = await collection.getOldJsonExpanded()
|
||||
const collectionItemsWithTracks = collectionExpanded.books.filter(li => li.media.tracks.length)
|
||||
|
||||
// Check collection has audio tracks
|
||||
|
@ -95,8 +96,9 @@ class RSSFeedController {
|
|||
}
|
||||
|
||||
const seriesJson = series.toJSON()
|
||||
|
||||
// Get books in series that have audio tracks
|
||||
seriesJson.books = Database.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasSeries(series.id) && li.media.tracks.length)
|
||||
seriesJson.books = (await libraryItemsBookFilters.getLibraryItemsForSeries(series)).filter(li => li.media.numTracks)
|
||||
|
||||
// Check series has audio tracks
|
||||
if (!seriesJson.books.length) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const Logger = require('../Logger')
|
||||
const SocketAuthority = require('../SocketAuthority')
|
||||
const Database = require('../Database')
|
||||
const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')
|
||||
|
||||
class SeriesController {
|
||||
constructor() { }
|
||||
|
@ -25,7 +26,7 @@ class SeriesController {
|
|||
const libraryItemsInSeries = req.libraryItemsInSeries
|
||||
const libraryItemsFinished = libraryItemsInSeries.filter(li => {
|
||||
const mediaProgress = req.user.getMediaProgress(li.id)
|
||||
return mediaProgress && mediaProgress.isFinished
|
||||
return mediaProgress?.isFinished
|
||||
})
|
||||
seriesJson.progress = {
|
||||
libraryItemIds: libraryItemsInSeries.map(li => li.id),
|
||||
|
@ -62,18 +63,17 @@ class SeriesController {
|
|||
res.json(req.series.toJSON())
|
||||
}
|
||||
|
||||
middleware(req, res, next) {
|
||||
async middleware(req, res, next) {
|
||||
const series = Database.series.find(se => se.id === req.params.id)
|
||||
if (!series) return res.sendStatus(404)
|
||||
|
||||
/**
|
||||
* Filter out any library items not accessible to user
|
||||
*/
|
||||
const libraryItems = Database.libraryItems.filter(li => li.media.metadata.hasSeries?.(series.id))
|
||||
const libraryItemsAccessible = libraryItems.filter(li => req.user.checkCanAccessLibraryItem(li))
|
||||
if (libraryItems.length && !libraryItemsAccessible.length) {
|
||||
Logger.warn(`[SeriesController] User attempted to access series "${series.id}" without access to any of the books`, req.user)
|
||||
return res.sendStatus(403)
|
||||
const libraryItems = await libraryItemsBookFilters.getLibraryItemsForSeries(series, req.user)
|
||||
if (!libraryItems.length) {
|
||||
Logger.warn(`[SeriesController] User attempted to access series "${series.id}" with no accessible books`, req.user)
|
||||
return res.sendStatus(404)
|
||||
}
|
||||
|
||||
if (req.method == 'DELETE' && !req.user.canDelete) {
|
||||
|
@ -85,7 +85,7 @@ class SeriesController {
|
|||
}
|
||||
|
||||
req.series = series
|
||||
req.libraryItemsInSeries = libraryItemsAccessible
|
||||
req.libraryItemsInSeries = libraryItems
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,15 +99,15 @@ class ToolsController {
|
|||
res.sendStatus(200)
|
||||
}
|
||||
|
||||
middleware(req, res, next) {
|
||||
async middleware(req, res, next) {
|
||||
if (!req.user.isAdminOrUp) {
|
||||
Logger.error(`[LibraryItemController] Non-root user attempted to access tools route`, req.user)
|
||||
return res.sendStatus(403)
|
||||
}
|
||||
|
||||
if (req.params.id) {
|
||||
const item = Database.libraryItems.find(li => li.id === req.params.id)
|
||||
if (!item || !item.media) return res.sendStatus(404)
|
||||
const item = await Database.models.libraryItem.getOldById(req.params.id)
|
||||
if (!item?.media) return res.sendStatus(404)
|
||||
|
||||
// Check user can access this library item
|
||||
if (!req.user.checkCanAccessLibraryItem(item)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue