mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-05-12 06:21:30 +00:00
Merge 2b8f0082df into 47ea6b5092
This commit is contained in:
commit
f2145b6f12
2 changed files with 112 additions and 54 deletions
|
|
@ -3,6 +3,7 @@ const Logger = require('../Logger')
|
|||
const SocketAuthority = require('../SocketAuthority')
|
||||
const Database = require('../Database')
|
||||
const htmlSanitizer = require('../utils/htmlSanitizer')
|
||||
const { resolvePlaylistRequestItems } = require('../utils/playlistHelpers')
|
||||
|
||||
/**
|
||||
* @typedef RequestUserObject
|
||||
|
|
@ -287,19 +288,10 @@ class PlaylistController {
|
|||
return res.status(400).send('Request body has no libraryItemId')
|
||||
}
|
||||
|
||||
const libraryItem = await Database.libraryItemModel.getExpandedById(itemToAdd.libraryItemId)
|
||||
if (!libraryItem) {
|
||||
const [resolvedItem] = (await resolvePlaylistRequestItems([itemToAdd], req.playlist.libraryId)) || []
|
||||
if (!resolvedItem) {
|
||||
return res.status(400).send('Library item not found')
|
||||
}
|
||||
if (libraryItem.libraryId !== req.playlist.libraryId) {
|
||||
return res.status(400).send('Library item in different library')
|
||||
}
|
||||
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.podcastEpisodes.some((pe) => pe.id === itemToAdd.episodeId)) {
|
||||
return res.status(400).send('Episode not found in library item')
|
||||
}
|
||||
|
||||
req.playlist.playlistMediaItems = await req.playlist.getMediaItemsExpandedWithLibraryItem()
|
||||
|
||||
|
|
@ -311,27 +303,13 @@ class PlaylistController {
|
|||
|
||||
const playlistMediaItem = {
|
||||
playlistId: req.playlist.id,
|
||||
mediaItemId: itemToAdd.episodeId || libraryItem.media.id,
|
||||
mediaItemType: itemToAdd.episodeId ? 'podcastEpisode' : 'book',
|
||||
mediaItemId: resolvedItem.mediaItemId,
|
||||
mediaItemType: resolvedItem.mediaItemType,
|
||||
order: req.playlist.playlistMediaItems.length + 1
|
||||
}
|
||||
await Database.playlistMediaItemModel.create(playlistMediaItem)
|
||||
|
||||
// Add the new item to to the old json expanded to prevent having to fully reload the playlist media items
|
||||
if (itemToAdd.episodeId) {
|
||||
const episode = libraryItem.media.podcastEpisodes.find((ep) => ep.id === itemToAdd.episodeId)
|
||||
jsonExpanded.items.push({
|
||||
episodeId: itemToAdd.episodeId,
|
||||
episode: episode.toOldJSONExpanded(libraryItem.id),
|
||||
libraryItemId: libraryItem.id,
|
||||
libraryItem: libraryItem.toOldJSONMinified()
|
||||
})
|
||||
} else {
|
||||
jsonExpanded.items.push({
|
||||
libraryItemId: libraryItem.id,
|
||||
libraryItem: libraryItem.toOldJSONExpanded()
|
||||
})
|
||||
}
|
||||
jsonExpanded.items.push(resolvedItem.jsonItem)
|
||||
|
||||
SocketAuthority.clientEmitter(jsonExpanded.userId, 'playlist_updated', jsonExpanded)
|
||||
res.json(jsonExpanded)
|
||||
|
|
@ -396,11 +374,8 @@ class PlaylistController {
|
|||
return res.status(400).send('Invalid request body items')
|
||||
}
|
||||
|
||||
// Find all library items
|
||||
const libraryItemIds = new Set(req.body.items.map((i) => i.libraryItemId).filter((i) => i))
|
||||
|
||||
const libraryItems = await Database.libraryItemModel.findAllExpandedWhere({ id: Array.from(libraryItemIds) })
|
||||
if (libraryItems.length !== libraryItemIds.size) {
|
||||
const resolvedItems = await resolvePlaylistRequestItems(req.body.items, req.playlist.libraryId)
|
||||
if (!resolvedItems || resolvedItems.some((item) => !item)) {
|
||||
return res.status(400).send('Invalid request body items')
|
||||
}
|
||||
|
||||
|
|
@ -411,10 +386,8 @@ class PlaylistController {
|
|||
|
||||
// Setup array of playlistMediaItem records to add
|
||||
let order = req.playlist.playlistMediaItems.length + 1
|
||||
for (const item of req.body.items) {
|
||||
const libraryItem = libraryItems.find((li) => li.id === item.libraryItemId)
|
||||
|
||||
const mediaItemId = item.episodeId || libraryItem.media.id
|
||||
for (const resolvedItem of resolvedItems) {
|
||||
const { mediaItemId, mediaItemType, jsonItem } = resolvedItem
|
||||
if (req.playlist.playlistMediaItems.some((pmi) => pmi.mediaItemId === mediaItemId)) {
|
||||
// Already exists in playlist
|
||||
continue
|
||||
|
|
@ -422,25 +395,10 @@ class PlaylistController {
|
|||
mediaItemsToAdd.push({
|
||||
playlistId: req.playlist.id,
|
||||
mediaItemId,
|
||||
mediaItemType: item.episodeId ? 'podcastEpisode' : 'book',
|
||||
mediaItemType,
|
||||
order: order++
|
||||
})
|
||||
|
||||
// Add the new item to to the old json expanded to prevent having to fully reload the playlist media items
|
||||
if (item.episodeId) {
|
||||
const episode = libraryItem.media.podcastEpisodes.find((ep) => ep.id === item.episodeId)
|
||||
jsonExpanded.items.push({
|
||||
episodeId: item.episodeId,
|
||||
episode: episode.toOldJSONExpanded(libraryItem.id),
|
||||
libraryItemId: libraryItem.id,
|
||||
libraryItem: libraryItem.toOldJSONMinified()
|
||||
})
|
||||
} else {
|
||||
jsonExpanded.items.push({
|
||||
libraryItemId: libraryItem.id,
|
||||
libraryItem: libraryItem.toOldJSONExpanded()
|
||||
})
|
||||
}
|
||||
jsonExpanded.items.push(jsonItem)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
100
server/utils/playlistHelpers.js
Normal file
100
server/utils/playlistHelpers.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
const Database = require('../Database')
|
||||
|
||||
async function resolvePlaylistRequestItems(items, libraryId) {
|
||||
// Get lists of items, episodes, and books to simplify later operations
|
||||
const libraryItemIds = Array.from(new Set(items.map((i) => i.libraryItemId).filter((i) => i)))
|
||||
const episodeIds = Array.from(new Set(items.map((i) => i.episodeId).filter((i) => i)))
|
||||
const bookLibraryItemIds = Array.from(new Set(items.filter((i) => !i.episodeId).map((i) => i.libraryItemId)))
|
||||
|
||||
// Load library items for later mapping to episodes and books.
|
||||
const libraryItems = await Database.libraryItemModel.findAll({
|
||||
attributes: ['id', 'mediaId', 'mediaType', 'libraryId'],
|
||||
where: {
|
||||
id: libraryItemIds,
|
||||
libraryId
|
||||
}
|
||||
})
|
||||
if (libraryItems.length !== libraryItemIds.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const libraryItemsById = new Map(libraryItems.map((libraryItem) => [libraryItem.id, libraryItem]))
|
||||
|
||||
// Books still need their fully expanded library item because the playlist response embeds the whole book object.
|
||||
const bookLibraryItems = bookLibraryItemIds.length
|
||||
? await Database.libraryItemModel.findAllExpandedWhere({
|
||||
id: bookLibraryItemIds,
|
||||
libraryId,
|
||||
mediaType: 'book'
|
||||
})
|
||||
: []
|
||||
const bookLibraryItemsById = new Map(bookLibraryItems.map((libraryItem) => [libraryItem.id, libraryItem]))
|
||||
|
||||
// For podcast adds, load only the requested episodes plus their owning podcast/library item.
|
||||
const podcastEpisodes = episodeIds.length
|
||||
? await Database.podcastEpisodeModel.findAll({
|
||||
where: {
|
||||
id: episodeIds
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: Database.podcastModel,
|
||||
include: [
|
||||
{
|
||||
model: Database.libraryItemModel
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
: []
|
||||
const podcastEpisodesById = new Map(podcastEpisodes.map((episode) => [episode.id, episode]))
|
||||
|
||||
return items.map((item) => {
|
||||
const libraryItem = libraryItemsById.get(item.libraryItemId)
|
||||
if (!libraryItem) return null
|
||||
|
||||
// If this is an episode item, create the object with owning library item
|
||||
if (item.episodeId) {
|
||||
const episode = podcastEpisodesById.get(item.episodeId)
|
||||
if (libraryItem.mediaType !== 'podcast' || !episode?.podcast?.libraryItem || episode.podcast.libraryItem.id !== item.libraryItemId) {
|
||||
return null
|
||||
}
|
||||
|
||||
const episodeLibraryItem = episode.podcast.libraryItem
|
||||
episodeLibraryItem.media = episode.podcast
|
||||
|
||||
return {
|
||||
item,
|
||||
mediaItemId: item.episodeId,
|
||||
mediaItemType: 'podcastEpisode',
|
||||
jsonItem: {
|
||||
episodeId: item.episodeId,
|
||||
episode: episode.toOldJSONExpanded(episodeLibraryItem.id),
|
||||
libraryItemId: episodeLibraryItem.id,
|
||||
libraryItem: episodeLibraryItem.toOldJSONMinified()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If not a podcast, this is a book
|
||||
const expandedBookLibraryItem = bookLibraryItemsById.get(item.libraryItemId)
|
||||
if (libraryItem.mediaType !== 'book' || !expandedBookLibraryItem) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
item,
|
||||
mediaItemId: expandedBookLibraryItem.media.id,
|
||||
mediaItemType: 'book',
|
||||
jsonItem: {
|
||||
libraryItemId: expandedBookLibraryItem.id,
|
||||
libraryItem: expandedBookLibraryItem.toOldJSONExpanded()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
resolvePlaylistRequestItems
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue