diff --git a/server/controllers/LibraryItemController.js b/server/controllers/LibraryItemController.js index fa6d5f2f..498398f7 100644 --- a/server/controllers/LibraryItemController.js +++ b/server/controllers/LibraryItemController.js @@ -225,15 +225,45 @@ class LibraryItemController { res.sendStatus(200) } - // GET api/items/:id/cover + /** + * GET: api/items/:id/cover + * + * @param {import('express').Request} req + * @param {import('express').Response} res + */ async getCover(req, res) { - const { query: { width, height, format, raw }, libraryItem } = req + const { query: { width, height, format, raw } } = req + + const libraryItem = await Database.libraryItemModel.findByPk(req.params.id, { + attributes: ['id', 'mediaType', 'mediaId', 'libraryId'], + include: [ + { + model: Database.bookModel, + attributes: ['id', 'coverPath', 'tags', 'explicit'] + }, + { + model: Database.podcastModel, + attributes: ['id', 'coverPath', 'tags', 'explicit'] + } + ] + }) + if (!libraryItem) { + Logger.warn(`[LibraryItemController] getCover: Library item "${req.params.id}" does not exist`) + return res.sendStatus(404) + } + + // Check if user can access this library item + if (!req.user.checkCanAccessLibraryItemWithData(libraryItem.libraryId, libraryItem.media.explicit, libraryItem.media.tags)) { + return res.sendStatus(403) + } + + // Check if library item media has a cover path + if (!libraryItem.media.coverPath || !await fs.pathExists(libraryItem.media.coverPath)) { + Logger.debug(`[LibraryItemController] getCover: Library item "${req.params.id}" has no cover path`) + return res.sendStatus(404) + } if (raw) { // any value - if (!libraryItem.media.coverPath || !await fs.pathExists(libraryItem.media.coverPath)) { - return res.sendStatus(404) - } - if (global.XAccel) { const encodedURI = encodeUriPath(global.XAccel + libraryItem.media.coverPath) Logger.debug(`Use X-Accel to serve static file ${encodedURI}`) @@ -247,7 +277,7 @@ class LibraryItemController { height: height ? parseInt(height) : null, width: width ? parseInt(width) : null } - return CacheManager.handleCoverCache(res, libraryItem, options) + return CacheManager.handleCoverCache(res, libraryItem.id, libraryItem.media.coverPath, options) } // GET: api/items/:id/stream diff --git a/server/managers/CacheManager.js b/server/managers/CacheManager.js index d7baee3b..c273d389 100644 --- a/server/managers/CacheManager.js +++ b/server/managers/CacheManager.js @@ -39,14 +39,14 @@ class CacheManager { } } - async handleCoverCache(res, libraryItem, options = {}) { + async handleCoverCache(res, libraryItemId, coverPath, options = {}) { const format = options.format || 'webp' const width = options.width || 400 const height = options.height || null res.type(`image/${format}`) - const path = Path.join(this.CoverCachePath, `${libraryItem.id}_${width}${height ? `x${height}` : ''}`) + '.' + format + const path = Path.join(this.CoverCachePath, `${libraryItemId}_${width}${height ? `x${height}` : ''}`) + '.' + format // Cache exists if (await fs.pathExists(path)) { @@ -67,11 +67,7 @@ class CacheManager { return ps.pipe(res) } - if (!libraryItem.media.coverPath || !await fs.pathExists(libraryItem.media.coverPath)) { - return res.sendStatus(500) - } - - const writtenFile = await resizeImage(libraryItem.media.coverPath, path, width, height) + const writtenFile = await resizeImage(coverPath, path, width, height) if (!writtenFile) return res.sendStatus(500) if (global.XAccel) { diff --git a/server/objects/user/User.js b/server/objects/user/User.js index 4bfcb105..1ed74bb2 100644 --- a/server/objects/user/User.js +++ b/server/objects/user/User.js @@ -326,6 +326,18 @@ class User { return this.checkCanAccessLibraryItemWithTags(libraryItem.media.tags) } + /** + * Checks if a user can access a library item + * @param {string} libraryId + * @param {boolean} explicit + * @param {string[]} tags + */ + checkCanAccessLibraryItemWithData(libraryId, explicit, tags) { + if (!this.checkCanAccessLibrary(libraryId)) return false + if (explicit && !this.canAccessExplicitContent) return false + return this.checkCanAccessLibraryItemWithTags(tags) + } + findBookmark(libraryItemId, time) { return this.bookmarks.find(bm => bm.libraryItemId === libraryItemId && bm.time == time) } diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js index 71d9429e..74d8aa56 100644 --- a/server/routers/ApiRouter.js +++ b/server/routers/ApiRouter.js @@ -99,7 +99,7 @@ class ApiRouter { this.router.delete('/items/:id', LibraryItemController.middleware.bind(this), LibraryItemController.delete.bind(this)) this.router.get('/items/:id/download', LibraryItemController.middleware.bind(this), LibraryItemController.download.bind(this)) this.router.patch('/items/:id/media', LibraryItemController.middleware.bind(this), LibraryItemController.updateMedia.bind(this)) - this.router.get('/items/:id/cover', LibraryItemController.middleware.bind(this), LibraryItemController.getCover.bind(this)) + this.router.get('/items/:id/cover', LibraryItemController.getCover.bind(this)) this.router.post('/items/:id/cover', LibraryItemController.middleware.bind(this), LibraryItemController.uploadCover.bind(this)) this.router.patch('/items/:id/cover', LibraryItemController.middleware.bind(this), LibraryItemController.updateCover.bind(this)) this.router.delete('/items/:id/cover', LibraryItemController.middleware.bind(this), LibraryItemController.removeCover.bind(this))