mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-02-10 00:18:06 +01:00
Update library collections api endpoint to use libraryItems from db
This commit is contained in:
parent
aac2879652
commit
38029d1202
@ -8,22 +8,23 @@ class CollectionController {
|
|||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
async create(req, res) {
|
async create(req, res) {
|
||||||
var newCollection = new Collection()
|
const newCollection = new Collection()
|
||||||
req.body.userId = req.user.id
|
req.body.userId = req.user.id
|
||||||
var success = newCollection.setData(req.body)
|
if (!newCollection.setData(req.body)) {
|
||||||
if (!success) {
|
|
||||||
return res.status(500).send('Invalid collection data')
|
return res.status(500).send('Invalid collection data')
|
||||||
}
|
}
|
||||||
var jsonExpanded = newCollection.toJSONExpanded(Database.libraryItems)
|
|
||||||
|
const libraryItemsInCollection = await Database.models.libraryItem.getForCollection(newCollection)
|
||||||
|
const jsonExpanded = newCollection.toJSONExpanded(libraryItemsInCollection)
|
||||||
await Database.createCollection(newCollection)
|
await Database.createCollection(newCollection)
|
||||||
SocketAuthority.emitter('collection_added', jsonExpanded)
|
SocketAuthority.emitter('collection_added', jsonExpanded)
|
||||||
res.json(jsonExpanded)
|
res.json(jsonExpanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll(req, res) {
|
async findAll(req, res) {
|
||||||
const collections = await Database.models.collection.getOldCollections()
|
const collectionsExpanded = await Database.models.collection.getOldCollectionsJsonExpanded(req.user)
|
||||||
res.json({
|
res.json({
|
||||||
collections: collections.map(c => c.toJSONExpanded(Database.libraryItems))
|
collections: collectionsExpanded
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,8 +535,6 @@ class LibraryController {
|
|||||||
|
|
||||||
// api/libraries/:id/collections
|
// api/libraries/:id/collections
|
||||||
async getCollectionsForLibrary(req, res) {
|
async getCollectionsForLibrary(req, res) {
|
||||||
const libraryItems = req.libraryItems
|
|
||||||
|
|
||||||
const include = (req.query.include || '').split(',').map(v => v.trim().toLowerCase()).filter(v => !!v)
|
const include = (req.query.include || '').split(',').map(v => v.trim().toLowerCase()).filter(v => !!v)
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
@ -551,23 +549,8 @@ class LibraryController {
|
|||||||
include: include.join(',')
|
include: include.join(',')
|
||||||
}
|
}
|
||||||
|
|
||||||
const collectionsForLibrary = await Database.models.collection.getAllForLibrary(req.library.id)
|
// TODO: Create paginated queries
|
||||||
|
let collections = await Database.models.collection.getOldCollectionsJsonExpanded(req.user, req.library.id, include)
|
||||||
let collections = await Promise.all(collectionsForLibrary.map(async c => {
|
|
||||||
const expanded = c.toJSONExpanded(libraryItems, payload.minified)
|
|
||||||
|
|
||||||
// If all books restricted to user in this collection then hide this collection
|
|
||||||
if (!expanded.books.length && c.books.length) return null
|
|
||||||
|
|
||||||
if (include.includes('rssfeed')) {
|
|
||||||
const feedData = await this.rssFeedManager.findFeedForEntityId(c.id)
|
|
||||||
expanded.rssFeed = feedData?.toJSONMinified() || null
|
|
||||||
}
|
|
||||||
|
|
||||||
return expanded
|
|
||||||
}))
|
|
||||||
|
|
||||||
collections = collections.filter(c => !!c)
|
|
||||||
|
|
||||||
payload.total = collections.length
|
payload.total = collections.length
|
||||||
|
|
||||||
@ -964,6 +947,12 @@ class LibraryController {
|
|||||||
res.send(opmlText)
|
res.send(opmlText)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Replace with middlewareNew
|
||||||
|
* @param {*} req
|
||||||
|
* @param {*} res
|
||||||
|
* @param {*} next
|
||||||
|
*/
|
||||||
async middleware(req, res, next) {
|
async middleware(req, res, next) {
|
||||||
if (!req.user.checkCanAccessLibrary(req.params.id)) {
|
if (!req.user.checkCanAccessLibrary(req.params.id)) {
|
||||||
Logger.warn(`[LibraryController] Library ${req.params.id} not accessible to user ${req.user.username}`)
|
Logger.warn(`[LibraryController] Library ${req.params.id} not accessible to user ${req.user.username}`)
|
||||||
@ -980,5 +969,25 @@ class LibraryController {
|
|||||||
})
|
})
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Middleware that is not using libraryItems from memory
|
||||||
|
* @param {*} req
|
||||||
|
* @param {*} res
|
||||||
|
* @param {*} next
|
||||||
|
*/
|
||||||
|
async middlewareNew(req, res, next) {
|
||||||
|
if (!req.user.checkCanAccessLibrary(req.params.id)) {
|
||||||
|
Logger.warn(`[LibraryController] Library ${req.params.id} not accessible to user ${req.user.username}`)
|
||||||
|
return res.sendStatus(403)
|
||||||
|
}
|
||||||
|
|
||||||
|
const library = await Database.models.library.getOldById(req.params.id)
|
||||||
|
if (!library) {
|
||||||
|
return res.status(404).send('Library not found')
|
||||||
|
}
|
||||||
|
req.library = library
|
||||||
|
next()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
module.exports = new LibraryController()
|
module.exports = new LibraryController()
|
||||||
|
@ -5,6 +5,10 @@ const { areEquivalent } = require('../utils/index')
|
|||||||
|
|
||||||
module.exports = (sequelize) => {
|
module.exports = (sequelize) => {
|
||||||
class Collection extends Model {
|
class Collection extends Model {
|
||||||
|
/**
|
||||||
|
* Get all old collections
|
||||||
|
* @returns {Promise<oldCollection[]>}
|
||||||
|
*/
|
||||||
static async getOldCollections() {
|
static async getOldCollections() {
|
||||||
const collections = await this.findAll({
|
const collections = await this.findAll({
|
||||||
include: {
|
include: {
|
||||||
@ -16,6 +20,103 @@ module.exports = (sequelize) => {
|
|||||||
return collections.map(c => this.getOldCollection(c))
|
return collections.map(c => this.getOldCollection(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all old collections toJSONExpanded, items filtered for user permissions
|
||||||
|
* @param {[oldUser]} user
|
||||||
|
* @param {[string]} libraryId
|
||||||
|
* @param {[string[]]} include
|
||||||
|
* @returns {Promise<object[]>} oldCollection.toJSONExpanded
|
||||||
|
*/
|
||||||
|
static async getOldCollectionsJsonExpanded(user, libraryId, include) {
|
||||||
|
let collectionWhere = null
|
||||||
|
if (libraryId) {
|
||||||
|
collectionWhere = {
|
||||||
|
libraryId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optionally include rssfeed for collection
|
||||||
|
const collectionIncludes = []
|
||||||
|
if (include.includes('rssfeed')) {
|
||||||
|
collectionIncludes.push({
|
||||||
|
model: sequelize.models.feed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const collections = await this.findAll({
|
||||||
|
where: collectionWhere,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: sequelize.models.book,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: sequelize.models.libraryItem
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: sequelize.models.author,
|
||||||
|
through: {
|
||||||
|
attributes: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: sequelize.models.series,
|
||||||
|
through: {
|
||||||
|
attributes: ['sequence']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
...collectionIncludes
|
||||||
|
],
|
||||||
|
order: [[sequelize.models.book, sequelize.models.collectionBook, 'order', 'ASC']]
|
||||||
|
})
|
||||||
|
// TODO: Handle user permission restrictions on initial query
|
||||||
|
return collections.map(c => {
|
||||||
|
const oldCollection = this.getOldCollection(c)
|
||||||
|
|
||||||
|
// Filter books using user permissions
|
||||||
|
const books = c.books?.filter(b => {
|
||||||
|
if (user) {
|
||||||
|
if (b.tags?.length && !user.checkCanAccessLibraryItemWithTags(b.tags)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (b.explicit === true && !user.canAccessExplicitContent) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}) || []
|
||||||
|
|
||||||
|
// Map to library items
|
||||||
|
const libraryItems = books.map(b => {
|
||||||
|
const libraryItem = b.libraryItem
|
||||||
|
delete b.libraryItem
|
||||||
|
libraryItem.media = b
|
||||||
|
return sequelize.models.libraryItem.getOldLibraryItem(libraryItem)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Users with restricted permissions will not see this collection
|
||||||
|
if (!books.length && oldCollection.books.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const collectionExpanded = oldCollection.toJSONExpanded(libraryItems)
|
||||||
|
|
||||||
|
// Map feed if found
|
||||||
|
if (c.feeds?.length) {
|
||||||
|
collectionExpanded.rssFeed = sequelize.models.feed.getOldFeed(c.feeds[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return collectionExpanded
|
||||||
|
}).filter(c => c)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get old collection from Collection
|
||||||
|
* @param {Collection} collectionExpanded
|
||||||
|
* @returns {oldCollection}
|
||||||
|
*/
|
||||||
static getOldCollection(collectionExpanded) {
|
static getOldCollection(collectionExpanded) {
|
||||||
const libraryItemIds = collectionExpanded.books?.map(b => b.libraryItem?.id || null).filter(lid => lid) || []
|
const libraryItemIds = collectionExpanded.books?.map(b => b.libraryItem?.id || null).filter(lid => lid) || []
|
||||||
return new oldCollection({
|
return new oldCollection({
|
||||||
|
@ -16,6 +16,11 @@ module.exports = (sequelize) => {
|
|||||||
return feeds.map(f => this.getOldFeed(f))
|
return feeds.map(f => this.getOldFeed(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get old feed from Feed and optionally Feed with FeedEpisodes
|
||||||
|
* @param {Feed} feedExpanded
|
||||||
|
* @returns {oldFeed}
|
||||||
|
*/
|
||||||
static getOldFeed(feedExpanded) {
|
static getOldFeed(feedExpanded) {
|
||||||
const episodes = feedExpanded.feedEpisodes?.map((feedEpisode) => feedEpisode.getOldEpisode())
|
const episodes = feedExpanded.feedEpisodes?.map((feedEpisode) => feedEpisode.getOldEpisode())
|
||||||
return new oldFeed({
|
return new oldFeed({
|
||||||
|
@ -661,13 +661,23 @@ module.exports = (sequelize) => {
|
|||||||
* Get book library items for author, optional use user permissions
|
* Get book library items for author, optional use user permissions
|
||||||
* @param {oldAuthor} author
|
* @param {oldAuthor} author
|
||||||
* @param {[oldUser]} user
|
* @param {[oldUser]} user
|
||||||
* @returns {oldLibraryItem[]}
|
* @returns {Promise<oldLibraryItem[]>}
|
||||||
*/
|
*/
|
||||||
static async getForAuthor(author, user = null) {
|
static async getForAuthor(author, user = null) {
|
||||||
const { libraryItems } = await libraryFilters.getLibraryItemsForAuthor(author, user, undefined, undefined)
|
const { libraryItems } = await libraryFilters.getLibraryItemsForAuthor(author, user, undefined, undefined)
|
||||||
return libraryItems.map(li => this.getOldLibraryItem(li))
|
return libraryItems.map(li => this.getOldLibraryItem(li))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get book library items in a collection
|
||||||
|
* @param {oldCollection} collection
|
||||||
|
* @returns {Promise<oldLibraryItem[]>}
|
||||||
|
*/
|
||||||
|
static async getForCollection(collection) {
|
||||||
|
const libraryItems = await libraryFilters.getLibraryItemsForCollection(collection)
|
||||||
|
return libraryItems.map(li => this.getOldLibraryItem(li))
|
||||||
|
}
|
||||||
|
|
||||||
getMedia(options) {
|
getMedia(options) {
|
||||||
if (!this.mediaType) return Promise.resolve(null)
|
if (!this.mediaType) return Promise.resolve(null)
|
||||||
const mixinMethodName = `get${sequelize.uppercaseFirst(this.mediaType)}`
|
const mixinMethodName = `get${sequelize.uppercaseFirst(this.mediaType)}`
|
||||||
|
@ -74,16 +74,16 @@ class ApiRouter {
|
|||||||
this.router.patch('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.update.bind(this))
|
this.router.patch('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.update.bind(this))
|
||||||
this.router.delete('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.delete.bind(this))
|
this.router.delete('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.delete.bind(this))
|
||||||
|
|
||||||
this.router.get('/libraries/:id/items2', LibraryController.middleware.bind(this), LibraryController.getLibraryItemsNew.bind(this))
|
this.router.get('/libraries/:id/items2', LibraryController.middlewareNew.bind(this), LibraryController.getLibraryItemsNew.bind(this))
|
||||||
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.middleware.bind(this), LibraryController.removeLibraryItemsWithIssues.bind(this))
|
this.router.delete('/libraries/:id/issues', LibraryController.middleware.bind(this), LibraryController.removeLibraryItemsWithIssues.bind(this))
|
||||||
this.router.get('/libraries/:id/episode-downloads', LibraryController.middleware.bind(this), LibraryController.getEpisodeDownloadQueue.bind(this))
|
this.router.get('/libraries/:id/episode-downloads', LibraryController.middleware.bind(this), LibraryController.getEpisodeDownloadQueue.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.middleware.bind(this), LibraryController.getSeriesForLibrary.bind(this))
|
this.router.get('/libraries/:id/series/:seriesId', LibraryController.middleware.bind(this), LibraryController.getSeriesForLibrary.bind(this))
|
||||||
this.router.get('/libraries/:id/collections', LibraryController.middleware.bind(this), LibraryController.getCollectionsForLibrary.bind(this))
|
this.router.get('/libraries/:id/collections', LibraryController.middlewareNew.bind(this), LibraryController.getCollectionsForLibrary.bind(this))
|
||||||
this.router.get('/libraries/:id/playlists', LibraryController.middleware.bind(this), LibraryController.getUserPlaylistsForLibrary.bind(this))
|
this.router.get('/libraries/:id/playlists', LibraryController.middleware.bind(this), LibraryController.getUserPlaylistsForLibrary.bind(this))
|
||||||
this.router.get('/libraries/:id/albums', LibraryController.middleware.bind(this), LibraryController.getAlbumsForLibrary.bind(this))
|
this.router.get('/libraries/:id/albums', LibraryController.middleware.bind(this), LibraryController.getAlbumsForLibrary.bind(this))
|
||||||
this.router.get('/libraries/:id/personalized2', LibraryController.middleware.bind(this), LibraryController.getUserPersonalizedShelves.bind(this))
|
this.router.get('/libraries/:id/personalized2', LibraryController.middlewareNew.bind(this), LibraryController.getUserPersonalizedShelves.bind(this))
|
||||||
this.router.get('/libraries/:id/personalized', LibraryController.middleware.bind(this), LibraryController.getLibraryUserPersonalizedOptimal.bind(this))
|
this.router.get('/libraries/:id/personalized', LibraryController.middleware.bind(this), LibraryController.getLibraryUserPersonalizedOptimal.bind(this))
|
||||||
this.router.get('/libraries/:id/filterdata', LibraryController.middleware.bind(this), LibraryController.getLibraryFilterData.bind(this))
|
this.router.get('/libraries/:id/filterdata', LibraryController.middleware.bind(this), LibraryController.getLibraryFilterData.bind(this))
|
||||||
this.router.get('/libraries/:id/search', LibraryController.middleware.bind(this), LibraryController.search.bind(this))
|
this.router.get('/libraries/:id/search', LibraryController.middleware.bind(this), LibraryController.search.bind(this))
|
||||||
|
@ -365,7 +365,7 @@ module.exports = {
|
|||||||
* @param {[oldUser]} user
|
* @param {[oldUser]} user
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @param {number} offset
|
* @param {number} offset
|
||||||
* @returns {object} { libraryItems:LibraryItem[], count:number }
|
* @returns {Promise<object>} { libraryItems:LibraryItem[], count:number }
|
||||||
*/
|
*/
|
||||||
async getLibraryItemsForAuthor(author, user, limit, offset) {
|
async getLibraryItemsForAuthor(author, user, limit, offset) {
|
||||||
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(author.libraryId, user, 'authors', author.id, 'addedAt', true, false, [], limit, offset)
|
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(author.libraryId, user, 'authors', author.id, 'addedAt', true, false, [], limit, offset)
|
||||||
@ -373,5 +373,14 @@ module.exports = {
|
|||||||
count,
|
count,
|
||||||
libraryItems
|
libraryItems
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get book library items in a collection
|
||||||
|
* @param {oldCollection} collection
|
||||||
|
* @returns {Promise<LibraryItem[]>}
|
||||||
|
*/
|
||||||
|
getLibraryItemsForCollection(collection) {
|
||||||
|
return libraryItemsBookFilters.getLibraryItemsForCollection(collection)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -548,7 +548,7 @@ module.exports = {
|
|||||||
replacements,
|
replacements,
|
||||||
benchmark: true,
|
benchmark: true,
|
||||||
logging: (sql, timeMs) => {
|
logging: (sql, timeMs) => {
|
||||||
console.log(`[Query] Elapsed ${timeMs}ms.`)
|
console.log(`[Query] Elapsed ${timeMs}ms`)
|
||||||
},
|
},
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
@ -870,5 +870,48 @@ module.exports = {
|
|||||||
libraryItems,
|
libraryItems,
|
||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get book library items in a collection
|
||||||
|
* @param {oldCollection} collection
|
||||||
|
* @returns {Promise<LibraryItem[]>}
|
||||||
|
*/
|
||||||
|
async getLibraryItemsForCollection(collection) {
|
||||||
|
if (!collection?.books?.length) {
|
||||||
|
Logger.error(`[libraryItemsBookFilters] Invalid collection`, collection)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const books = await Database.models.book.findAll({
|
||||||
|
where: {
|
||||||
|
id: {
|
||||||
|
[Sequelize.Op.in]: collection.books
|
||||||
|
}
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Database.models.libraryItem
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: sequelize.models.author,
|
||||||
|
through: {
|
||||||
|
attributes: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: sequelize.models.series,
|
||||||
|
through: {
|
||||||
|
attributes: ['sequence']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
return books.map((book) => {
|
||||||
|
const libraryItem = book.libraryItem
|
||||||
|
delete book.libraryItem
|
||||||
|
libraryItem.media = book
|
||||||
|
return libraryItem
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user