mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Update controllers to use toOldJSON functions
This commit is contained in:
		
							parent
							
								
									7fae25a726
								
							
						
					
					
						commit
						6d52f88a96
					
				@ -665,7 +665,7 @@ class Database {
 | 
				
			|||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Clean invalid records in database
 | 
					   * Clean invalid records in database
 | 
				
			||||||
   * Series should have atleast one Book
 | 
					   * Series should have atleast one Book
 | 
				
			||||||
   * Book and Podcast must have an associated LibraryItem
 | 
					   * Book and Podcast must have an associated LibraryItem (and vice versa)
 | 
				
			||||||
   * Remove playback sessions that are 3 seconds or less
 | 
					   * Remove playback sessions that are 3 seconds or less
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async cleanDatabase() {
 | 
					  async cleanDatabase() {
 | 
				
			||||||
@ -695,6 +695,28 @@ class Database {
 | 
				
			|||||||
      await book.destroy()
 | 
					      await book.destroy()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Remove invalid LibraryItem records
 | 
				
			||||||
 | 
					    const libraryItemsWithNoMedia = await this.libraryItemModel.findAll({
 | 
				
			||||||
 | 
					      include: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          model: this.bookModel,
 | 
				
			||||||
 | 
					          attributes: ['id']
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          model: this.podcastModel,
 | 
				
			||||||
 | 
					          attributes: ['id']
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      where: {
 | 
				
			||||||
 | 
					        '$book.id$': null,
 | 
				
			||||||
 | 
					        '$podcast.id$': null
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    for (const libraryItem of libraryItemsWithNoMedia) {
 | 
				
			||||||
 | 
					      Logger.warn(`Found libraryItem "${libraryItem.id}" with no media - removing it`)
 | 
				
			||||||
 | 
					      await libraryItem.destroy()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const playlistMediaItemsWithNoMediaItem = await this.playlistMediaItemModel.findAll({
 | 
					    const playlistMediaItemsWithNoMediaItem = await this.playlistMediaItemModel.findAll({
 | 
				
			||||||
      include: [
 | 
					      include: [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
				
			|||||||
@ -125,7 +125,7 @@ class AuthorController {
 | 
				
			|||||||
      const bookAuthorsToCreate = []
 | 
					      const bookAuthorsToCreate = []
 | 
				
			||||||
      const allItemsWithAuthor = await Database.authorModel.getAllLibraryItemsForAuthor(req.author.id)
 | 
					      const allItemsWithAuthor = await Database.authorModel.getAllLibraryItemsForAuthor(req.author.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const oldLibraryItems = []
 | 
					      const libraryItems = []
 | 
				
			||||||
      allItemsWithAuthor.forEach((libraryItem) => {
 | 
					      allItemsWithAuthor.forEach((libraryItem) => {
 | 
				
			||||||
        // Replace old author with merging author for each book
 | 
					        // Replace old author with merging author for each book
 | 
				
			||||||
        libraryItem.media.authors = libraryItem.media.authors.filter((au) => au.id !== req.author.id)
 | 
					        libraryItem.media.authors = libraryItem.media.authors.filter((au) => au.id !== req.author.id)
 | 
				
			||||||
@ -134,23 +134,22 @@ class AuthorController {
 | 
				
			|||||||
          name: existingAuthor.name
 | 
					          name: existingAuthor.name
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
 | 
					        libraryItems.push(libraryItem)
 | 
				
			||||||
        oldLibraryItems.push(oldLibraryItem)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bookAuthorsToCreate.push({
 | 
					        bookAuthorsToCreate.push({
 | 
				
			||||||
          bookId: libraryItem.media.id,
 | 
					          bookId: libraryItem.media.id,
 | 
				
			||||||
          authorId: existingAuthor.id
 | 
					          authorId: existingAuthor.id
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      if (oldLibraryItems.length) {
 | 
					      if (libraryItems.length) {
 | 
				
			||||||
        await Database.removeBulkBookAuthors(req.author.id) // Remove all old BookAuthor
 | 
					        await Database.removeBulkBookAuthors(req.author.id) // Remove all old BookAuthor
 | 
				
			||||||
        await Database.createBulkBookAuthors(bookAuthorsToCreate) // Create all new BookAuthor
 | 
					        await Database.createBulkBookAuthors(bookAuthorsToCreate) // Create all new BookAuthor
 | 
				
			||||||
        for (const libraryItem of allItemsWithAuthor) {
 | 
					        for (const libraryItem of libraryItems) {
 | 
				
			||||||
          await libraryItem.saveMetadataFile()
 | 
					          await libraryItem.saveMetadataFile()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        SocketAuthority.emitter(
 | 
					        SocketAuthority.emitter(
 | 
				
			||||||
          'items_updated',
 | 
					          'items_updated',
 | 
				
			||||||
          oldLibraryItems.map((li) => li.toJSONExpanded())
 | 
					          libraryItems.map((li) => li.toOldJSONExpanded())
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -190,7 +189,7 @@ class AuthorController {
 | 
				
			|||||||
        const allItemsWithAuthor = await Database.authorModel.getAllLibraryItemsForAuthor(req.author.id)
 | 
					        const allItemsWithAuthor = await Database.authorModel.getAllLibraryItemsForAuthor(req.author.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        numBooksForAuthor = allItemsWithAuthor.length
 | 
					        numBooksForAuthor = allItemsWithAuthor.length
 | 
				
			||||||
        const oldLibraryItems = []
 | 
					        const libraryItems = []
 | 
				
			||||||
        // Update author name on all books
 | 
					        // Update author name on all books
 | 
				
			||||||
        for (const libraryItem of allItemsWithAuthor) {
 | 
					        for (const libraryItem of allItemsWithAuthor) {
 | 
				
			||||||
          libraryItem.media.authors = libraryItem.media.authors.map((au) => {
 | 
					          libraryItem.media.authors = libraryItem.media.authors.map((au) => {
 | 
				
			||||||
@ -199,16 +198,16 @@ class AuthorController {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            return au
 | 
					            return au
 | 
				
			||||||
          })
 | 
					          })
 | 
				
			||||||
          const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
 | 
					
 | 
				
			||||||
          oldLibraryItems.push(oldLibraryItem)
 | 
					          libraryItems.push(libraryItem)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          await libraryItem.saveMetadataFile()
 | 
					          await libraryItem.saveMetadataFile()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (oldLibraryItems.length) {
 | 
					        if (libraryItems.length) {
 | 
				
			||||||
          SocketAuthority.emitter(
 | 
					          SocketAuthority.emitter(
 | 
				
			||||||
            'items_updated',
 | 
					            'items_updated',
 | 
				
			||||||
            oldLibraryItems.map((li) => li.toJSONExpanded())
 | 
					            libraryItems.map((li) => li.toOldJSONExpanded())
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
 | 
				
			|||||||
@ -221,7 +221,9 @@ class CollectionController {
 | 
				
			|||||||
   * @param {Response} res
 | 
					   * @param {Response} res
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async addBook(req, res) {
 | 
					  async addBook(req, res) {
 | 
				
			||||||
    const libraryItem = await Database.libraryItemModel.getOldById(req.body.id)
 | 
					    const libraryItem = await Database.libraryItemModel.findByPk(req.body.id, {
 | 
				
			||||||
 | 
					      attributes: ['libraryId', 'mediaId']
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
    if (!libraryItem) {
 | 
					    if (!libraryItem) {
 | 
				
			||||||
      return res.status(404).send('Book not found')
 | 
					      return res.status(404).send('Book not found')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -231,14 +233,14 @@ class CollectionController {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Check if book is already in collection
 | 
					    // Check if book is already in collection
 | 
				
			||||||
    const collectionBooks = await req.collection.getCollectionBooks()
 | 
					    const collectionBooks = await req.collection.getCollectionBooks()
 | 
				
			||||||
    if (collectionBooks.some((cb) => cb.bookId === libraryItem.media.id)) {
 | 
					    if (collectionBooks.some((cb) => cb.bookId === libraryItem.mediaId)) {
 | 
				
			||||||
      return res.status(400).send('Book already in collection')
 | 
					      return res.status(400).send('Book already in collection')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Create collectionBook record
 | 
					    // Create collectionBook record
 | 
				
			||||||
    await Database.collectionBookModel.create({
 | 
					    await Database.collectionBookModel.create({
 | 
				
			||||||
      collectionId: req.collection.id,
 | 
					      collectionId: req.collection.id,
 | 
				
			||||||
      bookId: libraryItem.media.id,
 | 
					      bookId: libraryItem.mediaId,
 | 
				
			||||||
      order: collectionBooks.length + 1
 | 
					      order: collectionBooks.length + 1
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    const jsonExpanded = await req.collection.getOldJsonExpanded()
 | 
					    const jsonExpanded = await req.collection.getOldJsonExpanded()
 | 
				
			||||||
@ -255,7 +257,9 @@ class CollectionController {
 | 
				
			|||||||
   * @param {Response} res
 | 
					   * @param {Response} res
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async removeBook(req, res) {
 | 
					  async removeBook(req, res) {
 | 
				
			||||||
    const libraryItem = await Database.libraryItemModel.getOldById(req.params.bookId)
 | 
					    const libraryItem = await Database.libraryItemModel.findByPk(req.params.bookId, {
 | 
				
			||||||
 | 
					      attributes: ['mediaId']
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
    if (!libraryItem) {
 | 
					    if (!libraryItem) {
 | 
				
			||||||
      return res.sendStatus(404)
 | 
					      return res.sendStatus(404)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -266,7 +270,7 @@ class CollectionController {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let jsonExpanded = null
 | 
					    let jsonExpanded = null
 | 
				
			||||||
    const collectionBookToRemove = collectionBooks.find((cb) => cb.bookId === libraryItem.media.id)
 | 
					    const collectionBookToRemove = collectionBooks.find((cb) => cb.bookId === libraryItem.mediaId)
 | 
				
			||||||
    if (collectionBookToRemove) {
 | 
					    if (collectionBookToRemove) {
 | 
				
			||||||
      // Remove collection book record
 | 
					      // Remove collection book record
 | 
				
			||||||
      await collectionBookToRemove.destroy()
 | 
					      await collectionBookToRemove.destroy()
 | 
				
			||||||
@ -274,7 +278,7 @@ class CollectionController {
 | 
				
			|||||||
      // Update order on collection books
 | 
					      // Update order on collection books
 | 
				
			||||||
      let order = 1
 | 
					      let order = 1
 | 
				
			||||||
      for (const collectionBook of collectionBooks) {
 | 
					      for (const collectionBook of collectionBooks) {
 | 
				
			||||||
        if (collectionBook.bookId === libraryItem.media.id) continue
 | 
					        if (collectionBook.bookId === libraryItem.mediaId) continue
 | 
				
			||||||
        if (collectionBook.order !== order) {
 | 
					        if (collectionBook.order !== order) {
 | 
				
			||||||
          await collectionBook.update({
 | 
					          await collectionBook.update({
 | 
				
			||||||
            order
 | 
					            order
 | 
				
			||||||
 | 
				
			|||||||
@ -1145,14 +1145,14 @@ class LibraryController {
 | 
				
			|||||||
      await libraryItem.media.update({
 | 
					      await libraryItem.media.update({
 | 
				
			||||||
        narrators: libraryItem.media.narrators
 | 
					        narrators: libraryItem.media.narrators
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
 | 
					
 | 
				
			||||||
      itemsUpdated.push(oldLibraryItem)
 | 
					      itemsUpdated.push(libraryItem)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (itemsUpdated.length) {
 | 
					    if (itemsUpdated.length) {
 | 
				
			||||||
      SocketAuthority.emitter(
 | 
					      SocketAuthority.emitter(
 | 
				
			||||||
        'items_updated',
 | 
					        'items_updated',
 | 
				
			||||||
        itemsUpdated.map((li) => li.toJSONExpanded())
 | 
					        itemsUpdated.map((li) => li.toOldJSONExpanded())
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1189,14 +1189,14 @@ class LibraryController {
 | 
				
			|||||||
      await libraryItem.media.update({
 | 
					      await libraryItem.media.update({
 | 
				
			||||||
        narrators: libraryItem.media.narrators
 | 
					        narrators: libraryItem.media.narrators
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
 | 
					
 | 
				
			||||||
      itemsUpdated.push(oldLibraryItem)
 | 
					      itemsUpdated.push(libraryItem)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (itemsUpdated.length) {
 | 
					    if (itemsUpdated.length) {
 | 
				
			||||||
      SocketAuthority.emitter(
 | 
					      SocketAuthority.emitter(
 | 
				
			||||||
        'items_updated',
 | 
					        'items_updated',
 | 
				
			||||||
        itemsUpdated.map((li) => li.toJSONExpanded())
 | 
					        itemsUpdated.map((li) => li.toOldJSONExpanded())
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -551,11 +551,11 @@ class LibraryItemController {
 | 
				
			|||||||
    const hardDelete = req.query.hard == 1 // Delete files from filesystem
 | 
					    const hardDelete = req.query.hard == 1 // Delete files from filesystem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { libraryItemIds } = req.body
 | 
					    const { libraryItemIds } = req.body
 | 
				
			||||||
    if (!libraryItemIds?.length) {
 | 
					    if (!libraryItemIds?.length || !Array.isArray(libraryItemIds)) {
 | 
				
			||||||
      return res.status(400).send('Invalid request body')
 | 
					      return res.status(400).send('Invalid request body')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const itemsToDelete = await Database.libraryItemModel.getAllOldLibraryItems({
 | 
					    const itemsToDelete = await Database.libraryItemModel.findAllExpandedWhere({
 | 
				
			||||||
      id: libraryItemIds
 | 
					      id: libraryItemIds
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -566,19 +566,19 @@ class LibraryItemController {
 | 
				
			|||||||
    const libraryId = itemsToDelete[0].libraryId
 | 
					    const libraryId = itemsToDelete[0].libraryId
 | 
				
			||||||
    for (const libraryItem of itemsToDelete) {
 | 
					    for (const libraryItem of itemsToDelete) {
 | 
				
			||||||
      const libraryItemPath = libraryItem.path
 | 
					      const libraryItemPath = libraryItem.path
 | 
				
			||||||
      Logger.info(`[LibraryItemController] (${hardDelete ? 'Hard' : 'Soft'}) deleting Library Item "${libraryItem.media.metadata.title}" with id "${libraryItem.id}"`)
 | 
					      Logger.info(`[LibraryItemController] (${hardDelete ? 'Hard' : 'Soft'}) deleting Library Item "${libraryItem.media.title}" with id "${libraryItem.id}"`)
 | 
				
			||||||
      const mediaItemIds = []
 | 
					      const mediaItemIds = []
 | 
				
			||||||
      const seriesIds = []
 | 
					      const seriesIds = []
 | 
				
			||||||
      const authorIds = []
 | 
					      const authorIds = []
 | 
				
			||||||
      if (libraryItem.isPodcast) {
 | 
					      if (libraryItem.isPodcast) {
 | 
				
			||||||
        mediaItemIds.push(...libraryItem.media.episodes.map((ep) => ep.id))
 | 
					        mediaItemIds.push(...libraryItem.media.podcastEpisodes.map((ep) => ep.id))
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        mediaItemIds.push(libraryItem.media.id)
 | 
					        mediaItemIds.push(libraryItem.media.id)
 | 
				
			||||||
        if (libraryItem.media.metadata.series?.length) {
 | 
					        if (libraryItem.media.series?.length) {
 | 
				
			||||||
          seriesIds.push(...libraryItem.media.metadata.series.map((se) => se.id))
 | 
					          seriesIds.push(...libraryItem.media.series.map((se) => se.id))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (libraryItem.media.metadata.authors?.length) {
 | 
					        if (libraryItem.media.authors?.length) {
 | 
				
			||||||
          authorIds.push(...libraryItem.media.metadata.authors.map((au) => au.id))
 | 
					          authorIds.push(...libraryItem.media.authors.map((au) => au.id))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds)
 | 
					      await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds)
 | 
				
			||||||
@ -623,7 +623,7 @@ class LibraryItemController {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get all library items to update
 | 
					    // Get all library items to update
 | 
				
			||||||
    const libraryItems = await Database.libraryItemModel.getAllOldLibraryItems({
 | 
					    const libraryItems = await Database.libraryItemModel.findAllExpandedWhere({
 | 
				
			||||||
      id: libraryItemIds
 | 
					      id: libraryItemIds
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    if (updatePayloads.length !== libraryItems.length) {
 | 
					    if (updatePayloads.length !== libraryItems.length) {
 | 
				
			||||||
@ -645,21 +645,23 @@ class LibraryItemController {
 | 
				
			|||||||
      if (libraryItem.isBook) {
 | 
					      if (libraryItem.isBook) {
 | 
				
			||||||
        if (Array.isArray(mediaPayload.metadata?.series)) {
 | 
					        if (Array.isArray(mediaPayload.metadata?.series)) {
 | 
				
			||||||
          const seriesIdsInUpdate = mediaPayload.metadata.series.map((se) => se.id)
 | 
					          const seriesIdsInUpdate = mediaPayload.metadata.series.map((se) => se.id)
 | 
				
			||||||
          const seriesRemoved = libraryItem.media.metadata.series.filter((se) => !seriesIdsInUpdate.includes(se.id))
 | 
					          const seriesRemoved = libraryItem.media.series.filter((se) => !seriesIdsInUpdate.includes(se.id))
 | 
				
			||||||
          seriesIdsRemoved.push(...seriesRemoved.map((se) => se.id))
 | 
					          seriesIdsRemoved.push(...seriesRemoved.map((se) => se.id))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (Array.isArray(mediaPayload.metadata?.authors)) {
 | 
					        if (Array.isArray(mediaPayload.metadata?.authors)) {
 | 
				
			||||||
          const authorIdsInUpdate = mediaPayload.metadata.authors.map((au) => au.id)
 | 
					          const authorIdsInUpdate = mediaPayload.metadata.authors.map((au) => au.id)
 | 
				
			||||||
          const authorsRemoved = libraryItem.media.metadata.authors.filter((au) => !authorIdsInUpdate.includes(au.id))
 | 
					          const authorsRemoved = libraryItem.media.authors.filter((au) => !authorIdsInUpdate.includes(au.id))
 | 
				
			||||||
          authorIdsRemoved.push(...authorsRemoved.map((au) => au.id))
 | 
					          authorIdsRemoved.push(...authorsRemoved.map((au) => au.id))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (libraryItem.media.update(mediaPayload)) {
 | 
					      const hasUpdates = await libraryItem.media.updateFromRequest(mediaPayload)
 | 
				
			||||||
        Logger.debug(`[LibraryItemController] Updated library item media ${libraryItem.media.metadata.title}`)
 | 
					      if (hasUpdates) {
 | 
				
			||||||
 | 
					        libraryItem.changed('updatedAt', true)
 | 
				
			||||||
 | 
					        await libraryItem.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await Database.updateLibraryItem(libraryItem)
 | 
					        Logger.debug(`[LibraryItemController] Updated library item media "${libraryItem.media.title}"`)
 | 
				
			||||||
        SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
 | 
					        SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
 | 
				
			||||||
        itemsUpdated++
 | 
					        itemsUpdated++
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -688,11 +690,11 @@ class LibraryItemController {
 | 
				
			|||||||
    if (!libraryItemIds.length) {
 | 
					    if (!libraryItemIds.length) {
 | 
				
			||||||
      return res.status(403).send('Invalid payload')
 | 
					      return res.status(403).send('Invalid payload')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const libraryItems = await Database.libraryItemModel.getAllOldLibraryItems({
 | 
					    const libraryItems = await Database.libraryItemModel.findAllExpandedWhere({
 | 
				
			||||||
      id: libraryItemIds
 | 
					      id: libraryItemIds
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    res.json({
 | 
					    res.json({
 | 
				
			||||||
      libraryItems: libraryItems.map((li) => li.toJSONExpanded())
 | 
					      libraryItems: libraryItems.map((li) => li.toOldJSONExpanded())
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -715,7 +717,7 @@ class LibraryItemController {
 | 
				
			|||||||
      return res.sendStatus(400)
 | 
					      return res.sendStatus(400)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const libraryItems = await Database.libraryItemModel.getAllOldLibraryItems({
 | 
					    const libraryItems = await Database.libraryItemModel.findAllExpandedWhere({
 | 
				
			||||||
      id: req.body.libraryItemIds
 | 
					      id: req.body.libraryItemIds
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    if (!libraryItems?.length) {
 | 
					    if (!libraryItems?.length) {
 | 
				
			||||||
@ -737,7 +739,8 @@ class LibraryItemController {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (const libraryItem of libraryItems) {
 | 
					    for (const libraryItem of libraryItems) {
 | 
				
			||||||
      const matchResult = await Scanner.quickMatchLibraryItem(this, libraryItem, options)
 | 
					      const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
 | 
				
			||||||
 | 
					      const matchResult = await Scanner.quickMatchLibraryItem(this, oldLibraryItem, options)
 | 
				
			||||||
      if (matchResult.updated) {
 | 
					      if (matchResult.updated) {
 | 
				
			||||||
        itemsUpdated++
 | 
					        itemsUpdated++
 | 
				
			||||||
      } else if (matchResult.warning) {
 | 
					      } else if (matchResult.warning) {
 | 
				
			||||||
 | 
				
			|||||||
@ -66,7 +66,7 @@ class MeController {
 | 
				
			|||||||
    const libraryItem = await Database.libraryItemModel.findByPk(req.params.libraryItemId)
 | 
					    const libraryItem = await Database.libraryItemModel.findByPk(req.params.libraryItemId)
 | 
				
			||||||
    const episode = await Database.podcastEpisodeModel.findByPk(req.params.episodeId)
 | 
					    const episode = await Database.podcastEpisodeModel.findByPk(req.params.episodeId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!libraryItem || (libraryItem.mediaType === 'podcast' && !episode)) {
 | 
					    if (!libraryItem || (libraryItem.isPodcast && !episode)) {
 | 
				
			||||||
      Logger.error(`[MeController] Media item not found for library item id "${req.params.libraryItemId}"`)
 | 
					      Logger.error(`[MeController] Media item not found for library item id "${req.params.libraryItemId}"`)
 | 
				
			||||||
      return res.sendStatus(404)
 | 
					      return res.sendStatus(404)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -296,7 +296,7 @@ class MeController {
 | 
				
			|||||||
    const mediaProgressesInProgress = req.user.mediaProgresses.filter((mp) => !mp.isFinished && (mp.currentTime > 0 || mp.ebookProgress > 0))
 | 
					    const mediaProgressesInProgress = req.user.mediaProgresses.filter((mp) => !mp.isFinished && (mp.currentTime > 0 || mp.ebookProgress > 0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const libraryItemsIds = [...new Set(mediaProgressesInProgress.map((mp) => mp.extraData?.libraryItemId).filter((id) => id))]
 | 
					    const libraryItemsIds = [...new Set(mediaProgressesInProgress.map((mp) => mp.extraData?.libraryItemId).filter((id) => id))]
 | 
				
			||||||
    const libraryItems = await Database.libraryItemModel.getAllOldLibraryItems({ id: libraryItemsIds })
 | 
					    const libraryItems = await Database.libraryItemModel.findAllExpandedWhere({ id: libraryItemsIds })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let itemsInProgress = []
 | 
					    let itemsInProgress = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -304,19 +304,19 @@ class MeController {
 | 
				
			|||||||
      const oldMediaProgress = mediaProgress.getOldMediaProgress()
 | 
					      const oldMediaProgress = mediaProgress.getOldMediaProgress()
 | 
				
			||||||
      const libraryItem = libraryItems.find((li) => li.id === oldMediaProgress.libraryItemId)
 | 
					      const libraryItem = libraryItems.find((li) => li.id === oldMediaProgress.libraryItemId)
 | 
				
			||||||
      if (libraryItem) {
 | 
					      if (libraryItem) {
 | 
				
			||||||
        if (oldMediaProgress.episodeId && libraryItem.mediaType === 'podcast') {
 | 
					        if (oldMediaProgress.episodeId && libraryItem.isPodcast) {
 | 
				
			||||||
          const episode = libraryItem.media.episodes.find((ep) => ep.id === oldMediaProgress.episodeId)
 | 
					          const episode = libraryItem.media.podcastEpisodes.find((ep) => ep.id === oldMediaProgress.episodeId)
 | 
				
			||||||
          if (episode) {
 | 
					          if (episode) {
 | 
				
			||||||
            const libraryItemWithEpisode = {
 | 
					            const libraryItemWithEpisode = {
 | 
				
			||||||
              ...libraryItem.toJSONMinified(),
 | 
					              ...libraryItem.toOldJSONMinified(),
 | 
				
			||||||
              recentEpisode: episode.toJSON(),
 | 
					              recentEpisode: episode.toOldJSON(libraryItem.id),
 | 
				
			||||||
              progressLastUpdate: oldMediaProgress.lastUpdate
 | 
					              progressLastUpdate: oldMediaProgress.lastUpdate
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            itemsInProgress.push(libraryItemWithEpisode)
 | 
					            itemsInProgress.push(libraryItemWithEpisode)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        } else if (!oldMediaProgress.episodeId) {
 | 
					        } else if (!oldMediaProgress.episodeId) {
 | 
				
			||||||
          itemsInProgress.push({
 | 
					          itemsInProgress.push({
 | 
				
			||||||
            ...libraryItem.toJSONMinified(),
 | 
					            ...libraryItem.toOldJSONMinified(),
 | 
				
			||||||
            progressLastUpdate: oldMediaProgress.lastUpdate
 | 
					            progressLastUpdate: oldMediaProgress.lastUpdate
 | 
				
			||||||
          })
 | 
					          })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -342,8 +342,8 @@ class MiscController {
 | 
				
			|||||||
          tags: libraryItem.media.tags
 | 
					          tags: libraryItem.media.tags
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        await libraryItem.saveMetadataFile()
 | 
					        await libraryItem.saveMetadataFile()
 | 
				
			||||||
        const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
 | 
					
 | 
				
			||||||
        SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
 | 
					        SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
 | 
				
			||||||
        numItemsUpdated++
 | 
					        numItemsUpdated++
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -385,8 +385,8 @@ class MiscController {
 | 
				
			|||||||
        tags: libraryItem.media.tags
 | 
					        tags: libraryItem.media.tags
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      await libraryItem.saveMetadataFile()
 | 
					      await libraryItem.saveMetadataFile()
 | 
				
			||||||
      const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
 | 
					
 | 
				
			||||||
      SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
 | 
					      SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
 | 
				
			||||||
      numItemsUpdated++
 | 
					      numItemsUpdated++
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -480,8 +480,8 @@ class MiscController {
 | 
				
			|||||||
          genres: libraryItem.media.genres
 | 
					          genres: libraryItem.media.genres
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        await libraryItem.saveMetadataFile()
 | 
					        await libraryItem.saveMetadataFile()
 | 
				
			||||||
        const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
 | 
					
 | 
				
			||||||
        SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
 | 
					        SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
 | 
				
			||||||
        numItemsUpdated++
 | 
					        numItemsUpdated++
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -523,8 +523,8 @@ class MiscController {
 | 
				
			|||||||
        genres: libraryItem.media.genres
 | 
					        genres: libraryItem.media.genres
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      await libraryItem.saveMetadataFile()
 | 
					      await libraryItem.saveMetadataFile()
 | 
				
			||||||
      const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
 | 
					
 | 
				
			||||||
      SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
 | 
					      SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
 | 
				
			||||||
      numItemsUpdated++
 | 
					      numItemsUpdated++
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -276,7 +276,7 @@ class PlaylistController {
 | 
				
			|||||||
      return res.status(400).send('Request body has no libraryItemId')
 | 
					      return res.status(400).send('Request body has no libraryItemId')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const libraryItem = await Database.libraryItemModel.getOldById(itemToAdd.libraryItemId)
 | 
					    const libraryItem = await Database.libraryItemModel.getExpandedById(itemToAdd.libraryItemId)
 | 
				
			||||||
    if (!libraryItem) {
 | 
					    if (!libraryItem) {
 | 
				
			||||||
      return res.status(400).send('Library item not found')
 | 
					      return res.status(400).send('Library item not found')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -286,7 +286,7 @@ class PlaylistController {
 | 
				
			|||||||
    if ((itemToAdd.episodeId && !libraryItem.isPodcast) || (libraryItem.isPodcast && !itemToAdd.episodeId)) {
 | 
					    if ((itemToAdd.episodeId && !libraryItem.isPodcast) || (libraryItem.isPodcast && !itemToAdd.episodeId)) {
 | 
				
			||||||
      return res.status(400).send('Invalid item to add for this library type')
 | 
					      return res.status(400).send('Invalid item to add for this library type')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (itemToAdd.episodeId && !libraryItem.media.checkHasEpisode(itemToAdd.episodeId)) {
 | 
					    if (itemToAdd.episodeId && !libraryItem.media.podcastEpisodes.some((pe) => pe.id === itemToAdd.episodeId)) {
 | 
				
			||||||
      return res.status(400).send('Episode not found in library item')
 | 
					      return res.status(400).send('Episode not found in library item')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -308,17 +308,17 @@ class PlaylistController {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Add the new item to to the old json expanded to prevent having to fully reload the playlist media items
 | 
					    // Add the new item to to the old json expanded to prevent having to fully reload the playlist media items
 | 
				
			||||||
    if (itemToAdd.episodeId) {
 | 
					    if (itemToAdd.episodeId) {
 | 
				
			||||||
      const episode = libraryItem.media.episodes.find((ep) => ep.id === itemToAdd.episodeId)
 | 
					      const episode = libraryItem.media.podcastEpisodes.find((ep) => ep.id === itemToAdd.episodeId)
 | 
				
			||||||
      jsonExpanded.items.push({
 | 
					      jsonExpanded.items.push({
 | 
				
			||||||
        episodeId: itemToAdd.episodeId,
 | 
					        episodeId: itemToAdd.episodeId,
 | 
				
			||||||
        episode: episode.toJSONExpanded(),
 | 
					        episode: episode.toOldJSONExpanded(libraryItem.id),
 | 
				
			||||||
        libraryItemId: libraryItem.id,
 | 
					        libraryItemId: libraryItem.id,
 | 
				
			||||||
        libraryItem: libraryItem.toJSONMinified()
 | 
					        libraryItem: libraryItem.toOldJSONMinified()
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      jsonExpanded.items.push({
 | 
					      jsonExpanded.items.push({
 | 
				
			||||||
        libraryItemId: libraryItem.id,
 | 
					        libraryItemId: libraryItem.id,
 | 
				
			||||||
        libraryItem: libraryItem.toJSONExpanded()
 | 
					        libraryItem: libraryItem.toOldJSONExpanded()
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -388,8 +388,8 @@ class PlaylistController {
 | 
				
			|||||||
    // Find all library items
 | 
					    // Find all library items
 | 
				
			||||||
    const libraryItemIds = new Set(req.body.items.map((i) => i.libraryItemId).filter((i) => i))
 | 
					    const libraryItemIds = new Set(req.body.items.map((i) => i.libraryItemId).filter((i) => i))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const oldLibraryItems = await Database.libraryItemModel.getAllOldLibraryItems({ id: Array.from(libraryItemIds) })
 | 
					    const libraryItems = await Database.libraryItemModel.findAllExpandedWhere({ id: Array.from(libraryItemIds) })
 | 
				
			||||||
    if (oldLibraryItems.length !== libraryItemIds.size) {
 | 
					    if (libraryItems.length !== libraryItemIds.size) {
 | 
				
			||||||
      return res.status(400).send('Invalid request body items')
 | 
					      return res.status(400).send('Invalid request body items')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -401,7 +401,7 @@ class PlaylistController {
 | 
				
			|||||||
    // Setup array of playlistMediaItem records to add
 | 
					    // Setup array of playlistMediaItem records to add
 | 
				
			||||||
    let order = req.playlist.playlistMediaItems.length + 1
 | 
					    let order = req.playlist.playlistMediaItems.length + 1
 | 
				
			||||||
    for (const item of req.body.items) {
 | 
					    for (const item of req.body.items) {
 | 
				
			||||||
      const libraryItem = oldLibraryItems.find((li) => li.id === item.libraryItemId)
 | 
					      const libraryItem = libraryItems.find((li) => li.id === item.libraryItemId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const mediaItemId = item.episodeId || libraryItem.media.id
 | 
					      const mediaItemId = item.episodeId || libraryItem.media.id
 | 
				
			||||||
      if (req.playlist.playlistMediaItems.some((pmi) => pmi.mediaItemId === mediaItemId)) {
 | 
					      if (req.playlist.playlistMediaItems.some((pmi) => pmi.mediaItemId === mediaItemId)) {
 | 
				
			||||||
@ -417,17 +417,17 @@ class PlaylistController {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Add the new item to to the old json expanded to prevent having to fully reload the playlist media items
 | 
					        // Add the new item to to the old json expanded to prevent having to fully reload the playlist media items
 | 
				
			||||||
        if (item.episodeId) {
 | 
					        if (item.episodeId) {
 | 
				
			||||||
          const episode = libraryItem.media.episodes.find((ep) => ep.id === item.episodeId)
 | 
					          const episode = libraryItem.media.podcastEpisodes.find((ep) => ep.id === item.episodeId)
 | 
				
			||||||
          jsonExpanded.items.push({
 | 
					          jsonExpanded.items.push({
 | 
				
			||||||
            episodeId: item.episodeId,
 | 
					            episodeId: item.episodeId,
 | 
				
			||||||
            episode: episode.toJSONExpanded(),
 | 
					            episode: episode.toOldJSONExpanded(libraryItem.id),
 | 
				
			||||||
            libraryItemId: libraryItem.id,
 | 
					            libraryItemId: libraryItem.id,
 | 
				
			||||||
            libraryItem: libraryItem.toJSONMinified()
 | 
					            libraryItem: libraryItem.toOldJSONMinified()
 | 
				
			||||||
          })
 | 
					          })
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          jsonExpanded.items.push({
 | 
					          jsonExpanded.items.push({
 | 
				
			||||||
            libraryItemId: libraryItem.id,
 | 
					            libraryItemId: libraryItem.id,
 | 
				
			||||||
            libraryItem: libraryItem.toJSONExpanded()
 | 
					            libraryItem: libraryItem.toOldJSONExpanded()
 | 
				
			||||||
          })
 | 
					          })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -296,9 +296,9 @@ class PodcastManager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    Logger.info(`[PodcastManager] runEpisodeCheck: "${libraryItem.media.title}" | Last check: ${new Date(lastEpisodeCheck)} | ${latestEpisodePublishedAt ? `Latest episode pubDate: ${new Date(latestEpisodePublishedAt)}` : 'No latest episode'}`)
 | 
					    Logger.info(`[PodcastManager] runEpisodeCheck: "${libraryItem.media.title}" | Last check: ${new Date(lastEpisodeCheck)} | ${latestEpisodePublishedAt ? `Latest episode pubDate: ${new Date(latestEpisodePublishedAt)}` : 'No latest episode'}`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Use latest episode pubDate if exists OR fallback to using lastEpisodeCheckDate
 | 
					    // Use latest episode pubDate if exists OR fallback to using lastEpisodeCheck
 | 
				
			||||||
    //    lastEpisodeCheckDate will be the current time when adding a new podcast
 | 
					    //    lastEpisodeCheck will be the current time when adding a new podcast
 | 
				
			||||||
    const dateToCheckForEpisodesAfter = latestEpisodePublishedAt || lastEpisodeCheckDate
 | 
					    const dateToCheckForEpisodesAfter = latestEpisodePublishedAt || lastEpisodeCheck
 | 
				
			||||||
    Logger.debug(`[PodcastManager] runEpisodeCheck: "${libraryItem.media.title}" checking for episodes after ${new Date(dateToCheckForEpisodesAfter)}`)
 | 
					    Logger.debug(`[PodcastManager] runEpisodeCheck: "${libraryItem.media.title}" checking for episodes after ${new Date(dateToCheckForEpisodesAfter)}`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const newEpisodes = await this.checkPodcastForNewEpisodes(libraryItem, dateToCheckForEpisodesAfter, libraryItem.media.maxNewEpisodesToDownload)
 | 
					    const newEpisodes = await this.checkPodcastForNewEpisodes(libraryItem, dateToCheckForEpisodesAfter, libraryItem.media.maxNewEpisodesToDownload)
 | 
				
			||||||
 | 
				
			|||||||
@ -282,7 +282,7 @@ class Collection extends Model {
 | 
				
			|||||||
      const libraryItem = book.libraryItem
 | 
					      const libraryItem = book.libraryItem
 | 
				
			||||||
      delete book.libraryItem
 | 
					      delete book.libraryItem
 | 
				
			||||||
      libraryItem.media = book
 | 
					      libraryItem.media = book
 | 
				
			||||||
      return this.sequelize.models.libraryItem.getOldLibraryItem(libraryItem).toJSONExpanded()
 | 
					      return libraryItem.toOldJSONExpanded()
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return json
 | 
					    return json
 | 
				
			||||||
 | 
				
			|||||||
@ -122,45 +122,6 @@ class LibraryItem extends Model {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   *
 | 
					 | 
				
			||||||
   * @param {import('sequelize').WhereOptions} [where]
 | 
					 | 
				
			||||||
   * @returns {Array<objects.LibraryItem>} old library items
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  static async getAllOldLibraryItems(where = null) {
 | 
					 | 
				
			||||||
    let libraryItems = await this.findAll({
 | 
					 | 
				
			||||||
      where,
 | 
					 | 
				
			||||||
      include: [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          model: this.sequelize.models.book,
 | 
					 | 
				
			||||||
          include: [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              model: this.sequelize.models.author,
 | 
					 | 
				
			||||||
              through: {
 | 
					 | 
				
			||||||
                attributes: []
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              model: this.sequelize.models.series,
 | 
					 | 
				
			||||||
              through: {
 | 
					 | 
				
			||||||
                attributes: ['sequence']
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          model: this.sequelize.models.podcast,
 | 
					 | 
				
			||||||
          include: [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              model: this.sequelize.models.podcastEpisode
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      ]
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    return libraryItems.map((ti) => this.getOldLibraryItem(ti))
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Convert an expanded LibraryItem into an old library item
 | 
					   * Convert an expanded LibraryItem into an old library item
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
@ -448,6 +409,47 @@ class LibraryItem extends Model {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param {import('sequelize').WhereOptions} where
 | 
				
			||||||
 | 
					   * @returns {Promise<LibraryItemExpanded[]>}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static async findAllExpandedWhere(where = null) {
 | 
				
			||||||
 | 
					    return this.findAll({
 | 
				
			||||||
 | 
					      where,
 | 
				
			||||||
 | 
					      include: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          model: this.sequelize.models.book,
 | 
				
			||||||
 | 
					          include: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              model: this.sequelize.models.author,
 | 
				
			||||||
 | 
					              through: {
 | 
				
			||||||
 | 
					                attributes: []
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              model: this.sequelize.models.series,
 | 
				
			||||||
 | 
					              through: {
 | 
				
			||||||
 | 
					                attributes: ['sequence']
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          model: this.sequelize.models.podcast,
 | 
				
			||||||
 | 
					          include: {
 | 
				
			||||||
 | 
					            model: this.sequelize.models.podcastEpisode
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      order: [
 | 
				
			||||||
 | 
					        // Ensure author & series stay in the same order
 | 
				
			||||||
 | 
					        [this.sequelize.models.book, this.sequelize.models.author, this.sequelize.models.bookAuthor, 'createdAt', 'ASC'],
 | 
				
			||||||
 | 
					        [this.sequelize.models.book, this.sequelize.models.series, 'bookSeries', 'createdAt', 'ASC']
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * @param {string} libraryItemId
 | 
					   * @param {string} libraryItemId
 | 
				
			||||||
@ -611,7 +613,7 @@ class LibraryItem extends Model {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      libraryItems: libraryItems.map((li) => {
 | 
					      libraryItems: libraryItems.map((li) => {
 | 
				
			||||||
        const oldLibraryItem = this.getOldLibraryItem(li).toJSONMinified()
 | 
					        const oldLibraryItem = li.toOldJSONMinified()
 | 
				
			||||||
        if (li.collapsedSeries) {
 | 
					        if (li.collapsedSeries) {
 | 
				
			||||||
          oldLibraryItem.collapsedSeries = li.collapsedSeries
 | 
					          oldLibraryItem.collapsedSeries = li.collapsedSeries
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -357,7 +357,7 @@ class Playlist extends Model {
 | 
				
			|||||||
        libraryItem.media = pmi.mediaItem
 | 
					        libraryItem.media = pmi.mediaItem
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
          libraryItemId: libraryItem.id,
 | 
					          libraryItemId: libraryItem.id,
 | 
				
			||||||
          libraryItem: this.sequelize.models.libraryItem.getOldLibraryItem(libraryItem).toJSONExpanded()
 | 
					          libraryItem: libraryItem.toOldJSONExpanded()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -368,7 +368,7 @@ class Playlist extends Model {
 | 
				
			|||||||
        episodeId: pmi.mediaItemId,
 | 
					        episodeId: pmi.mediaItemId,
 | 
				
			||||||
        episode: pmi.mediaItem.toOldJSONExpanded(libraryItem.id),
 | 
					        episode: pmi.mediaItem.toOldJSONExpanded(libraryItem.id),
 | 
				
			||||||
        libraryItemId: libraryItem.id,
 | 
					        libraryItemId: libraryItem.id,
 | 
				
			||||||
        libraryItem: this.sequelize.models.libraryItem.getOldLibraryItem(libraryItem).toJSONMinified()
 | 
					        libraryItem: libraryItem.toOldJSONMinified()
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -166,10 +166,6 @@ class Podcast {
 | 
				
			|||||||
    return true
 | 
					    return true
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  checkHasEpisode(episodeId) {
 | 
					 | 
				
			||||||
    return this.episodes.some((ep) => ep.id === episodeId)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  getEpisode(episodeId) {
 | 
					  getEpisode(episodeId) {
 | 
				
			||||||
    if (!episodeId) return null
 | 
					    if (!episodeId) return null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -64,8 +64,7 @@ class LibraryItemScanner {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const { libraryItem: expandedLibraryItem, wasUpdated } = await this.rescanLibraryItemMedia(libraryItem, libraryItemScanData, library.settings, scanLogger)
 | 
					    const { libraryItem: expandedLibraryItem, wasUpdated } = await this.rescanLibraryItemMedia(libraryItem, libraryItemScanData, library.settings, scanLogger)
 | 
				
			||||||
    if (libraryItemDataUpdated || wasUpdated) {
 | 
					    if (libraryItemDataUpdated || wasUpdated) {
 | 
				
			||||||
      const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(expandedLibraryItem)
 | 
					      SocketAuthority.emitter('item_updated', expandedLibraryItem.toOldJSONExpanded())
 | 
				
			||||||
      SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      await this.checkAuthorsAndSeriesRemovedFromBooks(library.id, scanLogger)
 | 
					      await this.checkAuthorsAndSeriesRemovedFromBooks(library.id, scanLogger)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -167,7 +167,7 @@ class LibraryScanner {
 | 
				
			|||||||
    if (this.shouldCancelScan(libraryScan)) return true
 | 
					    if (this.shouldCancelScan(libraryScan)) return true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const libraryItemIdsMissing = []
 | 
					    const libraryItemIdsMissing = []
 | 
				
			||||||
    let oldLibraryItemsUpdated = []
 | 
					    let libraryItemsUpdated = []
 | 
				
			||||||
    for (const existingLibraryItem of existingLibraryItems) {
 | 
					    for (const existingLibraryItem of existingLibraryItems) {
 | 
				
			||||||
      // First try to find matching library item with exact file path
 | 
					      // First try to find matching library item with exact file path
 | 
				
			||||||
      let libraryItemData = libraryItemDataFound.find((lid) => lid.path === existingLibraryItem.path)
 | 
					      let libraryItemData = libraryItemDataFound.find((lid) => lid.path === existingLibraryItem.path)
 | 
				
			||||||
@ -190,11 +190,11 @@ class LibraryScanner {
 | 
				
			|||||||
            libraryItemIdsMissing.push(existingLibraryItem.id)
 | 
					            libraryItemIdsMissing.push(existingLibraryItem.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // TODO: Temporary while using old model to socket emit
 | 
					            // TODO: Temporary while using old model to socket emit
 | 
				
			||||||
            const oldLibraryItem = await Database.libraryItemModel.getOldById(existingLibraryItem.id)
 | 
					            const libraryItem = await Database.libraryItemModel.getExpandedById(existingLibraryItem.id)
 | 
				
			||||||
            if (oldLibraryItem) {
 | 
					            if (libraryItem) {
 | 
				
			||||||
              oldLibraryItem.isMissing = true
 | 
					              libraryItem.isMissing = true
 | 
				
			||||||
              oldLibraryItem.updatedAt = Date.now()
 | 
					              await libraryItem.save()
 | 
				
			||||||
              oldLibraryItemsUpdated.push(oldLibraryItem)
 | 
					              libraryItemsUpdated.push(libraryItem)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -206,16 +206,15 @@ class LibraryScanner {
 | 
				
			|||||||
            const { libraryItem, wasUpdated } = await LibraryItemScanner.rescanLibraryItemMedia(existingLibraryItem, libraryItemData, libraryScan.library.settings, libraryScan)
 | 
					            const { libraryItem, wasUpdated } = await LibraryItemScanner.rescanLibraryItemMedia(existingLibraryItem, libraryItemData, libraryScan.library.settings, libraryScan)
 | 
				
			||||||
            if (!forceRescan || wasUpdated) {
 | 
					            if (!forceRescan || wasUpdated) {
 | 
				
			||||||
              libraryScan.resultsUpdated++
 | 
					              libraryScan.resultsUpdated++
 | 
				
			||||||
              const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem)
 | 
					              libraryItemsUpdated.push(libraryItem)
 | 
				
			||||||
              oldLibraryItemsUpdated.push(oldLibraryItem)
 | 
					 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              libraryScan.addLog(LogLevel.DEBUG, `Library item "${existingLibraryItem.relPath}" is up-to-date`)
 | 
					              libraryScan.addLog(LogLevel.DEBUG, `Library item "${existingLibraryItem.relPath}" is up-to-date`)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            libraryScan.resultsUpdated++
 | 
					            libraryScan.resultsUpdated++
 | 
				
			||||||
            // TODO: Temporary while using old model to socket emit
 | 
					            // TODO: Temporary while using old model to socket emit
 | 
				
			||||||
            const oldLibraryItem = await Database.libraryItemModel.getOldById(existingLibraryItem.id)
 | 
					            const libraryItem = await Database.libraryItemModel.getExpandedById(existingLibraryItem.id)
 | 
				
			||||||
            oldLibraryItemsUpdated.push(oldLibraryItem)
 | 
					            libraryItemsUpdated.push(libraryItem)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          libraryScan.addLog(LogLevel.DEBUG, `Library item "${existingLibraryItem.relPath}" is up-to-date`)
 | 
					          libraryScan.addLog(LogLevel.DEBUG, `Library item "${existingLibraryItem.relPath}" is up-to-date`)
 | 
				
			||||||
@ -223,23 +222,23 @@ class LibraryScanner {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Emit item updates in chunks of 10 to client
 | 
					      // Emit item updates in chunks of 10 to client
 | 
				
			||||||
      if (oldLibraryItemsUpdated.length === 10) {
 | 
					      if (libraryItemsUpdated.length === 10) {
 | 
				
			||||||
        // TODO: Should only emit to clients where library item is accessible
 | 
					        // TODO: Should only emit to clients where library item is accessible
 | 
				
			||||||
        SocketAuthority.emitter(
 | 
					        SocketAuthority.emitter(
 | 
				
			||||||
          'items_updated',
 | 
					          'items_updated',
 | 
				
			||||||
          oldLibraryItemsUpdated.map((li) => li.toJSONExpanded())
 | 
					          libraryItemsUpdated.map((li) => li.toOldJSONExpanded())
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        oldLibraryItemsUpdated = []
 | 
					        libraryItemsUpdated = []
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (this.shouldCancelScan(libraryScan)) return true
 | 
					      if (this.shouldCancelScan(libraryScan)) return true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // Emit item updates to client
 | 
					    // Emit item updates to client
 | 
				
			||||||
    if (oldLibraryItemsUpdated.length) {
 | 
					    if (libraryItemsUpdated.length) {
 | 
				
			||||||
      // TODO: Should only emit to clients where library item is accessible
 | 
					      // TODO: Should only emit to clients where library item is accessible
 | 
				
			||||||
      SocketAuthority.emitter(
 | 
					      SocketAuthority.emitter(
 | 
				
			||||||
        'items_updated',
 | 
					        'items_updated',
 | 
				
			||||||
        oldLibraryItemsUpdated.map((li) => li.toJSONExpanded())
 | 
					        libraryItemsUpdated.map((li) => li.toOldJSONExpanded())
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -267,34 +266,33 @@ class LibraryScanner {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Add new library items
 | 
					    // Add new library items
 | 
				
			||||||
    if (libraryItemDataFound.length) {
 | 
					    if (libraryItemDataFound.length) {
 | 
				
			||||||
      let newOldLibraryItems = []
 | 
					      let newLibraryItems = []
 | 
				
			||||||
      for (const libraryItemData of libraryItemDataFound) {
 | 
					      for (const libraryItemData of libraryItemDataFound) {
 | 
				
			||||||
        const newLibraryItem = await LibraryItemScanner.scanNewLibraryItem(libraryItemData, libraryScan.library.settings, libraryScan)
 | 
					        const newLibraryItem = await LibraryItemScanner.scanNewLibraryItem(libraryItemData, libraryScan.library.settings, libraryScan)
 | 
				
			||||||
        if (newLibraryItem) {
 | 
					        if (newLibraryItem) {
 | 
				
			||||||
          const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(newLibraryItem)
 | 
					          newLibraryItems.push(newLibraryItem)
 | 
				
			||||||
          newOldLibraryItems.push(oldLibraryItem)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          libraryScan.resultsAdded++
 | 
					          libraryScan.resultsAdded++
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Emit new items in chunks of 10 to client
 | 
					        // Emit new items in chunks of 10 to client
 | 
				
			||||||
        if (newOldLibraryItems.length === 10) {
 | 
					        if (newLibraryItems.length === 10) {
 | 
				
			||||||
          // TODO: Should only emit to clients where library item is accessible
 | 
					          // TODO: Should only emit to clients where library item is accessible
 | 
				
			||||||
          SocketAuthority.emitter(
 | 
					          SocketAuthority.emitter(
 | 
				
			||||||
            'items_added',
 | 
					            'items_added',
 | 
				
			||||||
            newOldLibraryItems.map((li) => li.toJSONExpanded())
 | 
					            newLibraryItems.map((li) => li.toOldJSONExpanded())
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
          newOldLibraryItems = []
 | 
					          newLibraryItems = []
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.shouldCancelScan(libraryScan)) return true
 | 
					        if (this.shouldCancelScan(libraryScan)) return true
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      // Emit new items to client
 | 
					      // Emit new items to client
 | 
				
			||||||
      if (newOldLibraryItems.length) {
 | 
					      if (newLibraryItems.length) {
 | 
				
			||||||
        // TODO: Should only emit to clients where library item is accessible
 | 
					        // TODO: Should only emit to clients where library item is accessible
 | 
				
			||||||
        SocketAuthority.emitter(
 | 
					        SocketAuthority.emitter(
 | 
				
			||||||
          'items_added',
 | 
					          'items_added',
 | 
				
			||||||
          newOldLibraryItems.map((li) => li.toJSONExpanded())
 | 
					          newLibraryItems.map((li) => li.toOldJSONExpanded())
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -645,8 +643,7 @@ class LibraryScanner {
 | 
				
			|||||||
      const isSingleMediaItem = isSingleMediaFile(fileUpdateGroup, itemDir)
 | 
					      const isSingleMediaItem = isSingleMediaFile(fileUpdateGroup, itemDir)
 | 
				
			||||||
      const newLibraryItem = await LibraryItemScanner.scanPotentialNewLibraryItem(fullPath, library, folder, isSingleMediaItem)
 | 
					      const newLibraryItem = await LibraryItemScanner.scanPotentialNewLibraryItem(fullPath, library, folder, isSingleMediaItem)
 | 
				
			||||||
      if (newLibraryItem) {
 | 
					      if (newLibraryItem) {
 | 
				
			||||||
        const oldNewLibraryItem = Database.libraryItemModel.getOldLibraryItem(newLibraryItem)
 | 
					        SocketAuthority.emitter('item_added', newLibraryItem.toOldJSONExpanded())
 | 
				
			||||||
        SocketAuthority.emitter('item_added', oldNewLibraryItem.toJSONExpanded())
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      itemGroupingResults[itemDir] = newLibraryItem ? ScanResult.ADDED : ScanResult.NOTHING
 | 
					      itemGroupingResults[itemDir] = newLibraryItem ? ScanResult.ADDED : ScanResult.NOTHING
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1200,7 +1200,7 @@ async function migrationPatchNewColumns(queryInterface) {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
async function handleOldLibraryItems(ctx) {
 | 
					async function handleOldLibraryItems(ctx) {
 | 
				
			||||||
  const oldLibraryItems = await oldDbFiles.loadOldData('libraryItems')
 | 
					  const oldLibraryItems = await oldDbFiles.loadOldData('libraryItems')
 | 
				
			||||||
  const libraryItems = await ctx.models.libraryItem.getAllOldLibraryItems()
 | 
					  const libraryItems = (await ctx.models.libraryItem.findAllExpandedWhere()).map((li) => ctx.models.libraryItem.getOldLibraryItem(li))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const bulkUpdateItems = []
 | 
					  const bulkUpdateItems = []
 | 
				
			||||||
  const bulkUpdateEpisodes = []
 | 
					  const bulkUpdateEpisodes = []
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ module.exports = {
 | 
				
			|||||||
   * @param {string} libraryId
 | 
					   * @param {string} libraryId
 | 
				
			||||||
   * @param {import('../../models/User')} user
 | 
					   * @param {import('../../models/User')} user
 | 
				
			||||||
   * @param {object} options
 | 
					   * @param {object} options
 | 
				
			||||||
   * @returns {object} { libraryItems:LibraryItem[], count:number }
 | 
					   * @returns {Promise<{ libraryItems:import('../../models/LibraryItem')[], count:number }>}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async getFilteredLibraryItems(libraryId, user, options) {
 | 
					  async getFilteredLibraryItems(libraryId, user, options) {
 | 
				
			||||||
    const { filterBy, sortBy, sortDesc, limit, offset, collapseseries, include, mediaType } = options
 | 
					    const { filterBy, sortBy, sortDesc, limit, offset, collapseseries, include, mediaType } = options
 | 
				
			||||||
@ -52,7 +52,7 @@ module.exports = {
 | 
				
			|||||||
      const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, 'progress', 'in-progress', 'progress', true, false, include, limit, 0, true)
 | 
					      const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, 'progress', 'in-progress', 'progress', true, false, include, limit, 0, true)
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        items: libraryItems.map((li) => {
 | 
					        items: libraryItems.map((li) => {
 | 
				
			||||||
          const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
 | 
					          const oldLibraryItem = li.toOldJSONMinified()
 | 
				
			||||||
          if (li.rssFeed) {
 | 
					          if (li.rssFeed) {
 | 
				
			||||||
            oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
					            oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
@ -68,7 +68,7 @@ module.exports = {
 | 
				
			|||||||
      return {
 | 
					      return {
 | 
				
			||||||
        count,
 | 
					        count,
 | 
				
			||||||
        items: libraryItems.map((li) => {
 | 
					        items: libraryItems.map((li) => {
 | 
				
			||||||
          const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
 | 
					          const oldLibraryItem = li.toOldJSONMinified()
 | 
				
			||||||
          oldLibraryItem.recentEpisode = li.recentEpisode
 | 
					          oldLibraryItem.recentEpisode = li.recentEpisode
 | 
				
			||||||
          return oldLibraryItem
 | 
					          return oldLibraryItem
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
@ -89,7 +89,7 @@ module.exports = {
 | 
				
			|||||||
      const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, 'recent', null, 'addedAt', true, false, include, limit, 0)
 | 
					      const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, 'recent', null, 'addedAt', true, false, include, limit, 0)
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        libraryItems: libraryItems.map((li) => {
 | 
					        libraryItems: libraryItems.map((li) => {
 | 
				
			||||||
          const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
 | 
					          const oldLibraryItem = li.toOldJSONMinified()
 | 
				
			||||||
          if (li.rssFeed) {
 | 
					          if (li.rssFeed) {
 | 
				
			||||||
            oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
					            oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
@ -107,7 +107,7 @@ module.exports = {
 | 
				
			|||||||
      const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredLibraryItems(library.id, user, 'recent', null, 'addedAt', true, include, limit, 0)
 | 
					      const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredLibraryItems(library.id, user, 'recent', null, 'addedAt', true, include, limit, 0)
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        libraryItems: libraryItems.map((li) => {
 | 
					        libraryItems: libraryItems.map((li) => {
 | 
				
			||||||
          const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
 | 
					          const oldLibraryItem = li.toOldJSONMinified()
 | 
				
			||||||
          if (li.rssFeed) {
 | 
					          if (li.rssFeed) {
 | 
				
			||||||
            oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
					            oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
@ -136,7 +136,7 @@ module.exports = {
 | 
				
			|||||||
    const { libraryItems, count } = await libraryItemsBookFilters.getContinueSeriesLibraryItems(library, user, include, limit, 0)
 | 
					    const { libraryItems, count } = await libraryItemsBookFilters.getContinueSeriesLibraryItems(library, user, include, limit, 0)
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      libraryItems: libraryItems.map((li) => {
 | 
					      libraryItems: libraryItems.map((li) => {
 | 
				
			||||||
        const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
 | 
					        const oldLibraryItem = li.toOldJSONMinified()
 | 
				
			||||||
        if (li.rssFeed) {
 | 
					        if (li.rssFeed) {
 | 
				
			||||||
          oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
					          oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -166,7 +166,7 @@ module.exports = {
 | 
				
			|||||||
      const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, 'progress', 'finished', 'progress', true, false, include, limit, 0)
 | 
					      const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, 'progress', 'finished', 'progress', true, false, include, limit, 0)
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        items: libraryItems.map((li) => {
 | 
					        items: libraryItems.map((li) => {
 | 
				
			||||||
          const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
 | 
					          const oldLibraryItem = li.toOldJSONMinified()
 | 
				
			||||||
          if (li.rssFeed) {
 | 
					          if (li.rssFeed) {
 | 
				
			||||||
            oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
					            oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
@ -182,7 +182,7 @@ module.exports = {
 | 
				
			|||||||
      return {
 | 
					      return {
 | 
				
			||||||
        count,
 | 
					        count,
 | 
				
			||||||
        items: libraryItems.map((li) => {
 | 
					        items: libraryItems.map((li) => {
 | 
				
			||||||
          const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
 | 
					          const oldLibraryItem = li.toOldJSONMinified()
 | 
				
			||||||
          oldLibraryItem.recentEpisode = li.recentEpisode
 | 
					          oldLibraryItem.recentEpisode = li.recentEpisode
 | 
				
			||||||
          return oldLibraryItem
 | 
					          return oldLibraryItem
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
@ -293,15 +293,17 @@ module.exports = {
 | 
				
			|||||||
      })
 | 
					      })
 | 
				
			||||||
      oldSeries.books = s.bookSeries
 | 
					      oldSeries.books = s.bookSeries
 | 
				
			||||||
        .map((bs) => {
 | 
					        .map((bs) => {
 | 
				
			||||||
          const libraryItem = bs.book.libraryItem?.toJSON()
 | 
					          const libraryItem = bs.book.libraryItem
 | 
				
			||||||
          if (!libraryItem) {
 | 
					          if (!libraryItem) {
 | 
				
			||||||
            Logger.warn(`Book series book has no libraryItem`, bs, bs.book, 'series=', series)
 | 
					            Logger.warn(`Book series book has no libraryItem`, bs, bs.book, 'series=', series)
 | 
				
			||||||
            return null
 | 
					            return null
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          delete bs.book.libraryItem
 | 
					          delete bs.book.libraryItem
 | 
				
			||||||
 | 
					          bs.book.authors = [] // Not needed
 | 
				
			||||||
 | 
					          bs.book.series = [] // Not needed
 | 
				
			||||||
          libraryItem.media = bs.book
 | 
					          libraryItem.media = bs.book
 | 
				
			||||||
          const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem).toJSONMinified()
 | 
					          const oldLibraryItem = libraryItem.toOldJSONMinified()
 | 
				
			||||||
          return oldLibraryItem
 | 
					          return oldLibraryItem
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .filter((b) => b)
 | 
					        .filter((b) => b)
 | 
				
			||||||
@ -373,7 +375,7 @@ module.exports = {
 | 
				
			|||||||
    const { libraryItems, count } = await libraryItemsBookFilters.getDiscoverLibraryItems(library.id, user, include, limit)
 | 
					    const { libraryItems, count } = await libraryItemsBookFilters.getDiscoverLibraryItems(library.id, user, include, limit)
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      libraryItems: libraryItems.map((li) => {
 | 
					      libraryItems: libraryItems.map((li) => {
 | 
				
			||||||
        const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
 | 
					        const oldLibraryItem = li.toOldJSONMinified()
 | 
				
			||||||
        if (li.rssFeed) {
 | 
					        if (li.rssFeed) {
 | 
				
			||||||
          oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
					          oldLibraryItem.rssFeed = li.rssFeed.toOldJSONMinified()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -400,7 +402,7 @@ module.exports = {
 | 
				
			|||||||
    return {
 | 
					    return {
 | 
				
			||||||
      count,
 | 
					      count,
 | 
				
			||||||
      libraryItems: libraryItems.map((li) => {
 | 
					      libraryItems: libraryItems.map((li) => {
 | 
				
			||||||
        const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
 | 
					        const oldLibraryItem = li.toOldJSONMinified()
 | 
				
			||||||
        oldLibraryItem.recentEpisode = li.recentEpisode
 | 
					        oldLibraryItem.recentEpisode = li.recentEpisode
 | 
				
			||||||
        return oldLibraryItem
 | 
					        return oldLibraryItem
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
				
			|||||||
@ -349,7 +349,7 @@ module.exports = {
 | 
				
			|||||||
   * @param {number} limit
 | 
					   * @param {number} limit
 | 
				
			||||||
   * @param {number} offset
 | 
					   * @param {number} offset
 | 
				
			||||||
   * @param {boolean} isHomePage for home page shelves
 | 
					   * @param {boolean} isHomePage for home page shelves
 | 
				
			||||||
   * @returns {object} { libraryItems:LibraryItem[], count:number }
 | 
					   * @returns {{ libraryItems: import('../../models/LibraryItem')[], count: number }}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async getFilteredLibraryItems(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, collapseseries, include, limit, offset, isHomePage = false) {
 | 
					  async getFilteredLibraryItems(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, collapseseries, include, limit, offset, isHomePage = false) {
 | 
				
			||||||
    // TODO: Handle collapse sub-series
 | 
					    // TODO: Handle collapse sub-series
 | 
				
			||||||
@ -583,8 +583,8 @@ module.exports = {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const libraryItems = books.map((bookExpanded) => {
 | 
					    const libraryItems = books.map((bookExpanded) => {
 | 
				
			||||||
      const libraryItem = bookExpanded.libraryItem.toJSON()
 | 
					      const libraryItem = bookExpanded.libraryItem
 | 
				
			||||||
      const book = bookExpanded.toJSON()
 | 
					      const book = bookExpanded
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (filterGroup === 'series' && book.series?.length) {
 | 
					      if (filterGroup === 'series' && book.series?.length) {
 | 
				
			||||||
        // For showing sequence on book cover when filtering for series
 | 
					        // For showing sequence on book cover when filtering for series
 | 
				
			||||||
@ -596,27 +596,37 @@ module.exports = {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      delete book.libraryItem
 | 
					      delete book.libraryItem
 | 
				
			||||||
      delete book.authors
 | 
					
 | 
				
			||||||
      delete book.series
 | 
					      book.series =
 | 
				
			||||||
 | 
					        book.bookSeries?.map((bs) => {
 | 
				
			||||||
 | 
					          const series = bs.series
 | 
				
			||||||
 | 
					          delete bs.series
 | 
				
			||||||
 | 
					          series.bookSeries = bs
 | 
				
			||||||
 | 
					          return series
 | 
				
			||||||
 | 
					        }) || []
 | 
				
			||||||
 | 
					      delete book.bookSeries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      book.authors = book.bookAuthors?.map((ba) => ba.author) || []
 | 
				
			||||||
 | 
					      delete book.bookAuthors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // For showing details of collapsed series
 | 
					      // For showing details of collapsed series
 | 
				
			||||||
      if (collapseseries && book.bookSeries?.length) {
 | 
					      if (collapseseries && book.series?.length) {
 | 
				
			||||||
        const collapsedSeries = book.bookSeries.find((bs) => collapseSeriesBookSeries.some((cbs) => cbs.id === bs.id))
 | 
					        const collapsedSeries = book.series.find((bs) => collapseSeriesBookSeries.some((cbs) => cbs.id === bs.bookSeries.id))
 | 
				
			||||||
        if (collapsedSeries) {
 | 
					        if (collapsedSeries) {
 | 
				
			||||||
          const collapseSeriesObj = collapseSeriesBookSeries.find((csbs) => csbs.id === collapsedSeries.id)
 | 
					          const collapseSeriesObj = collapseSeriesBookSeries.find((csbs) => csbs.id === collapsedSeries.bookSeries.id)
 | 
				
			||||||
          libraryItem.collapsedSeries = {
 | 
					          libraryItem.collapsedSeries = {
 | 
				
			||||||
            id: collapsedSeries.series.id,
 | 
					            id: collapsedSeries.id,
 | 
				
			||||||
            name: collapsedSeries.series.name,
 | 
					            name: collapsedSeries.name,
 | 
				
			||||||
            nameIgnorePrefix: collapsedSeries.series.nameIgnorePrefix,
 | 
					            nameIgnorePrefix: collapsedSeries.nameIgnorePrefix,
 | 
				
			||||||
            sequence: collapsedSeries.sequence,
 | 
					            sequence: collapsedSeries.bookSeries.sequence,
 | 
				
			||||||
            numBooks: collapseSeriesObj?.numBooks || 0,
 | 
					            numBooks: collapseSeriesObj?.numBooks || 0,
 | 
				
			||||||
            libraryItemIds: collapseSeriesObj?.libraryItemIds || []
 | 
					            libraryItemIds: collapseSeriesObj?.libraryItemIds || []
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (bookExpanded.libraryItem.feeds?.length) {
 | 
					      if (libraryItem.feeds?.length) {
 | 
				
			||||||
        libraryItem.rssFeed = bookExpanded.libraryItem.feeds[0]
 | 
					        libraryItem.rssFeed = libraryItem.feeds[0]
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (includeMediaItemShare) {
 | 
					      if (includeMediaItemShare) {
 | 
				
			||||||
@ -646,7 +656,7 @@ module.exports = {
 | 
				
			|||||||
   * @param {string[]} include
 | 
					   * @param {string[]} include
 | 
				
			||||||
   * @param {number} limit
 | 
					   * @param {number} limit
 | 
				
			||||||
   * @param {number} offset
 | 
					   * @param {number} offset
 | 
				
			||||||
   * @returns {{ libraryItems:import('../../models/LibraryItem')[], count:number }}
 | 
					   * @returns {Promise<{ libraryItems:import('../../models/LibraryItem')[], count:number }>}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async getContinueSeriesLibraryItems(library, user, include, limit, offset) {
 | 
					  async getContinueSeriesLibraryItems(library, user, include, limit, offset) {
 | 
				
			||||||
    const libraryId = library.id
 | 
					    const libraryId = library.id
 | 
				
			||||||
@ -758,16 +768,19 @@ module.exports = {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const libraryItem = s.bookSeries[bookIndex].book.libraryItem.toJSON()
 | 
					        const libraryItem = s.bookSeries[bookIndex].book.libraryItem
 | 
				
			||||||
        const book = s.bookSeries[bookIndex].book.toJSON()
 | 
					        const book = s.bookSeries[bookIndex].book
 | 
				
			||||||
        delete book.libraryItem
 | 
					        delete book.libraryItem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        book.series = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        libraryItem.series = {
 | 
					        libraryItem.series = {
 | 
				
			||||||
          id: s.id,
 | 
					          id: s.id,
 | 
				
			||||||
          name: s.name,
 | 
					          name: s.name,
 | 
				
			||||||
          sequence: s.bookSeries[bookIndex].sequence
 | 
					          sequence: s.bookSeries[bookIndex].sequence
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (s.bookSeries[bookIndex].book.libraryItem.feeds?.length) {
 | 
					        if (libraryItem.feeds?.length) {
 | 
				
			||||||
          libraryItem.rssFeed = s.bookSeries[bookIndex].book.libraryItem.feeds[0]
 | 
					          libraryItem.rssFeed = libraryItem.feeds[0]
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        libraryItem.media = book
 | 
					        libraryItem.media = book
 | 
				
			||||||
        return libraryItem
 | 
					        return libraryItem
 | 
				
			||||||
@ -788,7 +801,7 @@ module.exports = {
 | 
				
			|||||||
   * @param {import('../../models/User')} user
 | 
					   * @param {import('../../models/User')} user
 | 
				
			||||||
   * @param {string[]} include
 | 
					   * @param {string[]} include
 | 
				
			||||||
   * @param {number} limit
 | 
					   * @param {number} limit
 | 
				
			||||||
   * @returns {object} {libraryItems:LibraryItem, count:number}
 | 
					   * @returns {Promise<{ libraryItems: import('../../models/LibraryItem')[], count: number }>}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async getDiscoverLibraryItems(libraryId, user, include, limit) {
 | 
					  async getDiscoverLibraryItems(libraryId, user, include, limit) {
 | 
				
			||||||
    const userPermissionBookWhere = this.getUserPermissionBookWhereQuery(user)
 | 
					    const userPermissionBookWhere = this.getUserPermissionBookWhereQuery(user)
 | 
				
			||||||
@ -895,13 +908,26 @@ module.exports = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Step 3: Map books to library items
 | 
					    // Step 3: Map books to library items
 | 
				
			||||||
    const libraryItems = books.map((bookExpanded) => {
 | 
					    const libraryItems = books.map((bookExpanded) => {
 | 
				
			||||||
      const libraryItem = bookExpanded.libraryItem.toJSON()
 | 
					      const libraryItem = bookExpanded.libraryItem
 | 
				
			||||||
      const book = bookExpanded.toJSON()
 | 
					      const book = bookExpanded
 | 
				
			||||||
      delete book.libraryItem
 | 
					      delete book.libraryItem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      book.series =
 | 
				
			||||||
 | 
					        book.bookSeries?.map((bs) => {
 | 
				
			||||||
 | 
					          const series = bs.series
 | 
				
			||||||
 | 
					          delete bs.series
 | 
				
			||||||
 | 
					          series.bookSeries = bs
 | 
				
			||||||
 | 
					          return series
 | 
				
			||||||
 | 
					        }) || []
 | 
				
			||||||
 | 
					      delete book.bookSeries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      book.authors = book.bookAuthors?.map((ba) => ba.author) || []
 | 
				
			||||||
 | 
					      delete book.bookAuthors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      libraryItem.media = book
 | 
					      libraryItem.media = book
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (bookExpanded.libraryItem.feeds?.length) {
 | 
					      if (libraryItem.feeds?.length) {
 | 
				
			||||||
        libraryItem.rssFeed = bookExpanded.libraryItem.feeds[0]
 | 
					        libraryItem.rssFeed = libraryItem.feeds[0]
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return libraryItem
 | 
					      return libraryItem
 | 
				
			||||||
@ -961,11 +987,11 @@ module.exports = {
 | 
				
			|||||||
   * Get library items for series
 | 
					   * Get library items for series
 | 
				
			||||||
   * @param {import('../../models/Series')} series
 | 
					   * @param {import('../../models/Series')} series
 | 
				
			||||||
   * @param {import('../../models/User')} [user]
 | 
					   * @param {import('../../models/User')} [user]
 | 
				
			||||||
   * @returns {Promise<import('../../objects/LibraryItem')[]>}
 | 
					   * @returns {Promise<import('../../models/LibraryItem')[]>}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async getLibraryItemsForSeries(series, user) {
 | 
					  async getLibraryItemsForSeries(series, user) {
 | 
				
			||||||
    const { libraryItems } = await this.getFilteredLibraryItems(series.libraryId, user, 'series', series.id, null, null, false, [], null, null)
 | 
					    const { libraryItems } = await this.getFilteredLibraryItems(series.libraryId, user, 'series', series.id, null, null, false, [], null, null)
 | 
				
			||||||
    return libraryItems.map((li) => Database.libraryItemModel.getOldLibraryItem(li))
 | 
					    return libraryItems
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@ -1040,9 +1066,21 @@ module.exports = {
 | 
				
			|||||||
    for (const book of books) {
 | 
					    for (const book of books) {
 | 
				
			||||||
      const libraryItem = book.libraryItem
 | 
					      const libraryItem = book.libraryItem
 | 
				
			||||||
      delete book.libraryItem
 | 
					      delete book.libraryItem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      book.series = book.bookSeries.map((bs) => {
 | 
				
			||||||
 | 
					        const series = bs.series
 | 
				
			||||||
 | 
					        delete bs.series
 | 
				
			||||||
 | 
					        series.bookSeries = bs
 | 
				
			||||||
 | 
					        return series
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      delete book.bookSeries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      book.authors = book.bookAuthors.map((ba) => ba.author)
 | 
				
			||||||
 | 
					      delete book.bookAuthors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      libraryItem.media = book
 | 
					      libraryItem.media = book
 | 
				
			||||||
      itemMatches.push({
 | 
					      itemMatches.push({
 | 
				
			||||||
        libraryItem: Database.libraryItemModel.getOldLibraryItem(libraryItem).toJSONExpanded()
 | 
					        libraryItem: libraryItem.toOldJSONExpanded()
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1132,7 +1170,9 @@ module.exports = {
 | 
				
			|||||||
      const books = series.bookSeries.map((bs) => {
 | 
					      const books = series.bookSeries.map((bs) => {
 | 
				
			||||||
        const libraryItem = bs.book.libraryItem
 | 
					        const libraryItem = bs.book.libraryItem
 | 
				
			||||||
        libraryItem.media = bs.book
 | 
					        libraryItem.media = bs.book
 | 
				
			||||||
        return Database.libraryItemModel.getOldLibraryItem(libraryItem).toJSON()
 | 
					        libraryItem.media.authors = []
 | 
				
			||||||
 | 
					        libraryItem.media.series = []
 | 
				
			||||||
 | 
					        return libraryItem.toOldJSON()
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      seriesMatches.push({
 | 
					      seriesMatches.push({
 | 
				
			||||||
        series: series.toOldJSON(),
 | 
					        series: series.toOldJSON(),
 | 
				
			||||||
 | 
				
			|||||||
@ -107,7 +107,7 @@ module.exports = {
 | 
				
			|||||||
   * @param {string[]} include
 | 
					   * @param {string[]} include
 | 
				
			||||||
   * @param {number} limit
 | 
					   * @param {number} limit
 | 
				
			||||||
   * @param {number} offset
 | 
					   * @param {number} offset
 | 
				
			||||||
   * @returns {object} { libraryItems:LibraryItem[], count:number }
 | 
					   * @returns {Promise<{ libraryItems: import('../../models/LibraryItem')[], count: number }>}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async getFilteredLibraryItems(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, include, limit, offset) {
 | 
					  async getFilteredLibraryItems(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, include, limit, offset) {
 | 
				
			||||||
    const includeRSSFeed = include.includes('rssfeed')
 | 
					    const includeRSSFeed = include.includes('rssfeed')
 | 
				
			||||||
@ -175,16 +175,19 @@ module.exports = {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const libraryItems = podcasts.map((podcastExpanded) => {
 | 
					    const libraryItems = podcasts.map((podcastExpanded) => {
 | 
				
			||||||
      const libraryItem = podcastExpanded.libraryItem.toJSON()
 | 
					      const libraryItem = podcastExpanded.libraryItem
 | 
				
			||||||
      const podcast = podcastExpanded.toJSON()
 | 
					      const podcast = podcastExpanded
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      delete podcast.libraryItem
 | 
					      delete podcast.libraryItem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (podcastExpanded.libraryItem.feeds?.length) {
 | 
					      if (libraryItem.feeds?.length) {
 | 
				
			||||||
        libraryItem.rssFeed = podcastExpanded.libraryItem.feeds[0]
 | 
					        libraryItem.rssFeed = libraryItem.feeds[0]
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (podcast.numEpisodesIncomplete) {
 | 
					      if (podcast.dataValues.numEpisodesIncomplete) {
 | 
				
			||||||
        libraryItem.numEpisodesIncomplete = podcast.numEpisodesIncomplete
 | 
					        libraryItem.numEpisodesIncomplete = podcast.dataValues.numEpisodesIncomplete
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (podcast.dataValues.numEpisodes) {
 | 
				
			||||||
 | 
					        podcast.numEpisodes = podcast.dataValues.numEpisodes
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      libraryItem.media = podcast
 | 
					      libraryItem.media = podcast
 | 
				
			||||||
@ -209,7 +212,7 @@ module.exports = {
 | 
				
			|||||||
   * @param {number} limit
 | 
					   * @param {number} limit
 | 
				
			||||||
   * @param {number} offset
 | 
					   * @param {number} offset
 | 
				
			||||||
   * @param {boolean} isHomePage for home page shelves
 | 
					   * @param {boolean} isHomePage for home page shelves
 | 
				
			||||||
   * @returns {object} {libraryItems:LibraryItem[], count:number}
 | 
					   * @returns {Promise<{ libraryItems: import('../../models/LibraryItem')[], count: number }>}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async getFilteredPodcastEpisodes(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, limit, offset, isHomePage = false) {
 | 
					  async getFilteredPodcastEpisodes(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, limit, offset, isHomePage = false) {
 | 
				
			||||||
    if (sortBy === 'progress' && filterGroup !== 'progress') {
 | 
					    if (sortBy === 'progress' && filterGroup !== 'progress') {
 | 
				
			||||||
@ -289,10 +292,11 @@ module.exports = {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const libraryItems = podcastEpisodes.map((ep) => {
 | 
					    const libraryItems = podcastEpisodes.map((ep) => {
 | 
				
			||||||
      const libraryItem = ep.podcast.libraryItem.toJSON()
 | 
					      const libraryItem = ep.podcast.libraryItem
 | 
				
			||||||
      const podcast = ep.podcast.toJSON()
 | 
					      const podcast = ep.podcast
 | 
				
			||||||
      delete podcast.libraryItem
 | 
					      delete podcast.libraryItem
 | 
				
			||||||
      libraryItem.media = podcast
 | 
					      libraryItem.media = podcast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      libraryItem.recentEpisode = ep.getOldPodcastEpisode(libraryItem.id).toJSON()
 | 
					      libraryItem.recentEpisode = ep.getOldPodcastEpisode(libraryItem.id).toJSON()
 | 
				
			||||||
      return libraryItem
 | 
					      return libraryItem
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
@ -362,8 +366,9 @@ module.exports = {
 | 
				
			|||||||
      const libraryItem = podcast.libraryItem
 | 
					      const libraryItem = podcast.libraryItem
 | 
				
			||||||
      delete podcast.libraryItem
 | 
					      delete podcast.libraryItem
 | 
				
			||||||
      libraryItem.media = podcast
 | 
					      libraryItem.media = podcast
 | 
				
			||||||
 | 
					      libraryItem.media.podcastEpisodes = []
 | 
				
			||||||
      itemMatches.push({
 | 
					      itemMatches.push({
 | 
				
			||||||
        libraryItem: Database.libraryItemModel.getOldLibraryItem(libraryItem).toJSONExpanded()
 | 
					        libraryItem: libraryItem.toOldJSONExpanded()
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -162,6 +162,12 @@ module.exports = {
 | 
				
			|||||||
            include: [
 | 
					            include: [
 | 
				
			||||||
              {
 | 
					              {
 | 
				
			||||||
                model: Database.libraryItemModel
 | 
					                model: Database.libraryItemModel
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                model: Database.authorModel
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                model: Database.seriesModel
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
@ -195,10 +201,10 @@ module.exports = {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      oldSeries.books = s.bookSeries.map((bs) => {
 | 
					      oldSeries.books = s.bookSeries.map((bs) => {
 | 
				
			||||||
        const libraryItem = bs.book.libraryItem.toJSON()
 | 
					        const libraryItem = bs.book.libraryItem
 | 
				
			||||||
        delete bs.book.libraryItem
 | 
					        delete bs.book.libraryItem
 | 
				
			||||||
        libraryItem.media = bs.book
 | 
					        libraryItem.media = bs.book
 | 
				
			||||||
        const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem).toJSONMinified()
 | 
					        const oldLibraryItem = libraryItem.toOldJSONMinified()
 | 
				
			||||||
        return oldLibraryItem
 | 
					        return oldLibraryItem
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      allOldSeries.push(oldSeries)
 | 
					      allOldSeries.push(oldSeries)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user