mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Update updateMedia endpoint to use new model
This commit is contained in:
		
							parent
							
								
									5cd14108f9
								
							
						
					
					
						commit
						12c6f2e9a5
					
				| @ -234,32 +234,27 @@ class LibraryItemController { | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(req.libraryItem) | ||||
| 
 | ||||
|     // Book specific - Get all series being removed from this item
 | ||||
|     let seriesRemoved = [] | ||||
|     if (req.libraryItem.isBook && mediaPayload.metadata?.series) { | ||||
|       const seriesIdsInUpdate = mediaPayload.metadata.series?.map((se) => se.id) || [] | ||||
|       seriesRemoved = oldLibraryItem.media.metadata.series.filter((se) => !seriesIdsInUpdate.includes(se.id)) | ||||
|       seriesRemoved = req.libraryItem.media.series.filter((se) => !seriesIdsInUpdate.includes(se.id)) | ||||
|     } | ||||
| 
 | ||||
|     let authorsRemoved = [] | ||||
|     if (req.libraryItem.isBook && mediaPayload.metadata?.authors) { | ||||
|       const authorIdsInUpdate = mediaPayload.metadata.authors.map((au) => au.id) | ||||
|       authorsRemoved = oldLibraryItem.media.metadata.authors.filter((au) => !authorIdsInUpdate.includes(au.id)) | ||||
|       authorsRemoved = req.libraryItem.media.authors.filter((au) => !authorIdsInUpdate.includes(au.id)) | ||||
|     } | ||||
| 
 | ||||
|     const hasUpdates = oldLibraryItem.media.update(mediaPayload) || mediaPayload.url | ||||
|     const hasUpdates = (await req.libraryItem.media.updateFromRequest(mediaPayload)) || mediaPayload.url | ||||
|     if (hasUpdates) { | ||||
|       oldLibraryItem.updatedAt = Date.now() | ||||
| 
 | ||||
|       if (isPodcastAutoDownloadUpdated) { | ||||
|         this.cronManager.checkUpdatePodcastCron(oldLibraryItem) | ||||
|         this.cronManager.checkUpdatePodcastCron(req.libraryItem) | ||||
|       } | ||||
| 
 | ||||
|       Logger.debug(`[LibraryItemController] Updated library item media ${oldLibraryItem.media.metadata.title}`) | ||||
|       await Database.updateLibraryItem(oldLibraryItem) | ||||
|       SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded()) | ||||
|       Logger.debug(`[LibraryItemController] Updated library item media ${req.libraryItem.media.title}`) | ||||
|       SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded()) | ||||
| 
 | ||||
|       if (authorsRemoved.length) { | ||||
|         // Check remove empty authors
 | ||||
| @ -274,7 +269,7 @@ class LibraryItemController { | ||||
|     } | ||||
|     res.json({ | ||||
|       updated: hasUpdates, | ||||
|       libraryItem: oldLibraryItem | ||||
|       libraryItem: req.libraryItem.toOldJSON() | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -215,6 +215,10 @@ class CronManager { | ||||
|     this.podcastCrons = this.podcastCrons.filter((pc) => pc.expression !== podcastCron.expression) | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * | ||||
|    * @param {import('../models/LibraryItem')} libraryItem - this can be the old model | ||||
|    */ | ||||
|   checkUpdatePodcastCron(libraryItem) { | ||||
|     // Remove from old cron by library item id
 | ||||
|     const existingCron = this.podcastCrons.find((pc) => pc.libraryItemIds.includes(libraryItem.id)) | ||||
| @ -230,7 +234,10 @@ class CronManager { | ||||
|       const cronMatchingExpression = this.podcastCrons.find((pc) => pc.expression === libraryItem.media.autoDownloadSchedule) | ||||
|       if (cronMatchingExpression) { | ||||
|         cronMatchingExpression.libraryItemIds.push(libraryItem.id) | ||||
|         Logger.info(`[CronManager] Added podcast "${libraryItem.media.metadata.title}" to auto dl episode cron "${cronMatchingExpression.expression}"`) | ||||
| 
 | ||||
|         // TODO: Update after old model removed
 | ||||
|         const podcastTitle = libraryItem.media.title || libraryItem.media.metadata?.title | ||||
|         Logger.info(`[CronManager] Added podcast "${podcastTitle}" to auto dl episode cron "${cronMatchingExpression.expression}"`) | ||||
|       } else { | ||||
|         this.startPodcastCron(libraryItem.media.autoDownloadSchedule, [libraryItem.id]) | ||||
|       } | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| const { DataTypes, Model } = require('sequelize') | ||||
| const Logger = require('../Logger') | ||||
| const { getTitlePrefixAtEnd } = require('../utils') | ||||
| const { getTitlePrefixAtEnd, getTitleIgnorePrefix } = require('../utils') | ||||
| const parseNameString = require('../utils/parsers/parseNameString') | ||||
| 
 | ||||
| /** | ||||
| @ -425,6 +425,116 @@ class Book extends Model { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * | ||||
|    * @param {Object} payload - old book object | ||||
|    * @returns {Promise<boolean>} | ||||
|    */ | ||||
|   async updateFromRequest(payload) { | ||||
|     if (!payload) return false | ||||
| 
 | ||||
|     let hasUpdates = false | ||||
| 
 | ||||
|     if (payload.metadata) { | ||||
|       const metadataStringKeys = ['title', 'subtitle', 'publishedYear', 'publishedDate', 'publisher', 'description', 'isbn', 'asin', 'language'] | ||||
|       metadataStringKeys.forEach((key) => { | ||||
|         if (typeof payload.metadata[key] === 'string' && this[key] !== payload.metadata[key]) { | ||||
|           this[key] = payload.metadata[key] || null | ||||
| 
 | ||||
|           if (key === 'title') { | ||||
|             this.titleIgnorePrefix = getTitleIgnorePrefix(this.title) | ||||
|           } | ||||
| 
 | ||||
|           hasUpdates = true | ||||
|         } | ||||
|       }) | ||||
|       if (payload.metadata.explicit !== undefined && this.explicit !== !!payload.metadata.explicit) { | ||||
|         this.explicit = !!payload.metadata.explicit | ||||
|         hasUpdates = true | ||||
|       } | ||||
|       if (payload.metadata.abridged !== undefined && this.abridged !== !!payload.metadata.abridged) { | ||||
|         this.abridged = !!payload.metadata.abridged | ||||
|         hasUpdates = true | ||||
|       } | ||||
|       const arrayOfStringsKeys = ['narrators', 'genres'] | ||||
|       arrayOfStringsKeys.forEach((key) => { | ||||
|         if (Array.isArray(payload.metadata[key]) && !payload.metadata[key].some((item) => typeof item !== 'string') && JSON.stringify(this[key]) !== JSON.stringify(payload.metadata[key])) { | ||||
|           this[key] = payload.metadata[key] | ||||
|           this.changed(key, true) | ||||
|           hasUpdates = true | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
| 
 | ||||
|     if (Array.isArray(payload.tags) && !payload.tags.some((tag) => typeof tag !== 'string') && JSON.stringify(this.tags) !== JSON.stringify(payload.tags)) { | ||||
|       this.tags = payload.tags | ||||
|       this.changed('tags', true) | ||||
|       hasUpdates = true | ||||
|     } | ||||
| 
 | ||||
|     // TODO: Remove support for updating audioFiles, chapters and ebookFile here
 | ||||
|     const arrayOfObjectsKeys = ['audioFiles', 'chapters'] | ||||
|     arrayOfObjectsKeys.forEach((key) => { | ||||
|       if (Array.isArray(payload[key]) && !payload[key].some((item) => typeof item !== 'object') && JSON.stringify(this[key]) !== JSON.stringify(payload[key])) { | ||||
|         this[key] = payload[key] | ||||
|         this.changed(key, true) | ||||
|         hasUpdates = true | ||||
|       } | ||||
|     }) | ||||
|     if (payload.ebookFile && JSON.stringify(this.ebookFile) !== JSON.stringify(payload.ebookFile)) { | ||||
|       this.ebookFile = payload.ebookFile | ||||
|       this.changed('ebookFile', true) | ||||
|       hasUpdates = true | ||||
|     } | ||||
| 
 | ||||
|     if (hasUpdates) { | ||||
|       Logger.debug(`[Book] "${this.title}" changed keys:`, this.changed()) | ||||
|       await this.save() | ||||
|     } | ||||
| 
 | ||||
|     if (Array.isArray(payload.metadata?.authors)) { | ||||
|       const authorsRemoved = this.authors.filter((au) => !payload.metadata.authors.some((a) => a.id === au.id)) | ||||
|       const newAuthors = payload.metadata.authors.filter((a) => !this.authors.some((au) => au.id === a.id)) | ||||
| 
 | ||||
|       for (const author of authorsRemoved) { | ||||
|         await this.sequelize.models.bookAuthor.removeByIds(author.id, this.id) | ||||
|         Logger.debug(`[Book] "${this.title}" Removed author ${author.id}`) | ||||
|         hasUpdates = true | ||||
|       } | ||||
|       for (const author of newAuthors) { | ||||
|         await this.sequelize.models.bookAuthor.create({ bookId: this.id, authorId: author.id }) | ||||
|         Logger.debug(`[Book] "${this.title}" Added author ${author.id}`) | ||||
|         hasUpdates = true | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (Array.isArray(payload.metadata?.series)) { | ||||
|       const seriesRemoved = this.series.filter((se) => !payload.metadata.series.some((s) => s.id === se.id)) | ||||
|       const newSeries = payload.metadata.series.filter((s) => !this.series.some((se) => se.id === s.id)) | ||||
| 
 | ||||
|       for (const series of seriesRemoved) { | ||||
|         await this.sequelize.models.bookSeries.removeByIds(series.id, this.id) | ||||
|         Logger.debug(`[Book] "${this.title}" Removed series ${series.id}`) | ||||
|         hasUpdates = true | ||||
|       } | ||||
|       for (const series of newSeries) { | ||||
|         await this.sequelize.models.bookSeries.create({ bookId: this.id, seriesId: series.id, sequence: series.sequence }) | ||||
|         Logger.debug(`[Book] "${this.title}" Added series ${series.id}`) | ||||
|         hasUpdates = true | ||||
|       } | ||||
|       for (const series of payload.metadata.series) { | ||||
|         const existingSeries = this.series.find((se) => se.id === series.id) | ||||
|         if (existingSeries && existingSeries.bookSeries.sequence !== series.sequence) { | ||||
|           await existingSeries.bookSeries.update({ sequence: series.sequence }) | ||||
|           Logger.debug(`[Book] "${this.title}" Updated series ${series.id} sequence ${series.sequence}`) | ||||
|           hasUpdates = true | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     return hasUpdates | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Old model kept metadata in a separate object | ||||
|    */ | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| const { DataTypes, Model } = require('sequelize') | ||||
| const { getTitlePrefixAtEnd } = require('../utils') | ||||
| const { getTitlePrefixAtEnd, getTitleIgnorePrefix } = require('../utils') | ||||
| const Logger = require('../Logger') | ||||
| 
 | ||||
| /** | ||||
|  * @typedef PodcastExpandedProperties | ||||
| @ -199,6 +200,82 @@ class Podcast extends Model { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * | ||||
|    * @param {Object} payload - Old podcast object | ||||
|    * @returns {Promise<boolean>} | ||||
|    */ | ||||
|   async updateFromRequest(payload) { | ||||
|     if (!payload) return false | ||||
| 
 | ||||
|     let hasUpdates = false | ||||
| 
 | ||||
|     if (payload.metadata) { | ||||
|       const stringKeys = ['title', 'author', 'releaseDate', 'feedUrl', 'imageUrl', 'description', 'itunesPageUrl', 'itunesId', 'itunesArtistId', 'language', 'type'] | ||||
|       stringKeys.forEach((key) => { | ||||
|         let newKey = key | ||||
|         if (key === 'type') { | ||||
|           newKey = 'podcastType' | ||||
|         } else if (key === 'feedUrl') { | ||||
|           newKey = 'feedURL' | ||||
|         } else if (key === 'imageUrl') { | ||||
|           newKey = 'imageURL' | ||||
|         } else if (key === 'itunesPageUrl') { | ||||
|           newKey = 'itunesPageURL' | ||||
|         } | ||||
|         if (typeof payload.metadata[key] === 'string' && payload.metadata[key] !== this[newKey]) { | ||||
|           this[newKey] = payload.metadata[key] | ||||
|           if (key === 'title') { | ||||
|             this.titleIgnorePrefix = getTitleIgnorePrefix(this.title) | ||||
|           } | ||||
| 
 | ||||
|           hasUpdates = true | ||||
|         } | ||||
|       }) | ||||
| 
 | ||||
|       if (payload.metadata.explicit !== undefined && payload.metadata.explicit !== this.explicit) { | ||||
|         this.explicit = !!payload.metadata.explicit | ||||
|         hasUpdates = true | ||||
|       } | ||||
| 
 | ||||
|       if (Array.isArray(payload.metadata.genres) && !payload.metadata.genres.some((item) => typeof item !== 'string') && JSON.stringify(this.genres) !== JSON.stringify(payload.metadata.genres)) { | ||||
|         this.genres = payload.metadata.genres | ||||
|         this.changed('genres', true) | ||||
|         hasUpdates = true | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (Array.isArray(payload.tags) && !payload.tags.some((item) => typeof item !== 'string') && JSON.stringify(this.tags) !== JSON.stringify(payload.tags)) { | ||||
|       this.tags = payload.tags | ||||
|       this.changed('tags', true) | ||||
|       hasUpdates = true | ||||
|     } | ||||
| 
 | ||||
|     if (payload.autoDownloadEpisodes !== undefined && payload.autoDownloadEpisodes !== this.autoDownloadEpisodes) { | ||||
|       this.autoDownloadEpisodes = !!payload.autoDownloadEpisodes | ||||
|       hasUpdates = true | ||||
|     } | ||||
|     if (typeof payload.autoDownloadSchedule === 'string' && payload.autoDownloadSchedule !== this.autoDownloadSchedule) { | ||||
|       this.autoDownloadSchedule = payload.autoDownloadSchedule | ||||
|       hasUpdates = true | ||||
|     } | ||||
| 
 | ||||
|     const numberKeys = ['maxEpisodesToKeep', 'maxNewEpisodesToDownload'] | ||||
|     numberKeys.forEach((key) => { | ||||
|       if (typeof payload[key] === 'number' && payload[key] !== this[key]) { | ||||
|         this[key] = payload[key] | ||||
|         hasUpdates = true | ||||
|       } | ||||
|     }) | ||||
| 
 | ||||
|     if (hasUpdates) { | ||||
|       Logger.debug(`[Podcast] changed keys:`, this.changed()) | ||||
|       await this.save() | ||||
|     } | ||||
| 
 | ||||
|     return hasUpdates | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Old model kept metadata in a separate object | ||||
|    */ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user