1
0
mirror of https://github.com/advplyr/audiobookshelf.git synced 2025-07-25 01:35:33 +02:00
Files
.devcontainer
.github
.vscode
build
client
docs
images
server
controllers
AuthorController.js
BackupController.js
CacheController.js
CollectionController.js
FileSystemController.js
LibraryController.js
LibraryItemController.js
MeController.js
MiscController.js
NotificationController.js
PlaylistController.js
PodcastController.js
RSSFeedController.js
SearchController.js
SeriesController.js
SessionController.js
ToolsController.js
UserController.js
finders
libs
managers
objects
providers
routers
scanner
utils
Auth.js
Db.js
Logger.js
Server.js
SocketAuthority.js
Watcher.js
.dockerignore
.gitattributes
.gitignore
Dockerfile
LICENSE
docker-compose.yml
docker-template.xml
index.js
package-lock.json
package.json
prod.js
readme.md
audiobookshelf/server/controllers/PlaylistController.js
2022-12-17 17:31:19 -06:00

226 lines
7.8 KiB
JavaScript

const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Playlist = require('../objects/Playlist')
class PlaylistController {
constructor() { }
// POST: api/playlists
async create(req, res) {
const newPlaylist = new Playlist()
req.body.userId = req.user.id
const success = newPlaylist.setData(req.body)
if (!success) {
return res.status(400).send('Invalid playlist request data')
}
const jsonExpanded = newPlaylist.toJSONExpanded(this.db.libraryItems)
await this.db.insertEntity('playlist', newPlaylist)
SocketAuthority.clientEmitter(newPlaylist.userId, 'playlist_added', jsonExpanded)
res.json(jsonExpanded)
}
// GET: api/playlists
findAllForUser(req, res) {
res.json({
playlists: this.db.playlists.filter(p => p.userId === req.user.id).map(p => p.toJSONExpanded(this.db.libraryItems))
})
}
// GET: api/playlists/:id
findOne(req, res) {
res.json(req.playlist.toJSONExpanded(this.db.libraryItems))
}
// PATCH: api/playlists/:id
async update(req, res) {
const playlist = req.playlist
let wasUpdated = playlist.update(req.body)
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
if (wasUpdated) {
await this.db.updateEntity('playlist', playlist)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_updated', jsonExpanded)
}
res.json(jsonExpanded)
}
// DELETE: api/playlists/:id
async delete(req, res) {
const playlist = req.playlist
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
await this.db.removeEntity('playlist', playlist.id)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_removed', jsonExpanded)
res.sendStatus(200)
}
// POST: api/playlists/:id/item
async addItem(req, res) {
const playlist = req.playlist
const itemToAdd = req.body
if (!itemToAdd.libraryItemId) {
return res.status(400).send('Request body has no libraryItemId')
}
const libraryItem = this.db.libraryItems.find(li => li.id === itemToAdd.libraryItemId)
if (!libraryItem) {
return res.status(400).send('Library item not found')
}
if (libraryItem.libraryId !== playlist.libraryId) {
return res.status(400).send('Library item in different library')
}
if (playlist.containsItem(itemToAdd)) {
return res.status(400).send('Item already in playlist')
}
if ((itemToAdd.episodeId && !libraryItem.isPodcast) || (libraryItem.isPodcast && !itemToAdd.episodeId)) {
return res.status(400).send('Invalid item to add for this library type')
}
if (itemToAdd.episodeId && !libraryItem.media.checkHasEpisode(itemToAdd.episodeId)) {
return res.status(400).send('Episode not found in library item')
}
playlist.addItem(itemToAdd.libraryItemId, itemToAdd.episodeId)
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
await this.db.updateEntity('playlist', playlist)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_updated', jsonExpanded)
res.json(jsonExpanded)
}
// DELETE: api/playlists/:id/item/:libraryItemId/:episodeId?
async removeItem(req, res) {
const playlist = req.playlist
const itemToRemove = {
libraryItemId: req.params.libraryItemId,
episodeId: req.params.episodeId || null
}
if (!playlist.containsItem(itemToRemove)) {
return res.sendStatus(404)
}
playlist.removeItem(itemToRemove.libraryItemId, itemToRemove.episodeId)
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
// Playlist is removed when there are no items
if (!playlist.items.length) {
Logger.info(`[PlaylistController] Playlist "${playlist.name}" has no more items - removing it`)
await this.db.removeEntity('playlist', playlist.id)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_removed', jsonExpanded)
} else {
await this.db.updateEntity('playlist', playlist)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_updated', jsonExpanded)
}
res.json(jsonExpanded)
}
// POST: api/playlists/:id/batch/add
async addBatch(req, res) {
const playlist = req.playlist
if (!req.body.items || !req.body.items.length) {
return res.status(500).send('Invalid request body')
}
const itemsToAdd = req.body.items
let hasUpdated = false
for (const item of itemsToAdd) {
if (!item.libraryItemId) {
return res.status(400).send('Item does not have libraryItemId')
}
if (!playlist.containsItem(item)) {
playlist.addItem(item.libraryItemId, item.episodeId)
hasUpdated = true
}
}
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
if (hasUpdated) {
await this.db.updateEntity('playlist', playlist)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_updated', jsonExpanded)
}
res.json(jsonExpanded)
}
// POST: api/playlists/:id/batch/remove
async removeBatch(req, res) {
const playlist = req.playlist
if (!req.body.items || !req.body.items.length) {
return res.status(500).send('Invalid request body')
}
const itemsToRemove = req.body.items
let hasUpdated = false
for (const item of itemsToRemove) {
if (!item.libraryItemId) {
return res.status(400).send('Item does not have libraryItemId')
}
if (playlist.containsItem(item)) {
playlist.removeItem(item.libraryItemId, item.episodeId)
hasUpdated = true
}
}
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
if (hasUpdated) {
// Playlist is removed when there are no items
if (!playlist.items.length) {
Logger.info(`[PlaylistController] Playlist "${playlist.name}" has no more items - removing it`)
await this.db.removeEntity('playlist', playlist.id)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_removed', jsonExpanded)
} else {
await this.db.updateEntity('playlist', playlist)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_updated', jsonExpanded)
}
}
res.json(jsonExpanded)
}
// POST: api/playlists/collection/:collectionId
async createFromCollection(req, res) {
let collection = this.db.collections.find(c => c.id === req.params.collectionId)
if (!collection) {
return res.status(404).send('Collection not found')
}
// Expand collection to get library items
collection = collection.toJSONExpanded(this.db.libraryItems)
// Filter out library items not accessible to user
const libraryItems = collection.books.filter(item => req.user.checkCanAccessLibraryItem(item))
if (!libraryItems.length) {
return res.status(400).send('Collection has no books accessible to user')
}
const newPlaylist = new Playlist()
const newPlaylistData = {
userId: req.user.id,
libraryId: collection.libraryId,
name: collection.name,
description: collection.description || null,
items: libraryItems.map(li => ({ libraryItemId: li.id }))
}
newPlaylist.setData(newPlaylistData)
const jsonExpanded = newPlaylist.toJSONExpanded(this.db.libraryItems)
await this.db.insertEntity('playlist', newPlaylist)
SocketAuthority.clientEmitter(newPlaylist.userId, 'playlist_added', jsonExpanded)
res.json(jsonExpanded)
}
middleware(req, res, next) {
if (req.params.id) {
const playlist = this.db.playlists.find(p => p.id === req.params.id)
if (!playlist) {
return res.status(404).send('Playlist not found')
}
if (playlist.userId !== req.user.id) {
Logger.warn(`[PlaylistController] Playlist ${req.params.id} requested by user ${req.user.id} that is not the owner`)
return res.sendStatus(403)
}
req.playlist = playlist
}
next()
}
}
module.exports = new PlaylistController()